--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/remotestoragefw/webdavaccessplugin/src/rsfwpropfindparser.cpp Wed Sep 01 12:15:08 2010 +0100
@@ -0,0 +1,590 @@
+/*
+* Copyright (c) 2002-2004 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: Parse WebDAV PROPFIND method response body
+ *
+*/
+
+
+// INCLUDE FILES
+#include <f32file.h>
+#include <escapeutils.h>
+#include <tinternetdate.h>
+
+#include "rsfwpropfindparser.h"
+//#include "rsfwdirent.h"
+#include "rsfwdirentattr.h"
+#include "mdebug.h"
+#include "uri8.h"
+
+// ============================ MEMBER FUNCTIONS ==============================
+CRsfwPropFindParser* CRsfwPropFindParser::NewLC()
+ {
+ CRsfwPropFindParser* self = new (ELeave) CRsfwPropFindParser;
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ return self;
+ }
+
+CRsfwPropFindParser* CRsfwPropFindParser::NewL()
+ {
+ CRsfwPropFindParser* self = NewLC();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+void CRsfwPropFindParser::ConstructL()
+ {
+ ClearDirEntryL();
+ iCurrentIsParent = EFalse;
+ }
+
+CRsfwPropFindParser::~CRsfwPropFindParser()
+ {
+ delete iDirEntry;
+ delete iContentString;
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwPropFindParser::OnStartDocumentL
+// This method is a callback to indicate the start of the document.
+// @param aDocParam Specifies the various parameters of the document.
+// @arg aDocParam.iCharacterSetName The character encoding of the document.
+// ----------------------------------------------------------------------------
+//
+void CRsfwPropFindParser::OnStartDocumentL(
+ const Xml::RDocumentParameters& /* aDocParam */,
+ TInt aErrCode)
+ {
+ iError = KErrNone; // discard the old error
+ if (!aErrCode)
+ {
+ iParseState = ELooking;
+ }
+ else
+ {
+ User::Leave(aErrCode);
+ }
+
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwPropFindParser::OnStartDocumentL
+// This method is a callback to indicate the end of the document.
+// ----------------------------------------------------------------------------
+//
+void CRsfwPropFindParser::OnEndDocumentL(TInt aErrCode)
+ {
+ if (aErrCode)
+ {
+ User::Leave(aErrCode);
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwPropFindParser::OnStartElementL
+// This method is a callback to indicate an element has been parsed.
+// @param aElement is a handle to the element's details.
+// @param aAttributes contains the attributes for the element.
+// @param aErrorCode is the error code.
+// If this is not KErrNone then special action may be required.
+// ----------------------------------------------------------------------------
+//
+void CRsfwPropFindParser::OnStartElementL(
+ const Xml::RTagInfo& aElement,
+ const Xml::RAttributeArray& /* aAttributes */,
+ TInt aErrorCode)
+ {
+ _LIT8(KResponseHeader, "response");
+ _LIT8(KContentType, "getcontenttype");
+ _LIT8(KDate, "creationdate");
+ _LIT8(KModified, "getlastmodified");
+ _LIT8(KLength, "getcontentlength");
+ _LIT8(KResourceType, "resourcetype");
+ _LIT8(KEtag, "getetag");
+
+ if (aErrorCode)
+ {
+ User::Leave(aErrorCode);
+ }
+
+ switch (iParseState)
+ {
+ case EName:
+ break;
+
+ case EResponse:
+ {
+ _LIT8(KHRef, "href");
+ if (((aElement.LocalName()).DesC()).Compare(KHRef) == 0)
+ {
+ // href that follows response tag is the name of the file
+ iParseState = EName;
+ }
+ }
+ break;
+
+ case EModified:
+ break;
+
+ case ELength:
+ break;
+
+ case EDate:
+ break;
+
+ case EResourceType:
+ {
+ _LIT8(KCollection, "collection");
+ if (((aElement.LocalName()).DesC()).Compare(KCollection) == 0)
+ {
+ iDirEntry->Attr()->SetAtt(KEntryAttDir);
+ }
+ }
+ break;
+
+ case EContentType:
+ break;
+
+ case EETag:
+ break;
+
+ case ELooking: // we are trying to find the next interesting tag
+ if (((aElement.LocalName()).DesC()).Compare(KModified) == 0)
+ {
+ iParseState = EModified;
+ }
+ else if (((aElement.LocalName()).DesC()).Compare(KLength) == 0)
+ {
+ iParseState = ELength;
+ }
+ else if (((aElement.LocalName()).DesC()).Compare(KDate) == 0)
+ {
+ iParseState = EDate;
+ }
+ else if (((aElement.LocalName()).DesC()).Compare(KResourceType) == 0)
+ {
+ iParseState = EResourceType;
+ }
+ else if (((aElement.LocalName()).DesC()).Compare(KContentType) == 0)
+ {
+ iParseState = EContentType;
+ }
+ else if (((aElement.LocalName()).DesC()).Compare(KResponseHeader) == 0)
+ {
+ iParseState = EResponse;
+ }
+ else if (((aElement.LocalName()).DesC()).Compare(KEtag) == 0)
+ {
+ iParseState = EETag;
+ }
+ else
+ {
+ // lint
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwPropFindParser::OnEndElementL
+// This method is a callback to indicate that end of element has been reached.
+// @param aElement is a handle to the element's details.
+// @param aErrorCode is the error code.
+// If this is not KErrNone then special action may be required.
+// ----------------------------------------------------------------------------
+//
+void CRsfwPropFindParser::OnEndElementL(const Xml::RTagInfo& aElement,
+ TInt aErrorCode)
+ {
+ if (aErrorCode)
+ {
+ User::Leave(aErrorCode);
+ }
+
+ // If we reached </response> we can fill next entry in iDirEntArray
+ _LIT8(KResponse, "*response");
+ if (((aElement.LocalName()).DesC()).Match(KResponse) != KErrNotFound)
+ {
+ // Save the entry if depth = 0 or depth = 1 and
+ // this is not the parent directory
+ switch (iDepth)
+ {
+ case 0:
+ iDirEntArray->Append(iDirEntry);
+ // ownership transferred
+ iDirEntry = NULL;
+ break;
+
+ case 1:
+ if (!iCurrentIsParent)
+ {
+ iDirEntArray->Append(iDirEntry);
+ // ownership transferred
+ iDirEntry = NULL;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (iCurrentIsParent)
+ {
+ // We have 'seen' the end tag of parent directory
+ iCurrentIsParent = EFalse;
+ }
+
+ // In any case going through an entry is complete,
+ // reset iDirEntry
+ ClearDirEntryL();
+ delete iContentString;
+ iContentString = NULL;
+ iParseState = ELooking;
+ }
+
+ // otherwise we will continue reading
+ // if we have some interesting content
+ if ((iParseState != ELooking) && !iContentString)
+ {
+ iParseState = ELooking;
+ return;
+ }
+
+ switch (iParseState)
+ {
+ case EName:
+ {
+ // Figure out whether the entry we are currently reading
+ // is the directory itself.
+ // The directory itself is the first one in the reply that
+ // comes from server,
+ // and the last one that our XML-parser passes to us
+
+ // if the name is fully qualified URI, only take the path
+ TPtrC8 uriPtr = iContentString->Des();
+ TPtrC8 pathPtr = uriPtr;
+ TUriParser8 uriParser;
+ if (uriParser.Parse(uriPtr) == KErrNone)
+ {
+ pathPtr.Set(uriParser.Extract(EUriPath));
+ }
+
+
+ HBufC* name = DecodeL(pathPtr);
+ CleanupStack::PushL(name);
+
+ if (name->Compare(*iPropFindPath) == 0)
+ {
+ iCurrentIsParent = ETrue;
+ }
+ else
+ {
+ TPtrC namePtr = name->Des();
+ if ((namePtr.Length() > 1) &&
+ (namePtr[namePtr.Length() - 1] == '/'))
+ {
+ // strip off trailing '/'
+ namePtr.Set(namePtr.Left(namePtr.Length() - 1));
+ }
+
+ TInt pos = namePtr.LocateReverse('/');
+ // Shouldn't be negative as
+ // the path should always start with '/'
+ if ((pos >= 0) && (namePtr.Length() > 1))
+ {
+ namePtr.Set((namePtr.Right(namePtr.Length() - (pos + 1))));
+ }
+ iDirEntry->SetNameL(namePtr);
+ }
+ CleanupStack::PopAndDestroy(name);
+ }
+ break;
+
+ case EModified:
+ {
+ // Webdav sends dates in RFC 822 format
+ // (e.g., "Thu, 19 Dec 2002 13:51:16 GMT").
+ // We parse them as 8 bit data.
+ TInternetDate inetDate;
+ inetDate.SetDateL(*iContentString);
+ iDirEntry->Attr()->SetModified(inetDate.DateTime());
+ }
+ break;
+
+ case ELength:
+ {
+ // Convert to int
+ TLex8 lex(*iContentString);
+ TInt len;
+ User::LeaveIfError(lex.Val(len));
+ iDirEntry->Attr()->SetSize(len);
+ }
+ break;
+
+ case EETag:
+ // etag is stored for files
+ if (!(iDirEntry->Attr()->Att() & KEntryAttDir))
+ {
+ iDirEntry->Attr()->SetETagL(*iContentString);
+ }
+
+ break;
+
+ case EContentType:
+ {
+ iDirEntry->Attr()->SetMimeTypeL(*iContentString);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ delete iContentString;
+ iContentString = NULL;
+ iParseState = ELooking;
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwPropFindParser::OnContentL
+// This method is a callback that sends the content of the element.
+// Not all the content may be returned in one go.
+// The data may be sent in chunks.
+// When an OnEndElementL is received there is no more content to be sent.
+// @param aBytes is the raw content data for the element.
+// The client is responsible for converting the data to the
+// required character set if necessary.
+// In some instances the content may be binary and must not be converted.
+// @param aErrorCode is the error code.
+// If this is not KErrNone then special action may be required.
+//
+void CRsfwPropFindParser::OnContentL(const TDesC8& aBytes, TInt aErrorCode)
+ {
+ if (aErrorCode)
+ {
+ User::Leave(aErrorCode);
+ }
+
+ // We want to add to contentstring only if we are in a state
+ // where the content is interesting to us
+ if ((iParseState == EName) || (iParseState == EModified) ||
+ (iParseState == ELength) || (iParseState ==EETag) ||
+ (iParseState == EContentType))
+ {
+ if (!iContentString)
+ {
+ iContentString = HBufC8::NewL(aBytes.Length());
+ TPtr8 string = iContentString->Des();
+ string.Append(aBytes);
+ }
+ else
+ {
+ iContentString =
+ iContentString->ReAllocL(iContentString->Length() +
+ aBytes.Length());
+ TPtr8 string = iContentString->Des();
+ string.Append(aBytes);
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwPropFindParser::OnStartPrefixMappingL
+// This method is a notification of the beginning of the scope of a prefix-URI
+// Namespace mapping.
+// This method is always called before corresponding OnStartElementL method.
+// @param aPrefix is the Namespace prefix being declared.
+// @param aUri is the Namespace URI the prefix is mapped to.
+// @param aErrorCode is the error code.
+// If this is not KErrNone then special action may be required.
+// ----------------------------------------------------------------------------
+//
+void CRsfwPropFindParser::OnStartPrefixMappingL(const RString& /* aPrefix */,
+ const RString& /* aUri */,
+ TInt aErrorCode)
+ {
+ if (aErrorCode)
+ {
+ User::Leave(aErrorCode);
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwPropFindParser::OnEndPrefixMappingL
+// This method is a notification of end of the scope of a prefix-URI mapping.
+// This method is called after the corresponding DoEndElementL method.
+// @param aPrefix is the Namespace prefix that was mapped.
+// @param aErrorCode is the error code.
+// If this is not KErrNone then special action may be required.
+// ----------------------------------------------------------------------------
+//
+void CRsfwPropFindParser::OnEndPrefixMappingL(const RString& /* aPrefix */,
+ TInt aErrorCode)
+ {
+ if (aErrorCode)
+ {
+ User::Leave(aErrorCode);
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwPropFindParser::OnIgnorableWhiteSpaceL
+// This method is a notification of ignorable whitespace in element content.
+// @param aBytes are the ignored bytes from the document being parsed.
+// @param aErrorCode is the error code.
+// If this is not KErrNone then special action may be required.
+// ----------------------------------------------------------------------------
+//
+void CRsfwPropFindParser::OnIgnorableWhiteSpaceL(const TDesC8& /* aBytes */,
+ TInt aErrorCode)
+ {
+ if (aErrorCode)
+ {
+ User::Leave(aErrorCode);
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwPropFindParser::OnSkippedEntityL
+// This method is a notification of a skipped entity.
+// If the parser encounters an external entity it does not need to expand it -
+// it can return the entity as aName for the client to deal with.
+// @param aName is the name of the skipped entity.
+// @param aErrorCode is the error code.
+// If this is not KErrNone then special action may be required.
+// ----------------------------------------------------------------------------
+//
+void CRsfwPropFindParser::OnSkippedEntityL(const RString& /* aName */,
+ TInt aErrorCode)
+ {
+ if (aErrorCode)
+ {
+ User::Leave(aErrorCode);
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwPropFindParser::OnProcessingInstructionL
+// This method is a receive notification of a processing instruction.
+// @param aTarget is the processing instruction target.
+// @param aData is the processing instruction data. If empty none was supplied.
+// @param aErrorCode is the error code.
+// If this is not KErrNone then special action may be required.
+// ----------------------------------------------------------------------------
+//
+void CRsfwPropFindParser::OnProcessingInstructionL(const TDesC8& /* aTarget */,
+ const TDesC8& /* aData */,
+ TInt aErrorCode)
+ {
+ if (aErrorCode)
+ {
+ User::Leave(aErrorCode);
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwPropFindParser::OnError
+// This method indicates an error has occurred.
+// @param aErrorCode is the error code
+// ----------------------------------------------------------------------------
+//
+void CRsfwPropFindParser::OnError(TInt aErrorCode)
+ {
+ DEBUGSTRING(("CRsfwPropFindParser::OnError(%d)", aErrorCode));
+ iError = aErrorCode;
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwPropFindParser::GetExtendedInterface
+// This method obtains the interface matching the specified uid.
+// @return 0 if no interface matching the uid is found.
+// Otherwise, the this pointer cast to that interface.
+// @param aUid the uid identifying the required interface.
+// ----------------------------------------------------------------------------
+//
+TAny* CRsfwPropFindParser::GetExtendedInterface(const TInt32 /* aUid */)
+ {
+ return NULL;
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwPropFindParser::SetDirEntArray
+// Set a pointer to the directory entry array to be filled.
+// ----------------------------------------------------------------------------
+//
+void CRsfwPropFindParser::SetDirEntArray(RPointerArray<CRsfwDirEnt>* aDirEntArray)
+ {
+ iDirEntArray = aDirEntArray;
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwPropFindParser::SetTargetDirectory
+// Set the directory for which PROPFIND was targeted.
+// ----------------------------------------------------------------------------
+//
+void CRsfwPropFindParser::SetTargetDirectory(const TDesC& aPropFindPath,
+ TInt aDepth)
+ {
+ iPropFindPath = &aPropFindPath;
+ iDepth = aDepth;
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwPropFindParser::ClearDirEntryL()
+// Clear directory entry for later use.
+// ----------------------------------------------------------------------------
+//
+void CRsfwPropFindParser::ClearDirEntryL()
+ {
+ delete iDirEntry;
+ iDirEntry = NULL;
+ TPtrC noName;
+ iDirEntry = CRsfwDirEnt::NewL(noName, NULL);
+ // Will be changed to directory, if we ran into ´<collection> tag
+ iDirEntry->Attr()->SetAtt(KEntryAttNormal);
+ }
+
+// ----------------------------------------------------------------------------
+// CRsfwPropFindParser::DecodeL()
+// First UTF-8 decode and then escape decode data.
+// ----------------------------------------------------------------------------
+//
+HBufC* CRsfwPropFindParser::DecodeL(const TDesC8& aData)
+ {
+ HBufC8* utf8Data = EscapeUtils::EscapeDecodeL(aData);
+ CleanupStack::PushL(utf8Data);
+ HBufC* data = NULL;
+ // if converting to unicode fails, just return the escapedecoded string.
+ TRAPD(err, data = EscapeUtils::ConvertToUnicodeFromUtf8L(*utf8Data));
+ if (err)
+ {
+ data = HBufC::NewMaxL(utf8Data->Length());
+ TPtr dataPtr = data->Des();
+ dataPtr.Copy(*utf8Data);
+ }
+ CleanupStack::PopAndDestroy(utf8Data);
+ return data;
+
+ }
+
+TInt CRsfwPropFindParser::GetLastError()
+ {
+ return iError;
+ }
+
+
+// End of File