webengine/widgetinstaller/Src/WidgetConfigHandler.cpp
changeset 0 dd21522fd290
child 17 c8a366e56285
equal deleted inserted replaced
-1:000000000000 0:dd21522fd290
       
     1 /*
       
     2 * Copyright (c) 2006 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 the License "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:  Widget installer info file parsing.
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include <e32base.h>
       
    20 #include <f32file.h>
       
    21 #include <centralrepository.h>
       
    22 #include <libxml2_globals.h>
       
    23 #include <libxml2_parser.h>
       
    24 #include "WidgetConfigHandler.h"
       
    25 #include "SWInstWidgetUid.h"
       
    26 #include "WidgetInstallerInternalCRKeys.h"
       
    27 #include <charconv.h>
       
    28 #include <WidgetRegistryConstants.h>
       
    29 
       
    30 
       
    31 // DTD
       
    32 
       
    33 _LIT8( KNokiaId, "-//Nokia//DTD PLIST" );  // only the first part without version
       
    34 _LIT8( KAppleId, "-//Apple Computer//DTD PLIST" ); // only the first part without version
       
    35 
       
    36 // parsed elements in the DTD (XML element names are case sensitive)
       
    37 
       
    38 _LIT8( KKey,"key" );
       
    39 _LIT8( KString,"string" );
       
    40 _LIT8( KInt,"integer" );
       
    41 _LIT8( KTrue,"true" );
       
    42 _LIT8( KFalse,"false" );
       
    43 
       
    44 // properties from widget metadata file
       
    45 
       
    46 // NOTE: Comments "required" and "optional" apply to our requirements
       
    47 // for registering a widget.
       
    48 
       
    49 // NOTE: These property names are not XML element names, they are text
       
    50 // content for the <key> element, so we have made the match case
       
    51 // insensitive and capitalization here is just for readability.
       
    52 
       
    53 // Apple unique key names
       
    54 _LIT( KAppleBundleIdentifier,      "CFBundleIdentifier" );      // required
       
    55 _LIT( KAppleDisplayName,           "CFBundleDisplayName" );     // required
       
    56 _LIT( KAppleBundleVersion,         "CFBundleVersion" );         // optional
       
    57 _LIT( KAppleAllowFullAccess,       "AllowFullAccess" );         // optional
       
    58 // For Apple, AllowFullAccess is mapped to AllowNetworkAccess unless
       
    59 // AllowNetworkAccess appears too.
       
    60 
       
    61 // Nokia unique key names
       
    62 _LIT( KNokiaIdentifier,            "Identifier" );              // required
       
    63 _LIT( KNokiaDisplayName,           "DisplayName" );             // required
       
    64 _LIT( KNokiaVersion,               "Version" );                 // optional
       
    65 _LIT( KNokiaMiniViewEnabled,       "MiniViewEnabled" );         // optional
       
    66 _LIT( KBlanketPermGranted,          "BlanketPermissionGranted" );// optional 
       
    67 
       
    68 // Apple/Nokia shared key names
       
    69 _LIT( KMainHTML,                   "MainHTML" );                // required
       
    70 _LIT( KAllowNetworkAccess,         "AllowNetworkAccess" );      // optional
       
    71 _LIT( KHeight,                     "Height" );                  // optional
       
    72 _LIT( KWidth,                      "Width" );                   // optional
       
    73 
       
    74 
       
    75 enum TWidgetPropertyFlag
       
    76     {
       
    77     EMandatory = 1,
       
    78     EConfig = 2,
       
    79     EApple = 4,
       
    80     ENokia = 8,
       
    81     ESpecial = 16
       
    82     };
       
    83 
       
    84 #define CONFIG_MUST ( EMandatory | EConfig )
       
    85 #define CONFIG_APPLE_MUST ( EMandatory | EConfig | EApple )
       
    86 #define CONFIG_NOKIA_MUST ( EMandatory | EConfig | ENokia )
       
    87 
       
    88 #define CONFIG_MAY ( EConfig )
       
    89 #define CONFIG_APPLE_MAY ( EConfig | EApple )
       
    90 #define CONFIG_NOKIA_MAY ( EConfig | ENokia )
       
    91 
       
    92 #define CONFIG_APPLE_SPECIAL ( EConfig | EApple | ESpecial )
       
    93 
       
    94 // ============================================================================
       
    95 // Traverse to the next Node
       
    96 //
       
    97 // @param aNode: current node
       
    98 // @since 3.1
       
    99 // @return next node
       
   100 // ============================================================================
       
   101 //
       
   102 xmlNode* CWidgetConfigHandler::TraverseNextNode( xmlNode* n )
       
   103     {
       
   104     // depth first
       
   105     if ( n->children )
       
   106         {
       
   107         n = n->children;
       
   108         }
       
   109     else
       
   110         {
       
   111         // go up while no sibling
       
   112         while ( n->parent && !n->next )
       
   113             {
       
   114             n = n->parent;
       
   115             }
       
   116         // sibling?
       
   117         if ( n->next )
       
   118             {
       
   119             n = n->next;
       
   120             }
       
   121         else // done
       
   122             {
       
   123             n = NULL;
       
   124             }
       
   125         }
       
   126     return n;
       
   127     }
       
   128 
       
   129 // ============================================================================
       
   130 // CWidgetConfigHandler::NewL()
       
   131 // two-phase constructor
       
   132 //
       
   133 // @since 3.1
       
   134 // ============================================================================
       
   135 //
       
   136 CWidgetConfigHandler* CWidgetConfigHandler::NewL()
       
   137     {
       
   138     CWidgetConfigHandler *self = new (ELeave) CWidgetConfigHandler();
       
   139     CleanupStack::PushL( self );
       
   140     self->ConstructL();
       
   141     CleanupStack::Pop();
       
   142     return self;
       
   143     }
       
   144 
       
   145 // ============================================================================
       
   146 // CWidgetConfigHandler::CWidgetConfigHandler()
       
   147 // C++ constructor
       
   148 //
       
   149 // @since 3.1
       
   150 // ============================================================================
       
   151 //
       
   152 CWidgetConfigHandler::CWidgetConfigHandler()
       
   153     {
       
   154     iProperties[EPropertyDescriptionAppleBundleIdentifier].id = EBundleIdentifier;
       
   155     iProperties[EPropertyDescriptionAppleBundleIdentifier].name.Set( KAppleBundleIdentifier );
       
   156     iProperties[EPropertyDescriptionAppleBundleIdentifier].type = EWidgetPropTypeString;
       
   157     iProperties[EPropertyDescriptionAppleBundleIdentifier].flags = CONFIG_APPLE_MUST;
       
   158     //
       
   159     iProperties[EPropertyDescriptionAppleBundleDisplayName].id = EBundleDisplayName;
       
   160     iProperties[EPropertyDescriptionAppleBundleDisplayName].name.Set( KAppleDisplayName );
       
   161     iProperties[EPropertyDescriptionAppleBundleDisplayName].type = EWidgetPropTypeString;
       
   162     iProperties[EPropertyDescriptionAppleBundleDisplayName].flags = CONFIG_APPLE_MUST;
       
   163     //
       
   164     iProperties[EPropertyDescriptionAppleBundleVersion].id = EBundleVersion;
       
   165     iProperties[EPropertyDescriptionAppleBundleVersion].name.Set( KAppleBundleVersion );
       
   166     iProperties[EPropertyDescriptionAppleBundleVersion].type = EWidgetPropTypeString;
       
   167     iProperties[EPropertyDescriptionAppleBundleVersion].flags = CONFIG_APPLE_MAY;
       
   168     //
       
   169     iProperties[EPropertyDescriptionAppleAllowFullAccess].id = EWidgetPropertyIdInvalid;
       
   170     iProperties[EPropertyDescriptionAppleAllowFullAccess].name.Set( KAppleAllowFullAccess );
       
   171     iProperties[EPropertyDescriptionAppleAllowFullAccess].type = EWidgetPropTypeBool;
       
   172     iProperties[EPropertyDescriptionAppleAllowFullAccess].flags = CONFIG_APPLE_SPECIAL;
       
   173     //
       
   174     iProperties[EPropertyDescriptionNokiaIdentifier].id = EBundleIdentifier;
       
   175     iProperties[EPropertyDescriptionNokiaIdentifier].name.Set( KNokiaIdentifier );
       
   176     iProperties[EPropertyDescriptionNokiaIdentifier].type = EWidgetPropTypeString;
       
   177     iProperties[EPropertyDescriptionNokiaIdentifier].flags = CONFIG_NOKIA_MUST;
       
   178     //
       
   179     iProperties[EPropertyDescriptionNokiaDisplayName].id = EBundleDisplayName;
       
   180     iProperties[EPropertyDescriptionNokiaDisplayName].name.Set( KNokiaDisplayName );
       
   181     iProperties[EPropertyDescriptionNokiaDisplayName].type = EWidgetPropTypeString;
       
   182     iProperties[EPropertyDescriptionNokiaDisplayName].flags = CONFIG_NOKIA_MUST;
       
   183     //
       
   184     iProperties[EPropertyDescriptionNokiaVersion].id = EBundleVersion;
       
   185     iProperties[EPropertyDescriptionNokiaVersion].name.Set( KNokiaVersion );
       
   186     iProperties[EPropertyDescriptionNokiaVersion].type = EWidgetPropTypeString;
       
   187     iProperties[EPropertyDescriptionNokiaVersion].flags = CONFIG_NOKIA_MAY;
       
   188     //
       
   189     iProperties[EPropertyDescriptionMainHTML].id = EMainHTML;
       
   190     iProperties[EPropertyDescriptionMainHTML].name.Set( KMainHTML );
       
   191     iProperties[EPropertyDescriptionMainHTML].type = EWidgetPropTypeString;
       
   192     iProperties[EPropertyDescriptionMainHTML].flags = CONFIG_MUST;
       
   193     //
       
   194     iProperties[EPropertyDescriptionAllowNetworkAccess].id = EAllowNetworkAccess;
       
   195     iProperties[EPropertyDescriptionAllowNetworkAccess].name.Set( KAllowNetworkAccess );
       
   196     iProperties[EPropertyDescriptionAllowNetworkAccess].type = EWidgetPropTypeBool;
       
   197     iProperties[EPropertyDescriptionAllowNetworkAccess].flags = CONFIG_MAY;
       
   198     //
       
   199     iProperties[EPropertyDescriptionHeight].id = EHeight;
       
   200     iProperties[EPropertyDescriptionHeight].name.Set( KHeight );
       
   201     iProperties[EPropertyDescriptionHeight].type = EWidgetPropTypeInt;
       
   202     iProperties[EPropertyDescriptionHeight].flags = CONFIG_MAY;
       
   203     //
       
   204     iProperties[EPropertyDescriptionWidth].id = EWidth;
       
   205     iProperties[EPropertyDescriptionWidth].name.Set( KWidth );
       
   206     iProperties[EPropertyDescriptionWidth].type = EWidgetPropTypeInt;
       
   207     iProperties[EPropertyDescriptionWidth].flags = CONFIG_MAY;
       
   208 	//
       
   209 	iProperties[EPropertyDescriptionNokiaMiniViewEnable].id = EMiniViewEnable;
       
   210     iProperties[EPropertyDescriptionNokiaMiniViewEnable].name.Set( KNokiaMiniViewEnabled );
       
   211     iProperties[EPropertyDescriptionNokiaMiniViewEnable].type = EWidgetPropTypeBool;
       
   212     iProperties[EPropertyDescriptionNokiaMiniViewEnable].flags = CONFIG_NOKIA_MAY;
       
   213     //
       
   214     iProperties[EPropertyDescriptionNokiaPromptNeeded].id = EBlanketPermGranted;
       
   215     iProperties[EPropertyDescriptionNokiaPromptNeeded].name.Set( KBlanketPermGranted );
       
   216     iProperties[EPropertyDescriptionNokiaPromptNeeded].type = EWidgetPropTypeBool;
       
   217     iProperties[EPropertyDescriptionNokiaPromptNeeded].flags = CONFIG_NOKIA_MAY;
       
   218 
       
   219     }
       
   220 
       
   221 // ============================================================================
       
   222 // CWidgetConfigHandler::ConstructL()
       
   223 // C++ constructor
       
   224 //
       
   225 // @since 3.1
       
   226 // ============================================================================
       
   227 //
       
   228 void CWidgetConfigHandler::ConstructL()
       
   229     {
       
   230     }
       
   231 
       
   232 // ============================================================================
       
   233 // CWidgetConfigHandler::~CWidgetConfigHandler()
       
   234 // destructor
       
   235 //
       
   236 // @since 3.1
       
   237 // ============================================================================
       
   238 //
       
   239 CWidgetConfigHandler::~CWidgetConfigHandler()
       
   240     {
       
   241     }
       
   242 
       
   243 // ============================================================================
       
   244 // Get the key type out of the keyname
       
   245 //
       
   246 // @param aKeyName The name of the key: <key>KeyName</key>
       
   247 // @since 3.1
       
   248 // @return Key type.
       
   249 // ============================================================================
       
   250 //
       
   251 TWidgetPropertyId CWidgetConfigHandler::GetPropertyId(
       
   252     const TDesC& aKeyName,
       
   253     DtdType aDtdType,
       
   254     TWidgetPropertyDescriptionId& aPropertyDescriptionId )
       
   255     {
       
   256     aPropertyDescriptionId = EPropertyDescriptionIdInvalid;
       
   257     TInt i = 0;
       
   258     for (; i < EPropertyDescriptionIdCount; ++i )
       
   259         {
       
   260         if ( (EDtdTypeApple == aDtdType)
       
   261              && ( iProperties[i].flags & ENokia ) )
       
   262             {
       
   263             continue;
       
   264             }
       
   265         if ( (EDtdTypeNokia == aDtdType)
       
   266              && ( iProperties[i].flags & EApple ) )
       
   267             {
       
   268             continue;
       
   269             }
       
   270         // we use case insensitive match for property names
       
   271         if ( 0 == aKeyName.CompareF( iProperties[i].name ) )
       
   272             {
       
   273             aPropertyDescriptionId = static_cast<TWidgetPropertyDescriptionId>(i);
       
   274             if ( iProperties[i].flags & ESpecial )
       
   275                 {
       
   276                 return EWidgetPropertyIdInvalid;
       
   277                 }
       
   278             return iProperties[i].id;
       
   279             }
       
   280         }
       
   281     return EWidgetPropertyIdInvalid;
       
   282     }
       
   283 
       
   284 // ============================================================================
       
   285 // CWidgetConfigHandler::ToUnicodeL
       
   286 // Utility to bundle transcoding to unicode steps.
       
   287 //
       
   288 // @since 3.1
       
   289 // @param aEncoding input buffer encoding
       
   290 // @param aUnicodeSizeMultiplier how many bytes of input make one unicode char
       
   291 // @param aInBuf input data in encoding
       
   292 // @param aOutBuf malloc'ed output buf, caller takes ownership
       
   293 // @param aFileSession CCnvCharacterSetConverter requires it
       
   294 // ============================================================================
       
   295 //
       
   296 void CWidgetConfigHandler::ToUnicodeL( TInt aEncoding,
       
   297                                        TInt aUnicodeSizeMultiplier,
       
   298                                        TPtrC8 aInBuf, HBufC16** aOutBuf,
       
   299                                        RFs& aFileSession )
       
   300     {
       
   301     *aOutBuf = NULL;
       
   302 
       
   303     // outbuf sizing and alloction
       
   304     HBufC16* outBuf = HBufC16::NewLC(aUnicodeSizeMultiplier * aInBuf.Length());
       
   305     TPtr16 outPtr = outBuf->Des();
       
   306 
       
   307     // convert to unicode
       
   308     CCnvCharacterSetConverter* charConv = CCnvCharacterSetConverter::NewLC();
       
   309     charConv->PrepareToConvertToOrFromL( aEncoding, aFileSession );
       
   310     TInt state = CCnvCharacterSetConverter::KStateDefault;
       
   311     TInt rep = 0; // number of unconvertible characters
       
   312     TInt rIndx = 0; // index of first unconvertible character
       
   313     User::LeaveIfError(
       
   314         charConv->ConvertToUnicode( outPtr, aInBuf, state, rep, rIndx ) );
       
   315     CleanupStack::PopAndDestroy( charConv );
       
   316 
       
   317     CleanupStack::Pop(); // outBuf
       
   318     *aOutBuf = outBuf;
       
   319     }
       
   320 
       
   321 // ============================================================================
       
   322 // CWidgetConfigHandler::GetContentL
       
   323 // Utility to bundle extraction of XML text content
       
   324 //
       
   325 // @since 3.1
       
   326 // @param aEncoding input buffer encoding
       
   327 // @param aUnicodeSizeMultiplier how many bytes of input make one unicode char
       
   328 // @param aInBuf input data in encoding
       
   329 // @param aOutBuf malloc'ed output buf, caller takes ownership
       
   330 // @param aFileSession CCnvCharacterSetConverter requires it
       
   331 // ============================================================================
       
   332 //
       
   333 void CWidgetConfigHandler::GetContentL( RFs& aFileSession,
       
   334                                         xmlDocPtr aDoc,
       
   335                                         xmlNode* aNode,
       
   336                                         HBufC** aContent )
       
   337     {
       
   338     // xml uses UTF-8 for the internal representation
       
   339     xmlChar* xmlContent =
       
   340         xmlNodeListGetString( aDoc, aNode, 1 /* expand entities inline */);
       
   341     if ( NULL == xmlContent )
       
   342         {
       
   343         User::Leave( OOM_FLAG ? KErrNoMemory : KErrCorrupt );
       
   344         }
       
   345     // we must transcode UTF-8 to UCS-2 (historical
       
   346     // and now inaccurate name "unicode")
       
   347     CleanupStack::PushL( xmlContent );
       
   348     TPtrC8 content( xmlContent );
       
   349     ToUnicodeL( KCharacterSetIdentifierUtf8, 2,
       
   350                 content, aContent, aFileSession );
       
   351     CleanupStack::PopAndDestroy(); // xmlContent equivalent to xmlFree()
       
   352     if ( NULL == *aContent )
       
   353         {
       
   354         User::Leave( KErrCorrupt );
       
   355         }
       
   356     }
       
   357 
       
   358 // ============================================================================
       
   359 // CWidgetConfigHandler::ParseValidateBundleMetadataL
       
   360 // Parse the widget info file and create widget entry
       
   361 // check for required keys and values
       
   362 //
       
   363 // @since 3.1
       
   364 // @param aBuffer The buffer contains widget info file content.
       
   365 // @param aPropertyValues output filled with parsed values from buf
       
   366 // ============================================================================
       
   367 //
       
   368 void CWidgetConfigHandler::ParseValidateBundleMetadataL(
       
   369     TPtr8 aBuffer,
       
   370     RPointerArray<CWidgetPropertyValue>& aPropertyValues,
       
   371     RFs& aFileSession )
       
   372     {
       
   373     /*
       
   374       steps: 1. parse bundle metadata (ex., info.plist) and put
       
   375       results in aPropertyValues; 2. validate the metadata 2a. are
       
   376       required keys present? 2b. are values sane?
       
   377 
       
   378       leaves: 1. doesn't parse -> KErrCorrupt; 2. DTD not Nokia and
       
   379       cenrep key KWidgetInstallerStrictMode is 1 -> KErrNotSupported;
       
   380       3. key type bool but child element not true or false ->
       
   381       KErrCorrupt; 4. key type integer but child element not integer
       
   382       -> KErrCorrupt; 5. key type integer and child element integer
       
   383       but unparsable integer value -> KErrCorrupt; 6. key type string
       
   384       and child element not string -> KErrCorrupt; 7. key type string
       
   385       and child element string but does not contain text ->
       
   386       KErrCorrupt; 8. required keys not present -> KErrNotSupported
       
   387       9. key values not sane -> KErrNotSupported; 10. Heap allocation
       
   388       failure -> KErrNoMem
       
   389     */
       
   390 
       
   391     TInt nokiaOnly = 0;
       
   392     TRAP_IGNORE(
       
   393         CRepository* rep = CRepository::NewL( TUid::Uid( KSWInstWidgetUIUid ) );
       
   394         rep->Get( KWidgetInstallerStrictMode, nokiaOnly );
       
   395         delete rep; );
       
   396 
       
   397     // initialize the parser and check compiled code matches lib version
       
   398 
       
   399 #if 0
       
   400 // xmllib has a memory leak, so in order to detect mem leaks outside
       
   401 // of the xmllib, this code fills in the values that the parse step
       
   402 // would and returns.  you have to fill in the values for the specific
       
   403 // Info.plist you are installing
       
   404 
       
   405     _LIT( KIdentifier, "com.aws.widget.beta1" );
       
   406     _LIT( KName, "WeatherBug" );
       
   407     _LIT( KHtml, "index.html" );
       
   408     *(aPropertyValues[EBundleIdentifier]) = KIdentifier;
       
   409     *(aPropertyValues[EBundleDisplayName]) = KName();
       
   410     *(aPropertyValues[EMainHTML]) = KHtml;
       
   411     *(aPropertyValues[EAllowNetworkAccess]) = 1;
       
   412     *(aPropertyValues[ENokiaWidget]) = 0;
       
   413 
       
   414     // TODO: We decided to drop BundleName and just use
       
   415     // DisplayName but the registry code has errors in it and uses
       
   416     // BundleName when it should use DisplayName so as a workaround,
       
   417     // set BundleName to DisplayName.  Should eventually remove
       
   418     // BundleName from set of registry values.
       
   419     const TDesC& name = *(aPropertyValues[EBundleDisplayName]);
       
   420     *(aPropertyValues[EBundleName]) = name;
       
   421 
       
   422 #else
       
   423     LIBXML_TEST_VERSION
       
   424 
       
   425     xmlDocPtr doc; // resulting document tree
       
   426 
       
   427     doc = xmlReadMemory( (const char *)aBuffer.Ptr(), aBuffer.Length(),
       
   428                          NULL, // no base URL
       
   429                          NULL, // get encoding from doc
       
   430                          XML_PARSE_NOWARNING | XML_PARSE_NONET ); // options
       
   431     // parse failed check
       
   432     if ( !doc )
       
   433       {
       
   434       xmlCleanupParser();
       
   435       User::Leave( KErrCorrupt );
       
   436       }
       
   437 
       
   438     // determine doctype
       
   439     xmlNode* n;
       
   440     xmlDtd* dtd = NULL;
       
   441     for ( n = doc->children; n; n = n->next )
       
   442         {
       
   443         if ( XML_DTD_NODE == n->type )
       
   444             {
       
   445             dtd = (xmlDtd*)n;
       
   446             break;
       
   447             }
       
   448         }
       
   449     iDtdType = EDtdTypeUnknown;
       
   450     if ( dtd )
       
   451         {
       
   452         TPtrC8 id( dtd->ExternalID );
       
   453         if ( 0 == id.Left(KNokiaId().Length()).Compare(KNokiaId()) )
       
   454             {
       
   455             iDtdType = EDtdTypeNokia;
       
   456             }
       
   457         else if ( 0 == id.Left(KAppleId().Length()).Compare(KAppleId()) )
       
   458             {
       
   459             iDtdType = EDtdTypeApple;
       
   460             }
       
   461         }
       
   462 
       
   463     // save for registry so non-nokia installed on memory cards can be blocked
       
   464     // when inserted in nokia-only configured device
       
   465     *(aPropertyValues[ENokiaWidget]) = ( (EDtdTypeNokia == iDtdType) ? 1 : 0 );
       
   466 
       
   467     // handle cenrep nokia only setting
       
   468     if ( (EDtdTypeUnknown == iDtdType)
       
   469          || (nokiaOnly && ( EDtdTypeNokia != iDtdType )) )
       
   470         {
       
   471         User::Leave( KErrNotSupported );
       
   472         }
       
   473 
       
   474     xmlNode* rootElement = xmlDocGetRootElement( doc );
       
   475     TWidgetPropertyId valId( EWidgetPropertyIdInvalid );
       
   476     TWidgetPropertyDescriptionId propertyDescriptionId( EPropertyDescriptionIdInvalid );
       
   477 
       
   478     for ( n = rootElement; n; n = TraverseNextNode( n ) )
       
   479         {
       
   480         if ( XML_ELEMENT_NODE == n->type )
       
   481             {
       
   482             TPtrC8 element( n->name );
       
   483 
       
   484             if ( 0 == element.Compare( KKey() ) )
       
   485                 {
       
   486                 valId = EWidgetPropertyIdInvalid;
       
   487                 HBufC* keyName;
       
   488                 GetContentL( aFileSession, doc, n->children, &keyName );
       
   489                 CleanupStack::PushL( keyName );
       
   490                 TPtr name( keyName->Des() );
       
   491                 name.Trim(); // remove surrounding whitespace
       
   492                 valId = GetPropertyId( name, iDtdType, propertyDescriptionId );
       
   493                 CleanupStack::PopAndDestroy( keyName );
       
   494 
       
   495                 // reject duplicate keys based on value already being
       
   496                 // set (unset values have type unknown)
       
   497                 if ( ( EWidgetPropertyIdInvalid != valId )
       
   498                      && ( EWidgetPropTypeUnknown
       
   499                           != aPropertyValues[valId]->iType ) )
       
   500                     {
       
   501                     User::Leave( KErrCorrupt );
       
   502                     }
       
   503                 }
       
   504             else if ( EWidgetPropertyIdInvalid != valId )
       
   505                 {
       
   506                 switch ( iProperties[propertyDescriptionId].type )
       
   507                     {
       
   508                 case EWidgetPropTypeBool:
       
   509                     // map true to 1 and false to 0
       
   510                     if ( 0 == element.Compare( KTrue ) )
       
   511                         {
       
   512                         *(aPropertyValues[valId]) = 1;
       
   513                         }
       
   514                     else if ( 0 == element.Compare( KFalse ) )
       
   515                         {
       
   516                         *(aPropertyValues[valId]) = 0;
       
   517                         }
       
   518                     else
       
   519                         {
       
   520                         User::Leave( KErrCorrupt );
       
   521                         }
       
   522                     break;
       
   523                 case EWidgetPropTypeInt:
       
   524                     {
       
   525                     if ( 0 == element.Compare( KInt() ) )
       
   526                         {
       
   527                         HBufC* keyVal;
       
   528                         GetContentL( aFileSession, doc, n->children, &keyVal );
       
   529                         CleanupStack::PushL( keyVal );
       
   530                         TPtr value( keyVal->Des() );
       
   531                         value.Trim(); // remove surrounding whitespace
       
   532                         TLex tlex;
       
   533                         tlex.Assign( value );
       
   534                         TInt x;
       
   535                         TInt e = tlex.Val( x );
       
   536                         CleanupStack::PopAndDestroy( keyVal );
       
   537                         if ( !e && tlex.Eos() )
       
   538                             {
       
   539                             *(aPropertyValues[valId]) = x;
       
   540                             }
       
   541                         else
       
   542                             {
       
   543                             User::Leave( KErrCorrupt );
       
   544                             }
       
   545                         }
       
   546                     else
       
   547                         {
       
   548                         User::Leave( KErrCorrupt );
       
   549                         }
       
   550                     }
       
   551                     break;
       
   552                 case EWidgetPropTypeString:
       
   553                     if ( 0 == element.Compare( KString() ) )
       
   554                         {
       
   555                         HBufC* keyVal;
       
   556                         GetContentL( aFileSession, doc, n->children, &keyVal );
       
   557                         CleanupStack::PushL( keyVal );
       
   558                         TPtr value( keyVal->Des() );
       
   559                         value.Trim(); // remove surrounding whitespace
       
   560                         *(aPropertyValues[valId]) = value;
       
   561                         CleanupStack::PopAndDestroy( keyVal );
       
   562                         }
       
   563                     else
       
   564                         {
       
   565                         User::Leave( KErrCorrupt );
       
   566                         }
       
   567                     break;
       
   568                 default:
       
   569                     // ignore other things
       
   570                     break;
       
   571                     }
       
   572                 }
       
   573             else if ( EPropertyDescriptionIdInvalid != propertyDescriptionId )
       
   574                 {
       
   575                 if ( EPropertyDescriptionAppleAllowFullAccess == propertyDescriptionId )
       
   576                     {
       
   577                     // only set if AllowNetworkAccess is not yet set
       
   578                     if ( aPropertyValues[EAllowNetworkAccess]->iType != EWidgetPropTypeInt )
       
   579                         {
       
   580                         // map true to 1 and false to 0
       
   581                         if ( 0 == element.Compare( KTrue ) )
       
   582                             {
       
   583                             *(aPropertyValues[EAllowNetworkAccess]) = 1;
       
   584                             }
       
   585                         else if ( 0 == element.Compare( KFalse ) )
       
   586                             {
       
   587                             *(aPropertyValues[EAllowNetworkAccess]) = 0;
       
   588                             }
       
   589                         else
       
   590                             {
       
   591                             User::Leave( KErrCorrupt );
       
   592                             }
       
   593                         }
       
   594 					   // only set if MiniViewEnable is not yet set
       
   595                     else if ( aPropertyValues[EMiniViewEnable]->iType != EWidgetPropTypeInt )
       
   596                         {
       
   597                         // map true to 1 and false to 0
       
   598                         if ( 0 == element.Compare( KTrue ) )
       
   599                             {
       
   600                             *(aPropertyValues[EMiniViewEnable]) = 1;
       
   601                             }
       
   602                         else if ( 0 == element.Compare( KFalse ) )
       
   603                             {
       
   604                             *(aPropertyValues[EMiniViewEnable]) = 0;
       
   605                             }
       
   606                         else
       
   607                             {
       
   608                             User::Leave( KErrCorrupt );
       
   609                             }
       
   610                         }
       
   611                     }				                  
       
   612                 }
       
   613             }   // if n is element
       
   614         }   // for
       
   615 
       
   616     // validate: all required keys are present
       
   617     TInt i = 0;
       
   618     for ( ; i < EPropertyDescriptionIdCount; ++i )
       
   619         {
       
   620         if ( (iProperties[i].flags & EMandatory)
       
   621              && (iProperties[i].flags & EConfig)
       
   622              // a prop name maps to some value id
       
   623              && ((EWidgetPropertyIdInvalid != iProperties[i].id)
       
   624                  && (aPropertyValues[iProperties[i].id]->iType
       
   625                      != iProperties[i].type)) )
       
   626             {
       
   627             // if cause of mismatch is bool mapped to int, then continue check
       
   628             if ( (EWidgetPropTypeInt != aPropertyValues[iProperties[i].id]->iType)
       
   629                  || (EWidgetPropTypeBool != iProperties[i].type) )
       
   630                 {
       
   631                 User::Leave( KErrNotSupported );
       
   632                 }
       
   633             }
       
   634         }
       
   635 
       
   636     // TODO: We decided to drop BundleName and just use
       
   637     // DisplayName but the registry code has errors in it and uses
       
   638     // BundleName when it should use DisplayName so as a workaround,
       
   639     // set BundleName to DisplayName.  Should eventually remove
       
   640     // BundleName from set of registry values.
       
   641     const TDesC& name = *(aPropertyValues[EBundleDisplayName]);
       
   642     *(aPropertyValues[EBundleName]) = name;
       
   643 
       
   644     // validate values are sane
       
   645     ValidateL( aPropertyValues );
       
   646 
       
   647     xmlFreeDoc(doc);
       
   648     xmlCleanupParser();
       
   649 #endif
       
   650     }
       
   651 
       
   652 // ============================================================================
       
   653 // CWidgetConfigHandler::ValidateL
       
   654 // Check values.
       
   655 //
       
   656 // @since 3.1
       
   657 // @param aPropertyValues output filled with parsed values from buf
       
   658 // ============================================================================
       
   659 //
       
   660 void CWidgetConfigHandler::ValidateL(
       
   661     RPointerArray<CWidgetPropertyValue>& aPropertyValues )
       
   662     {
       
   663     // leaves with KErrCorrupt if any values are rejected
       
   664 
       
   665     // The limits and their justification:
       
   666     //
       
   667     // Strings are limited to KMaxFileName and must not be empty.
       
   668     //
       
   669     // For values like "Identifier" that will be used in filenames the
       
   670     // fundamental limit in Symbian is KMaxFileName (from e32const.h
       
   671     // and included by essentially all higher level e32*.h).  Since
       
   672     // these values will be concatenated with other directory
       
   673     // components, we might think to use a heuristic limit less than
       
   674     // KMaxFileName, but this introduces a needless arbitrary limit
       
   675     // and it will be cleaner to check length against KMaxFileName
       
   676     // after concatenation.  Checking here just means detecting a
       
   677     // limit violation earlier and maybe giving a better error
       
   678     // message.  Also, the KErrBadName error value from filesystem
       
   679     // operations will signal a pathname problem and MUST be checked.
       
   680     //
       
   681     // For strings like "DisplayName" that will be used in menus there
       
   682     // is no clear predefined value given that displays come in
       
   683     // various sizes and various fonts are used.  I'm going to impose
       
   684     // the same limit as for values used in filenames on the belief
       
   685     // that this is useful and not harmfull.
       
   686 
       
   687     // Also, check that values are not empty.
       
   688 
       
   689     TInt i = 0;
       
   690     for (; i < EPropertyDescriptionIdCount; ++i )
       
   691         {
       
   692         if ( EWidgetPropTypeString == aPropertyValues[i]->iType )
       
   693             {
       
   694             const TDesC& s = *(aPropertyValues[i]);
       
   695             if ( !s.Length() || ( s.Length() > KMaxFileName ) )
       
   696                 {
       
   697                 User::Leave( KErrCorrupt );
       
   698                 }
       
   699             }
       
   700         }
       
   701     }
       
   702 
       
   703 // ============================================================================
       
   704 // CWidgetConfigHandler::ParseInfoLocL()
       
   705 //
       
   706 // @since 3.1
       
   707 // ============================================================================
       
   708 //
       
   709 void CWidgetConfigHandler::ParseInfoLocL(
       
   710     TPtrC8 aBuffer,
       
   711     RFs& aFileSession,
       
   712     CWidgetPropertyValue& aBundleDisplayName )
       
   713     {
       
   714     // This logic is for localization of the display name.  The
       
   715     // display name appears in a localization file in the form:
       
   716     // DisplayName = "something"; (for Nokia DTD) or
       
   717     // CFBundleDisplayName = "something"; (for Apple DTD).
       
   718 
       
   719     // The encoding of the localization file is not given so it must
       
   720     // be automatically recognized.  The default is UTF-8 but if a
       
   721     // byte-order-mark is the first character then the BOM determines
       
   722     // the encoding.
       
   723 
       
   724     // get key name ID for display name depending on DTD
       
   725     TWidgetPropertyDescriptionId displayNameId = EPropertyDescriptionIdInvalid;
       
   726     if ( iDtdType == EDtdTypeNokia )
       
   727       {
       
   728         displayNameId = EPropertyDescriptionNokiaDisplayName;
       
   729       }
       
   730     else if ( iDtdType == EDtdTypeApple )
       
   731       {
       
   732         displayNameId = EPropertyDescriptionAppleBundleDisplayName;
       
   733       }
       
   734     if ( EPropertyDescriptionIdInvalid == displayNameId )
       
   735         {
       
   736         User::Leave( KErrCorrupt );
       
   737         }
       
   738 
       
   739     TPtrC8 inBuf;
       
   740 
       
   741     // default input encoding, no BOM
       
   742     TInt encoding = KCharacterSetIdentifierUtf8;
       
   743     TInt unicodeSizeMultiplier = 2; // a safe value which may waste some space
       
   744     inBuf.Set( aBuffer );
       
   745 
       
   746     // check for BOM, we only recognize UTF-16(BE/LE) and UTF-8,
       
   747     // remove BOM if found
       
   748     if ( aBuffer[0] == 0xFE && aBuffer[1] == 0xFF )
       
   749         {
       
   750         encoding = KCharacterSetIdentifierUnicodeBig;
       
   751         unicodeSizeMultiplier = 1;
       
   752         inBuf.Set( aBuffer.Right( aBuffer.Length() - 2 ) );
       
   753         }
       
   754     else if ( aBuffer[0] == 0xFF && aBuffer[1] == 0xFE )
       
   755         {
       
   756         encoding = KCharacterSetIdentifierUnicodeLittle;
       
   757         unicodeSizeMultiplier = 1;
       
   758         inBuf.Set( aBuffer.Right( aBuffer.Length() - 2 ) );
       
   759         }
       
   760     else if ( aBuffer[0] == 0xEF && aBuffer[1] == 0xBB && aBuffer[2] == 0xBF )
       
   761         {
       
   762         encoding = KCharacterSetIdentifierUtf8;
       
   763         unicodeSizeMultiplier = 2; // a safe value which may waste some space
       
   764         inBuf.Set( aBuffer.Right( aBuffer.Length() - 3 ) );
       
   765         }
       
   766 
       
   767     // convert to unicode
       
   768     HBufC16* outBuf;
       
   769     ToUnicodeL( encoding, unicodeSizeMultiplier,
       
   770                 inBuf, &outBuf, aFileSession );
       
   771     CleanupStack::PushL( outBuf );
       
   772     TPtr16 outPtr = outBuf->Des();
       
   773     // convert the display name key name to unicode since it is just
       
   774     // _LIT() and so might be 8 bit and we want 16 bit "unicode"
       
   775     TPtrC keyName = iProperties[displayNameId].name;
       
   776     HBufC16* keyNameUnicode = HBufC16::NewLC( keyName.Length() );
       
   777     TPtr16 keyNameUnicodePtr( keyNameUnicode->Des() );
       
   778     keyNameUnicodePtr.Copy( keyName );
       
   779 
       
   780     // parse the display name
       
   781     outPtr.TrimLeft(); // remove leading whitespace
       
   782     TInt pos = outPtr.Find( keyNameUnicodePtr );
       
   783     if ( (KErrNotFound == pos) || (0 != pos) )
       
   784         {
       
   785         User::Leave( KErrCorrupt );
       
   786         }
       
   787 
       
   788     // rest contains buffer after the DisplayName,
       
   789     // i.e. = "some localized text"
       
   790     TPtr16 rest =
       
   791         outPtr.RightTPtr(
       
   792             outPtr.Length()
       
   793             - pos
       
   794             - keyNameUnicode->Length() );
       
   795     const TUint16* data = rest.Ptr();
       
   796     TBool hasEqual = EFalse;    // already pass the = sign?
       
   797 
       
   798     // start pos and end pos of localized displayname
       
   799     TUint8 start = 0;
       
   800     TUint8 end = 0;
       
   801     for ( TInt i = 0; i < rest.Length(); i++ )
       
   802         {
       
   803         if ( data[i] == ' ' || data[i] == '\t' )
       
   804             {
       
   805             continue;
       
   806             }
       
   807         if ( data[i] == '=' )
       
   808             {
       
   809             hasEqual = ETrue;
       
   810             continue;
       
   811             }
       
   812         if ( data[i] == '\"' )
       
   813             {
       
   814             if ( !start )
       
   815                 {
       
   816                 start = i + 1;
       
   817                 continue;
       
   818                 }
       
   819             // else already inquote, so this is close quote
       
   820             end = i;
       
   821             break;
       
   822             }
       
   823         if ( !hasEqual || !start )
       
   824             {
       
   825             User::Leave( KErrCorrupt );
       
   826             }
       
   827         }
       
   828 
       
   829     if ( end <= start )
       
   830         {
       
   831         User::Leave( KErrCorrupt );
       
   832         }
       
   833     TInt left = pos + keyNameUnicode->Length() + start;
       
   834     aBundleDisplayName = outPtr.MidTPtr( left, end - start);
       
   835     CleanupStack::PopAndDestroy( 2 ); // outBuf, keyNameUnicode
       
   836     }
       
   837 
       
   838 // End of File