javamanager/javasettings/appmngrplugin/src/appmngr2midletmanifestreader.cpp
branchRCL_3
changeset 19 04becd199f91
child 60 6c158198356e
equal deleted inserted replaced
16:f5050f1da672 19:04becd199f91
       
     1 /*
       
     2 * Copyright (c) 2007 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:  CManifestReader implementation file
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include <caf/content.h>
       
    20 #include <zipfile.h>
       
    21 #include <utf.h>
       
    22 #include <e32cmn.h>
       
    23 
       
    24 #include <javaattribute.h>
       
    25 
       
    26 #include "appmngr2midletmanifestreader.h"
       
    27 #include "logger.h"                         // LOG
       
    28 
       
    29 const TInt KAllRead = -1;
       
    30 const TInt KAttributeMinSize = 3;
       
    31 const TInt KFilePrefix = 4;
       
    32 
       
    33 _LIT(KManifestEntryName, "META-INF/MANIFEST.MF");
       
    34 
       
    35 const TUint32 LF  = 10;
       
    36 const TUint32 CR  = 13;
       
    37 const TUint32 SP  = 32;
       
    38 const TUint32 COLON = 58;
       
    39 
       
    40 
       
    41 AppMngr2MidletManifestReader::AppMngr2MidletManifestReader(RFs& aFs) :
       
    42         mFs(aFs), mSessionOpen(false)
       
    43 {
       
    44 }
       
    45 
       
    46 AppMngr2MidletManifestReader::~AppMngr2MidletManifestReader()
       
    47 {
       
    48     // Close the file session (if opened by ManifestReader)
       
    49     if (mSessionOpen)
       
    50     {
       
    51         mFs.Close();
       
    52     }
       
    53 }
       
    54 
       
    55 void AppMngr2MidletManifestReader::ReadManifestL(
       
    56     const TDesC& aManifestFile,
       
    57     RPointerArray<MJavaAttribute>& aAttributes)
       
    58 {
       
    59     if (mManifestContent.get())
       
    60     {
       
    61         mManifestContent.reset(0);
       
    62     }
       
    63 
       
    64     ContentL(aManifestFile);
       
    65 
       
    66     ReadAttributesL(aAttributes);
       
    67 }
       
    68 
       
    69 void AppMngr2MidletManifestReader::ReadAttributesL(
       
    70     RPointerArray<MJavaAttribute>& aAttributes)
       
    71 {
       
    72     TPtr16 contentPtr(mManifestContent->Des());
       
    73 
       
    74     //remove white space from the beginning of the file
       
    75     contentPtr.TrimLeft();
       
    76 
       
    77     TInt attributeIndex = -1;
       
    78 
       
    79     // Continue until new line is found and manifest content is more than 3.
       
    80     // It can't be shorter than a:b\n. Actually spec specifies that it must be 'a: b\n'
       
    81     // that makes four but for the robustness as also user inserted variables
       
    82     // are read. Parameter can be e.g. either TestCase1:myCase or TestCase1: myCase.
       
    83     while ((attributeIndex = ReadLineIndexL(EFalse)) != KAllRead)
       
    84     {
       
    85         HBufC16* attribute = contentPtr.Left(attributeIndex).AllocLC();
       
    86         TPtr16 attributePtr(attribute->Des());
       
    87         attributePtr.Trim();
       
    88 
       
    89         TInt colonIndex = attributePtr.Locate(COLON);
       
    90 
       
    91         // Invalid attribute. Name not found
       
    92         if (KErrNotFound == colonIndex)
       
    93         {
       
    94             ELOG(EJavaAppMngrPlugin, "MF parsing failed: No attribute name defined");
       
    95             //User::Leave(KJavaParseNameAttributeMissing);
       
    96             User::Leave(KErrArgument);
       
    97         }
       
    98 
       
    99         // Implementation expects that attribute name fits to first line.
       
   100         HBufC16* name = attributePtr.Left(colonIndex).AllocLC();
       
   101         TPtr16 namePtr(name->Des());
       
   102         namePtr.Trim();
       
   103 
       
   104         ValidateAttributeNameL(namePtr);
       
   105 
       
   106         // Rest of the manifest data can be continuational value.
       
   107         HBufC16* value = HBufC16::NewLC(contentPtr.Length());
       
   108         TPtr16 valuePtr(value->Des());
       
   109 
       
   110         // Skip colon
       
   111         valuePtr.Append(attributePtr.Mid(colonIndex + 1));
       
   112         valuePtr.Trim();
       
   113 
       
   114         ReadContinuationLineL(valuePtr, contentPtr, attributeIndex);
       
   115 
       
   116         // If manifest attribute value is not defined attribute is
       
   117         // skipped and it is not returned to caller.
       
   118         if (valuePtr.Length() > 0)
       
   119         {
       
   120             CJavaAttribute* javaAttribute
       
   121             = CJavaAttribute::NewL(namePtr, valuePtr, EFalse);
       
   122             aAttributes.Append(javaAttribute);
       
   123         }
       
   124 
       
   125         CleanupStack::PopAndDestroy(value);
       
   126         CleanupStack::PopAndDestroy(name);
       
   127         CleanupStack::PopAndDestroy(attribute);
       
   128 
       
   129         // Delete already handled attribute from the buffer.
       
   130         // Content is read until the enter and it must be deleted to reach next one.
       
   131         contentPtr.Delete(0, attributeIndex + 1);
       
   132         contentPtr.TrimLeft();
       
   133     }
       
   134 }
       
   135 
       
   136 void AppMngr2MidletManifestReader::ContentL(const TDesC& aManifestFileName)
       
   137 {
       
   138     RFile file;
       
   139     TInt err = file.Open(mFs,
       
   140                          aManifestFileName,
       
   141                          EFileStream | EFileShareAny | EFileRead);
       
   142 
       
   143     User::LeaveIfError(err);
       
   144     CleanupClosePushL(file);
       
   145 
       
   146     std::auto_ptr<HBufC8>fileStart(HBufC8::NewL(KFilePrefix));
       
   147     TPtr8 fileStartPtr(fileStart->Des());
       
   148 
       
   149     std::auto_ptr<HBufC16>filePrefix(HBufC16::NewL(KFilePrefix));
       
   150     TPtr16 filePrefixPtr(filePrefix->Des());
       
   151 
       
   152     err = file.Read(fileStartPtr, KFilePrefix);
       
   153     User::LeaveIfError(err);
       
   154 
       
   155     err = CnvUtfConverter::ConvertToUnicodeFromUtf8(
       
   156               filePrefixPtr, fileStartPtr);
       
   157 
       
   158     if (KErrNone != err)
       
   159     {
       
   160         ELOG1(EJavaAppMngrPlugin, "MF UTF-8 to unicode conversion failed: %d", err);
       
   161         // User::Leave(KJavaErrNoneUTF8);
       
   162         User::Leave(KErrArgument);
       
   163     }
       
   164 
       
   165     if (fileStartPtr.Length() < KFilePrefix)
       
   166     {
       
   167         ELOG(EJavaAppMngrPlugin, "Not enough content at manifest file");
       
   168         // User::Leave(KJavaErrInvalidManifest);
       
   169         User::Leave(KErrArgument);
       
   170     }
       
   171 
       
   172     // Check from CAF if file is DRM protected.
       
   173     TBool drmProtected = EFalse;
       
   174     std::auto_ptr<ContentAccess::CContent>content(
       
   175         ContentAccess::CContent::NewL(file));
       
   176 
       
   177     err = content->GetAttribute(ContentAccess::EIsProtected, drmProtected);
       
   178     if (KErrNone != err)
       
   179     {
       
   180         ELOG1(EJavaAppMngrPlugin, "DRM protection check failed: %d", err);
       
   181         User::Leave(KErrArgument);
       
   182     }
       
   183 
       
   184     // Detect JAR package. JAR is either a DRM protected file or a ZIP file.
       
   185     // ZIP file has PK\003\004 prefix.
       
   186     if (drmProtected
       
   187             || (filePrefixPtr[0] == 0x50
       
   188                 && filePrefixPtr[1] == 0x4B
       
   189                 && filePrefixPtr[2] == 0x03
       
   190                 && filePrefixPtr[3] == 0x04))
       
   191     {
       
   192         ReadManifestContentFromPackageL(file);
       
   193     }
       
   194     else
       
   195     {
       
   196         // Plain manifest file
       
   197         ReadManifestContentL(file);
       
   198     }
       
   199     CleanupStack::PopAndDestroy(&file);
       
   200 }
       
   201 
       
   202 void AppMngr2MidletManifestReader::ReadManifestContentL(RFile& aManifestFile)
       
   203 {
       
   204     // Reads the entire file into a heap descriptor. Use the content
       
   205     // access framework to access the manifest.
       
   206     ContentAccess::CContent* content
       
   207     = ContentAccess::CContent::NewLC(aManifestFile);
       
   208     ContentAccess::CData* manifestFile
       
   209     = content->OpenContentL(ContentAccess::EPeek);
       
   210     CleanupStack::PushL(manifestFile);
       
   211 
       
   212     HBufC8* manifestFileData = ReadRawManifestFileL(*manifestFile);
       
   213     TPtr8 ptr(manifestFileData->Des());
       
   214 
       
   215     CleanupStack::PopAndDestroy(manifestFile);
       
   216     CleanupStack::PopAndDestroy(content);
       
   217     CleanupStack::PushL(manifestFileData);
       
   218 
       
   219     mManifestContent.reset(HBufC16::NewL(ptr.Size()));
       
   220     TPtr16 ucsPtr(mManifestContent->Des());
       
   221     TInt err = CnvUtfConverter::ConvertToUnicodeFromUtf8(ucsPtr, ptr);
       
   222 
       
   223     if (KErrNone != err)
       
   224     {
       
   225         ELOG1(EJavaAppMngrPlugin, "MF UTF-8 to unicode conversion failed: %d", err);
       
   226         //User::Leave(KJavaErrNoneUTF8);
       
   227         User::Leave(KErrArgument);
       
   228     }
       
   229     CleanupStack::PopAndDestroy(manifestFileData);
       
   230 }
       
   231 
       
   232 HBufC8* AppMngr2MidletManifestReader::ReadRawManifestFileL(
       
   233     ContentAccess::CData& aManifestFile)
       
   234 {
       
   235     // Reads size of file
       
   236     TInt manifestSize;
       
   237     aManifestFile.DataSizeL(manifestSize);
       
   238     // allocates buffer for file contents, if this is too big and device runs
       
   239     // out of memory function will leave. Do not really care about this as file
       
   240     // was unlikely to have been a manifest file at all.
       
   241     HBufC8* manifestFileData = HBufC8::NewMaxLC(manifestSize);
       
   242     TPtr8 manifestFileDataPtr(manifestFileData->Des());
       
   243 
       
   244     // Now read the manifest file
       
   245     User::LeaveIfError(aManifestFile.Read(manifestFileDataPtr, manifestSize));
       
   246     CleanupStack::Pop(manifestFileData);
       
   247 
       
   248     return manifestFileData;
       
   249 }
       
   250 
       
   251 void AppMngr2MidletManifestReader::ReadManifestContentFromPackageL(
       
   252     RFile& aPackageFile)
       
   253 {
       
   254     CZipFile* zipFile = CZipFile::NewL(mFs, aPackageFile);
       
   255     CleanupStack::PushL(zipFile);
       
   256 
       
   257     // Seek manifest file
       
   258     CZipFileMember* zippedFile =
       
   259         zipFile->CaseSensitiveOrCaseInsensitiveMemberL(KManifestEntryName());
       
   260 
       
   261     if (!zippedFile)
       
   262     {
       
   263         ELOG(EJavaAppMngrPlugin, "Package is missing manifest");
       
   264         //User::LeaveIfError(KJavaErrMissingManifest);
       
   265         User::Leave(KErrArgument);
       
   266     }
       
   267     CleanupStack::PushL(zippedFile);
       
   268 
       
   269     TUint uncompressedSize = zippedFile->UncompressedSize();
       
   270     if ((TUint)uncompressedSize>=(KMaxTInt/2))
       
   271     {
       
   272         ELOG(EJavaAppMngrPlugin, "Invalid manifest");
       
   273         //User::Leave(KJavaErrInvalidManifest);
       
   274         User::Leave(KErrArgument);
       
   275     }
       
   276     HBufC8* resultData = HBufC8::NewLC(uncompressedSize);
       
   277 
       
   278     RZipFileMemberReaderStream* zippedStream = 0;
       
   279     TInt err = zipFile->GetInputStreamL(zippedFile, zippedStream);
       
   280     User::LeaveIfError(err);
       
   281     CleanupStack::PushL(zippedStream);
       
   282 
       
   283     TPtr8 ptr(resultData->Des());
       
   284     User::LeaveIfError(zippedStream->Read(ptr, uncompressedSize));
       
   285 
       
   286     CleanupStack::PopAndDestroy(zippedStream);
       
   287 
       
   288     mManifestContent.reset(HBufC16::NewL(uncompressedSize));
       
   289     TPtr16 ucsPtr(mManifestContent->Des());
       
   290     err = CnvUtfConverter::ConvertToUnicodeFromUtf8(ucsPtr, ptr);
       
   291 
       
   292     if (KErrNone != err)
       
   293     {
       
   294         ELOG1(EJavaAppMngrPlugin, "UTF-8 to unicode conversion failed: %d", err);
       
   295         //User::Leave(KJavaErrNoneUTF8);
       
   296         User::Leave(KErrArgument);
       
   297     }
       
   298 
       
   299     CleanupStack::PopAndDestroy(resultData);
       
   300     CleanupStack::PopAndDestroy(zippedFile);
       
   301     CleanupStack::PopAndDestroy(zipFile);
       
   302 }
       
   303 
       
   304 TInt AppMngr2MidletManifestReader::ReadLineIndexL(TBool aContinuation)
       
   305 {
       
   306     TPtr16 contentPtr(mManifestContent->Des());
       
   307 
       
   308     if (contentPtr.Length() < KAttributeMinSize)
       
   309     {
       
   310         // EOF. This covers also case where all rest of the data
       
   311         // was whitespace characters trimmed were trimmed off before
       
   312         // going to next line.
       
   313         return KAllRead;
       
   314     }
       
   315 
       
   316     TInt attributeIndex = contentPtr.Locate(LF);
       
   317     TInt tmp = contentPtr.Locate(CR);
       
   318 
       
   319     // New line can be CR LF | LF | CR. Let's take
       
   320     // the first appearance of new line character.
       
   321     if ((tmp < attributeIndex && tmp != KErrNotFound)
       
   322             || attributeIndex == KErrNotFound)
       
   323     {
       
   324         // This covers also new line indicated only with CR.
       
   325         attributeIndex = tmp;
       
   326     }
       
   327 
       
   328     if (KErrNotFound == attributeIndex && KErrNotFound == tmp)
       
   329     {
       
   330         // Check if no enter after last line
       
   331         if (contentPtr.Length() > KAttributeMinSize)
       
   332         {
       
   333             attributeIndex = contentPtr.Length();
       
   334         }
       
   335         else
       
   336         {
       
   337             ELOG(EJavaAppMngrPlugin, "No attribute found");
       
   338             //User::Leave(KJavaErrInvalidManifest);
       
   339             User::Leave(KErrArgument);
       
   340         }
       
   341     }
       
   342     else if ((attributeIndex < KAttributeMinSize) && !aContinuation)
       
   343     {
       
   344         // Minimum parameter length is 4 e.g. 'a: b\n' or 'a:b\n'
       
   345         // This is a bit more robust than manifest specification as
       
   346         // it expects nameCOLONSPACEvalue format.
       
   347         ELOG(EJavaAppMngrPlugin, "Invalid attribute");
       
   348         //User::Leave(KJavaErrInvalidManifest);
       
   349         User::Leave(KErrArgument);
       
   350     }
       
   351     else if (attributeIndex <= 0)
       
   352     {
       
   353         // Minimum continuation parameter length is 1 e.g. 'a\n'
       
   354         ELOG(EJavaAppMngrPlugin, "Invalid continuation attribute");
       
   355         //User::Leave(KJavaErrInvalidManifest);
       
   356         User::Leave(KErrArgument);
       
   357     }
       
   358 
       
   359     return attributeIndex;
       
   360 }
       
   361 
       
   362 void AppMngr2MidletManifestReader::ReadContinuationLineL(TDes16& aValue,
       
   363         TDes& aContent,
       
   364         TInt& aIndex)
       
   365 {
       
   366     TBool continuation = ETrue;
       
   367 
       
   368     while (continuation)
       
   369     {
       
   370         if (aContent.Length() <= aIndex + 2)
       
   371         {
       
   372             // Last line
       
   373             continuation = EFalse;
       
   374         }
       
   375         // Continuation can be CR LF SPACE | LF SPACE | CR SPACE
       
   376         else if ((aContent[ aIndex ] == CR
       
   377                   && aContent[ aIndex + 1 ] == LF
       
   378                   && aContent[ aIndex + 2 ] == SP)
       
   379                  ||
       
   380                  (aContent[ aIndex ] == CR
       
   381                   && aContent[ aIndex + 1 ] == SP)
       
   382                  ||
       
   383                  (aContent[ aIndex ] == LF
       
   384                   && aContent[ aIndex + 1 ] == SP))
       
   385         {
       
   386             // Clean previous entry.
       
   387             aContent.Delete(0, aIndex + 1);
       
   388 
       
   389             // Delete continuation indicator. Trim cannot be used here. If continuation
       
   390             // starts with SP it will be trimmed out and that must be prevented.
       
   391 
       
   392             // CR SP or LF SP case
       
   393             if (aContent[0] == SP)
       
   394             {
       
   395                 if ((aContent.Length() > 1) &&
       
   396                         (aContent[1] != CR) && (aContent[1] != LF))
       
   397                 {
       
   398                     aContent.Delete(0, 1);//for Manifest i JAD
       
   399                 }
       
   400             }
       
   401             // CR LF SP case
       
   402             else
       
   403             {
       
   404                 if ((aContent.Length() > 2) &&
       
   405                         (aContent[2] != CR) && (aContent[2] != LF))
       
   406                 {
       
   407                     aContent.Delete(0, 2);//for Manifest i JAD
       
   408                 }
       
   409                 else
       
   410                 {
       
   411                     aContent.Delete(0, 1);//for Manifest i JAD
       
   412                 }
       
   413             }
       
   414 
       
   415             aIndex = ReadLineIndexL(ETrue);
       
   416             if (aIndex != KAllRead)
       
   417             {
       
   418                 // Do not append whitespace combination. Only content.
       
   419                 aValue.Append(aContent.Left(aIndex));
       
   420                 aValue.TrimRight();
       
   421             }
       
   422             else
       
   423             {
       
   424                 // Can't be continuation if all read. Not leaving
       
   425                 // as last line can easilly contain unnecessary SPACEs.
       
   426                 continuation = EFalse;
       
   427             }
       
   428         }
       
   429         else
       
   430         {
       
   431             continuation = EFalse;
       
   432         }
       
   433     }
       
   434 }
       
   435 
       
   436 void AppMngr2MidletManifestReader::ValidateAttributeNameL(TDesC16& aName)
       
   437 {
       
   438     if (aName.Length() == 0)
       
   439     {
       
   440         ELOG(EJavaAppMngrPlugin, "Invalid attribute name");
       
   441         // User::Leave(KJavaParseInvalidAttributeName);
       
   442         User::Leave(KErrArgument);
       
   443     }
       
   444     TLex lexer(aName);
       
   445     TChar ch;
       
   446 
       
   447     // Manifest name cannot start with - and _ chars.
       
   448     ch = lexer.Get();
       
   449 
       
   450     if (ch == '_' || ch == '-')
       
   451     {
       
   452         ELOG(EJavaAppMngrPlugin, "Invalid attribute name start");
       
   453         //User::Leave(KJavaParseInvalidAttributeName);
       
   454         User::Leave(KErrArgument);
       
   455 
       
   456     }
       
   457 
       
   458     lexer.UnGet();
       
   459 
       
   460     while ((ch = lexer.Get()) != '\0')
       
   461     {
       
   462         // Allowed chars: {A-Z} | {a-z} | {0-9} | - | _
       
   463         if (!('0' <= ch && ch <= '9')
       
   464                 && !(ch >= 'a' && ch <= 'z')
       
   465                 && !(ch >= 'A' && ch <= 'Z')
       
   466                 && !('-' == ch)
       
   467                 && !('_' == ch)
       
   468                 && !('.' == ch))
       
   469         {
       
   470             ELOG(EJavaAppMngrPlugin, "Invalid attribute name");
       
   471             //User::Leave(KJavaParseInvalidAttributeName);
       
   472             User::Leave(KErrArgument);
       
   473         }
       
   474     }
       
   475 }