remotestoragefw/webdavaccessplugin/src/rsfwpropfindparser.cpp
branchRCL_3
changeset 20 1aa8c82cb4cb
parent 0 3ad9d5175a89
equal deleted inserted replaced
19:88ee4cf65e19 20:1aa8c82cb4cb
       
     1 /*
       
     2 * Copyright (c) 2002-2004 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  Parse WebDAV PROPFIND method response body
       
    15  *
       
    16 */
       
    17 
       
    18 
       
    19 // INCLUDE FILES
       
    20 #include <f32file.h>
       
    21 #include <escapeutils.h>
       
    22 #include <tinternetdate.h>
       
    23 
       
    24 #include "rsfwpropfindparser.h"
       
    25 //#include "rsfwdirent.h"
       
    26 #include "rsfwdirentattr.h"
       
    27 #include "mdebug.h"
       
    28 #include "uri8.h"
       
    29 
       
    30 // ============================ MEMBER FUNCTIONS ==============================
       
    31 CRsfwPropFindParser* CRsfwPropFindParser::NewLC()
       
    32     {
       
    33     CRsfwPropFindParser* self = new (ELeave) CRsfwPropFindParser;
       
    34     CleanupStack::PushL(self);
       
    35     self->ConstructL();
       
    36     return self;
       
    37     }
       
    38 
       
    39 CRsfwPropFindParser* CRsfwPropFindParser::NewL()
       
    40     {
       
    41     CRsfwPropFindParser* self = NewLC();
       
    42     CleanupStack::Pop(self);
       
    43     return self;
       
    44     }
       
    45 
       
    46 void CRsfwPropFindParser::ConstructL()
       
    47     {
       
    48     ClearDirEntryL();
       
    49     iCurrentIsParent = EFalse;
       
    50     }
       
    51 
       
    52 CRsfwPropFindParser::~CRsfwPropFindParser()
       
    53     {
       
    54     delete iDirEntry;
       
    55     delete iContentString;
       
    56     }
       
    57 
       
    58 // ----------------------------------------------------------------------------
       
    59 // CRsfwPropFindParser::OnStartDocumentL
       
    60 // This method is a callback to indicate the start of the document.
       
    61 // @param aDocParam Specifies the various parameters of the document.
       
    62 // @arg aDocParam.iCharacterSetName The character encoding of the document.
       
    63 // ----------------------------------------------------------------------------
       
    64 //
       
    65 void CRsfwPropFindParser::OnStartDocumentL(
       
    66     const Xml::RDocumentParameters& /* aDocParam */,
       
    67     TInt aErrCode)
       
    68     {
       
    69     iError = KErrNone;    // discard the old error
       
    70     if (!aErrCode)
       
    71         {
       
    72         iParseState = ELooking;
       
    73         }
       
    74     else
       
    75         {
       
    76         User::Leave(aErrCode);
       
    77         }
       
    78     
       
    79     }
       
    80 
       
    81 // ----------------------------------------------------------------------------
       
    82 // CRsfwPropFindParser::OnStartDocumentL
       
    83 // This method is a callback to indicate the end of the document.
       
    84 // ----------------------------------------------------------------------------
       
    85 //
       
    86 void CRsfwPropFindParser::OnEndDocumentL(TInt aErrCode)
       
    87     {
       
    88     if (aErrCode)
       
    89         {
       
    90         User::Leave(aErrCode);
       
    91         }
       
    92     }
       
    93 
       
    94 // ----------------------------------------------------------------------------
       
    95 // CRsfwPropFindParser::OnStartElementL
       
    96 // This method is a callback to indicate an element has been parsed.
       
    97 // @param aElement is a handle to the element's details.
       
    98 // @param aAttributes contains the attributes for the element.
       
    99 // @param aErrorCode is the error code.
       
   100 // If this is not KErrNone then special action may be required.
       
   101 // ----------------------------------------------------------------------------
       
   102 //
       
   103 void CRsfwPropFindParser::OnStartElementL(
       
   104     const Xml::RTagInfo& aElement,
       
   105     const Xml::RAttributeArray& /* aAttributes */,
       
   106     TInt aErrorCode)
       
   107     {
       
   108     _LIT8(KResponseHeader, "response");
       
   109     _LIT8(KContentType,    "getcontenttype");
       
   110     _LIT8(KDate,           "creationdate");
       
   111     _LIT8(KModified,       "getlastmodified");
       
   112     _LIT8(KLength,         "getcontentlength");
       
   113     _LIT8(KResourceType,   "resourcetype");
       
   114     _LIT8(KEtag,           "getetag");
       
   115 
       
   116     if (aErrorCode)
       
   117         {
       
   118         User::Leave(aErrorCode);
       
   119         }
       
   120 
       
   121     switch (iParseState)
       
   122         {
       
   123     case EName:
       
   124         break;
       
   125 
       
   126     case EResponse:
       
   127         {
       
   128         _LIT8(KHRef, "href");
       
   129         if (((aElement.LocalName()).DesC()).Compare(KHRef) == 0)
       
   130             {
       
   131             // href that follows response tag is the name of the file
       
   132             iParseState = EName;
       
   133             }
       
   134         }
       
   135         break;
       
   136 
       
   137     case EModified:
       
   138         break;
       
   139 
       
   140     case ELength:
       
   141         break;
       
   142 
       
   143     case EDate:
       
   144         break;
       
   145 
       
   146     case EResourceType:
       
   147         {
       
   148         _LIT8(KCollection, "collection");
       
   149         if (((aElement.LocalName()).DesC()).Compare(KCollection) == 0)
       
   150             {
       
   151             iDirEntry->Attr()->SetAtt(KEntryAttDir);
       
   152             }
       
   153         }
       
   154         break;
       
   155 
       
   156     case EContentType:
       
   157         break;
       
   158 
       
   159     case EETag:
       
   160         break;
       
   161 
       
   162     case ELooking: // we are trying to find the next interesting tag
       
   163         if (((aElement.LocalName()).DesC()).Compare(KModified) == 0)
       
   164             {
       
   165             iParseState = EModified;
       
   166             }
       
   167         else if (((aElement.LocalName()).DesC()).Compare(KLength) == 0)
       
   168             {
       
   169             iParseState = ELength;
       
   170             }
       
   171         else if (((aElement.LocalName()).DesC()).Compare(KDate) == 0)
       
   172             {
       
   173             iParseState = EDate;
       
   174             }
       
   175         else if (((aElement.LocalName()).DesC()).Compare(KResourceType) == 0)
       
   176             {
       
   177             iParseState = EResourceType;
       
   178             }
       
   179         else if (((aElement.LocalName()).DesC()).Compare(KContentType) == 0)
       
   180             {
       
   181             iParseState = EContentType;
       
   182             }
       
   183         else if (((aElement.LocalName()).DesC()).Compare(KResponseHeader) == 0)
       
   184             {
       
   185             iParseState = EResponse;
       
   186             }
       
   187         else if (((aElement.LocalName()).DesC()).Compare(KEtag) == 0)
       
   188             {
       
   189             iParseState = EETag;
       
   190             }
       
   191         else
       
   192             {
       
   193             // lint
       
   194             }
       
   195         break;
       
   196 
       
   197     default:
       
   198         break;
       
   199         }
       
   200     }
       
   201 
       
   202 // ----------------------------------------------------------------------------
       
   203 // CRsfwPropFindParser::OnEndElementL
       
   204 // This method is a callback to indicate that end of element has been reached.
       
   205 // @param aElement is a handle to the element's details.
       
   206 // @param aErrorCode is the error code.
       
   207 // If this is not KErrNone then special action may be required.
       
   208 // ----------------------------------------------------------------------------
       
   209 //
       
   210 void CRsfwPropFindParser::OnEndElementL(const Xml::RTagInfo& aElement,
       
   211                                     TInt aErrorCode)
       
   212     {
       
   213     if (aErrorCode)
       
   214         {
       
   215         User::Leave(aErrorCode);
       
   216         }
       
   217 
       
   218     // If we reached </response> we can fill next entry in iDirEntArray
       
   219     _LIT8(KResponse, "*response");
       
   220     if (((aElement.LocalName()).DesC()).Match(KResponse) != KErrNotFound)
       
   221         {
       
   222         // Save the entry if depth = 0 or depth = 1 and
       
   223         // this is not the parent directory
       
   224         switch (iDepth)
       
   225             {
       
   226         case 0:
       
   227             iDirEntArray->Append(iDirEntry);
       
   228             // ownership transferred
       
   229             iDirEntry = NULL;
       
   230             break;
       
   231 
       
   232         case 1:
       
   233             if (!iCurrentIsParent)
       
   234                 {
       
   235                 iDirEntArray->Append(iDirEntry);
       
   236                 // ownership transferred
       
   237                 iDirEntry = NULL;
       
   238                 }
       
   239             break;
       
   240 
       
   241         default:
       
   242             break;
       
   243             }
       
   244 
       
   245         if (iCurrentIsParent)
       
   246             {
       
   247             // We have 'seen' the end tag of parent directory
       
   248             iCurrentIsParent = EFalse;
       
   249             }
       
   250 
       
   251         // In any case going through an entry is complete,
       
   252         // reset iDirEntry
       
   253         ClearDirEntryL();
       
   254         delete iContentString;
       
   255         iContentString = NULL;
       
   256         iParseState = ELooking;
       
   257         }
       
   258 
       
   259     // otherwise we will continue reading
       
   260     // if we have some interesting content
       
   261     if ((iParseState != ELooking) && !iContentString)
       
   262         {
       
   263         iParseState = ELooking;
       
   264         return;
       
   265         }
       
   266 
       
   267     switch (iParseState)
       
   268         {
       
   269     case EName:
       
   270         {
       
   271         // Figure out whether the entry we are currently reading
       
   272         // is the directory itself.
       
   273         // The directory itself is the first one in the reply that
       
   274         // comes from server,
       
   275         // and the last one that our XML-parser passes to us
       
   276         
       
   277         // if the name is fully qualified URI, only take the path
       
   278         TPtrC8 uriPtr = iContentString->Des();
       
   279         TPtrC8 pathPtr = uriPtr;
       
   280         TUriParser8 uriParser;
       
   281         if (uriParser.Parse(uriPtr) == KErrNone) 
       
   282         {
       
   283         	pathPtr.Set(uriParser.Extract(EUriPath));
       
   284         }
       
   285         
       
   286         
       
   287         HBufC* name = DecodeL(pathPtr);
       
   288         CleanupStack::PushL(name);
       
   289         
       
   290         if (name->Compare(*iPropFindPath) == 0)
       
   291             {
       
   292             iCurrentIsParent = ETrue;
       
   293             }
       
   294         else
       
   295             {
       
   296             TPtrC namePtr = name->Des();
       
   297             if ((namePtr.Length() > 1) &&
       
   298                 (namePtr[namePtr.Length() - 1] == '/'))
       
   299                 {
       
   300                 // strip off trailing '/'
       
   301                 namePtr.Set(namePtr.Left(namePtr.Length() - 1));
       
   302                 }
       
   303 
       
   304             TInt pos = namePtr.LocateReverse('/');
       
   305             // Shouldn't be negative as
       
   306             // the path should always start with '/'
       
   307             if ((pos >= 0) && (namePtr.Length() > 1))
       
   308                 {
       
   309                 namePtr.Set((namePtr.Right(namePtr.Length() - (pos + 1))));
       
   310                 }
       
   311             iDirEntry->SetNameL(namePtr);
       
   312             }
       
   313         CleanupStack::PopAndDestroy(name);
       
   314         }
       
   315         break;
       
   316 
       
   317     case EModified:
       
   318         {
       
   319         // Webdav sends dates in RFC 822 format
       
   320         // (e.g., "Thu, 19 Dec 2002 13:51:16 GMT").
       
   321         // We parse them as 8 bit data.
       
   322         TInternetDate inetDate;
       
   323         inetDate.SetDateL(*iContentString);
       
   324         iDirEntry->Attr()->SetModified(inetDate.DateTime());
       
   325         }
       
   326         break;
       
   327 
       
   328     case ELength:
       
   329         {
       
   330         // Convert to int
       
   331         TLex8 lex(*iContentString);
       
   332         TInt len;
       
   333         User::LeaveIfError(lex.Val(len));
       
   334         iDirEntry->Attr()->SetSize(len);
       
   335         }
       
   336         break;
       
   337 
       
   338     case EETag:
       
   339         // etag is stored for files
       
   340         if (!(iDirEntry->Attr()->Att() & KEntryAttDir)) 
       
   341             {
       
   342             iDirEntry->Attr()->SetETagL(*iContentString);
       
   343             }
       
   344         
       
   345         break;
       
   346 
       
   347     case EContentType:
       
   348         {
       
   349         iDirEntry->Attr()->SetMimeTypeL(*iContentString);
       
   350         }
       
   351         break;
       
   352 
       
   353     default:
       
   354         break;
       
   355         }
       
   356 
       
   357     delete iContentString;
       
   358     iContentString = NULL;
       
   359     iParseState = ELooking;
       
   360     }
       
   361 
       
   362 // ----------------------------------------------------------------------------
       
   363 // CRsfwPropFindParser::OnContentL
       
   364 // This method is a callback that sends the content of the element.
       
   365 // Not all the content may be returned in one go.
       
   366 // The data may be sent in chunks.
       
   367 // When an OnEndElementL is received there is no more content to be sent.
       
   368 // @param aBytes is the raw content data for the element.
       
   369 // The client is responsible for converting the data to the
       
   370 // required character set if necessary.
       
   371 // In some instances the content may be binary and must not be converted.
       
   372 // @param aErrorCode is the error code.
       
   373 // If this is not KErrNone then special action may be required.
       
   374 //
       
   375 void CRsfwPropFindParser::OnContentL(const TDesC8& aBytes, TInt aErrorCode)
       
   376     {
       
   377     if (aErrorCode)
       
   378         {
       
   379         User::Leave(aErrorCode);
       
   380         }
       
   381 
       
   382     // We want to add to contentstring only if we are in a state
       
   383     // where the content is interesting to us
       
   384     if ((iParseState == EName) || (iParseState == EModified) ||
       
   385         (iParseState == ELength) || (iParseState ==EETag) ||
       
   386         (iParseState == EContentType))
       
   387         {
       
   388         if (!iContentString)
       
   389             {
       
   390             iContentString = HBufC8::NewL(aBytes.Length());
       
   391             TPtr8 string = iContentString->Des();
       
   392             string.Append(aBytes);
       
   393             }
       
   394         else
       
   395             {
       
   396             iContentString =
       
   397                 iContentString->ReAllocL(iContentString->Length() +
       
   398                                          aBytes.Length());
       
   399             TPtr8 string = iContentString->Des();
       
   400             string.Append(aBytes);
       
   401             }
       
   402         }
       
   403     }
       
   404 
       
   405 // ----------------------------------------------------------------------------
       
   406 // CRsfwPropFindParser::OnStartPrefixMappingL
       
   407 // This method is a notification of the beginning of the scope of a prefix-URI
       
   408 // Namespace mapping.
       
   409 // This method is always called before corresponding OnStartElementL method.
       
   410 // @param aPrefix is the Namespace prefix being declared.
       
   411 // @param aUri is the Namespace URI the prefix is mapped to.
       
   412 // @param aErrorCode is the error code.
       
   413 // If this is not KErrNone then special action may be required.
       
   414 // ----------------------------------------------------------------------------
       
   415 //
       
   416 void CRsfwPropFindParser::OnStartPrefixMappingL(const RString& /* aPrefix */,
       
   417                                             const RString& /* aUri */,
       
   418                                             TInt aErrorCode)
       
   419     {
       
   420     if (aErrorCode)
       
   421         {
       
   422         User::Leave(aErrorCode);
       
   423         }
       
   424     }
       
   425 
       
   426 // ----------------------------------------------------------------------------
       
   427 // CRsfwPropFindParser::OnEndPrefixMappingL
       
   428 // This method is a notification of end of the scope of a prefix-URI mapping.
       
   429 // This method is called after the corresponding DoEndElementL method.
       
   430 // @param aPrefix is the Namespace prefix that was mapped.
       
   431 // @param aErrorCode is the error code.
       
   432 // If this is not KErrNone then special action may be required.
       
   433 // ----------------------------------------------------------------------------
       
   434 //
       
   435 void CRsfwPropFindParser::OnEndPrefixMappingL(const RString& /* aPrefix */,
       
   436                                           TInt aErrorCode)
       
   437     {
       
   438     if (aErrorCode)
       
   439         {
       
   440         User::Leave(aErrorCode);
       
   441         }
       
   442     }
       
   443 
       
   444 // ----------------------------------------------------------------------------
       
   445 // CRsfwPropFindParser::OnIgnorableWhiteSpaceL
       
   446 // This method is a notification of ignorable whitespace in element content.
       
   447 // @param aBytes are the ignored bytes from the document being parsed.
       
   448 // @param aErrorCode is the error code.
       
   449 // If this is not KErrNone then special action may be required.
       
   450 // ----------------------------------------------------------------------------
       
   451 //
       
   452 void CRsfwPropFindParser::OnIgnorableWhiteSpaceL(const TDesC8& /* aBytes */,
       
   453                                              TInt aErrorCode)
       
   454     {
       
   455     if (aErrorCode)
       
   456         {
       
   457         User::Leave(aErrorCode);
       
   458         }
       
   459     }
       
   460 
       
   461 // ----------------------------------------------------------------------------
       
   462 // CRsfwPropFindParser::OnSkippedEntityL
       
   463 // This method is a notification of a skipped entity.
       
   464 // If the parser encounters an external entity it does not need to expand it -
       
   465 // it can return the entity as aName for the client to deal with.
       
   466 // @param aName is the name of the skipped entity.
       
   467 // @param aErrorCode is the error code.
       
   468 // If this is not KErrNone then special action may be required.
       
   469 // ----------------------------------------------------------------------------
       
   470 //
       
   471 void CRsfwPropFindParser::OnSkippedEntityL(const RString& /* aName */,
       
   472                                        TInt aErrorCode)
       
   473     {
       
   474     if (aErrorCode)
       
   475         {
       
   476         User::Leave(aErrorCode);
       
   477         }
       
   478     }
       
   479 
       
   480 // ----------------------------------------------------------------------------
       
   481 // CRsfwPropFindParser::OnProcessingInstructionL
       
   482 // This method is a receive notification of a processing instruction.
       
   483 // @param aTarget is the processing instruction target.
       
   484 // @param aData is the processing instruction data. If empty none was supplied.
       
   485 // @param aErrorCode is the error code.
       
   486 // If this is not KErrNone then special action may be required.
       
   487 // ----------------------------------------------------------------------------
       
   488 //
       
   489 void CRsfwPropFindParser::OnProcessingInstructionL(const TDesC8& /* aTarget */,
       
   490                                                const TDesC8& /* aData */,
       
   491                                                TInt aErrorCode)
       
   492     {
       
   493     if (aErrorCode)
       
   494         {
       
   495         User::Leave(aErrorCode);
       
   496         }
       
   497     }
       
   498 
       
   499 // ----------------------------------------------------------------------------
       
   500 // CRsfwPropFindParser::OnError
       
   501 // This method indicates an error has occurred.
       
   502 // @param aErrorCode is the error code
       
   503 // ----------------------------------------------------------------------------
       
   504 //
       
   505 void CRsfwPropFindParser::OnError(TInt aErrorCode)
       
   506     {
       
   507     DEBUGSTRING(("CRsfwPropFindParser::OnError(%d)", aErrorCode));
       
   508     iError = aErrorCode;
       
   509     }
       
   510 
       
   511 // ----------------------------------------------------------------------------
       
   512 // CRsfwPropFindParser::GetExtendedInterface
       
   513 // This method obtains the interface matching the specified uid.
       
   514 // @return 0 if no interface matching the uid is found.
       
   515 // Otherwise, the this pointer cast to that interface.
       
   516 // @param aUid the uid identifying the required interface.
       
   517 // ----------------------------------------------------------------------------
       
   518 //
       
   519 TAny* CRsfwPropFindParser::GetExtendedInterface(const TInt32 /* aUid */)
       
   520     {
       
   521     return NULL;
       
   522     }
       
   523 
       
   524 // ----------------------------------------------------------------------------
       
   525 // CRsfwPropFindParser::SetDirEntArray
       
   526 // Set a pointer to the directory entry array to be filled.
       
   527 // ----------------------------------------------------------------------------
       
   528 //
       
   529 void CRsfwPropFindParser::SetDirEntArray(RPointerArray<CRsfwDirEnt>* aDirEntArray)
       
   530     {
       
   531     iDirEntArray = aDirEntArray;
       
   532     }
       
   533 
       
   534 // ----------------------------------------------------------------------------
       
   535 // CRsfwPropFindParser::SetTargetDirectory
       
   536 // Set the directory for which PROPFIND was targeted.
       
   537 // ----------------------------------------------------------------------------
       
   538 //
       
   539 void CRsfwPropFindParser::SetTargetDirectory(const TDesC& aPropFindPath,
       
   540                                          TInt aDepth)
       
   541     {
       
   542     iPropFindPath = &aPropFindPath;
       
   543     iDepth = aDepth;
       
   544     }
       
   545 
       
   546 // ----------------------------------------------------------------------------
       
   547 // CRsfwPropFindParser::ClearDirEntryL()
       
   548 // Clear directory entry for later use.
       
   549 // ----------------------------------------------------------------------------
       
   550 //
       
   551 void CRsfwPropFindParser::ClearDirEntryL()
       
   552     {
       
   553     delete iDirEntry;
       
   554     iDirEntry = NULL;
       
   555     TPtrC noName;
       
   556     iDirEntry = CRsfwDirEnt::NewL(noName, NULL);
       
   557     // Will be changed to directory, if we ran into ´<collection> tag
       
   558     iDirEntry->Attr()->SetAtt(KEntryAttNormal);
       
   559     }
       
   560 
       
   561 // ----------------------------------------------------------------------------
       
   562 // CRsfwPropFindParser::DecodeL()
       
   563 // First UTF-8 decode and then escape decode data.
       
   564 // ----------------------------------------------------------------------------
       
   565 //
       
   566 HBufC* CRsfwPropFindParser::DecodeL(const TDesC8& aData)
       
   567     {
       
   568     HBufC8* utf8Data = EscapeUtils::EscapeDecodeL(aData);
       
   569     CleanupStack::PushL(utf8Data);
       
   570     HBufC* data = NULL;
       
   571     // if converting to unicode fails, just return the escapedecoded string.
       
   572     TRAPD(err, data = EscapeUtils::ConvertToUnicodeFromUtf8L(*utf8Data));
       
   573     if (err) 
       
   574         {
       
   575         data = HBufC::NewMaxL(utf8Data->Length());
       
   576         TPtr dataPtr = data->Des();
       
   577         dataPtr.Copy(*utf8Data);
       
   578         }
       
   579     CleanupStack::PopAndDestroy(utf8Data);
       
   580     return data;    
       
   581 
       
   582     }
       
   583     
       
   584 TInt CRsfwPropFindParser::GetLastError() 
       
   585 	{
       
   586 	return iError;
       
   587 	}
       
   588 	
       
   589 
       
   590 //  End of File