remotestoragefw/webdavaccessplugin/src/rsfwpropfindparser.cpp
changeset 0 3ad9d5175a89
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/remotestoragefw/webdavaccessplugin/src/rsfwpropfindparser.cpp	Thu Dec 17 09:07:59 2009 +0200
@@ -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