--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/webengine/widgetinstaller/Src/WidgetConfigHandler.cpp Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,838 @@
+/*
+* Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: Widget installer info file parsing.
+*
+*/
+
+
+#include <e32base.h>
+#include <f32file.h>
+#include <centralrepository.h>
+#include <libxml2_globals.h>
+#include <libxml2_parser.h>
+#include "WidgetConfigHandler.h"
+#include "SWInstWidgetUid.h"
+#include "WidgetInstallerInternalCRKeys.h"
+#include <charconv.h>
+#include <WidgetRegistryConstants.h>
+
+
+// DTD
+
+_LIT8( KNokiaId, "-//Nokia//DTD PLIST" ); // only the first part without version
+_LIT8( KAppleId, "-//Apple Computer//DTD PLIST" ); // only the first part without version
+
+// parsed elements in the DTD (XML element names are case sensitive)
+
+_LIT8( KKey,"key" );
+_LIT8( KString,"string" );
+_LIT8( KInt,"integer" );
+_LIT8( KTrue,"true" );
+_LIT8( KFalse,"false" );
+
+// properties from widget metadata file
+
+// NOTE: Comments "required" and "optional" apply to our requirements
+// for registering a widget.
+
+// NOTE: These property names are not XML element names, they are text
+// content for the <key> element, so we have made the match case
+// insensitive and capitalization here is just for readability.
+
+// Apple unique key names
+_LIT( KAppleBundleIdentifier, "CFBundleIdentifier" ); // required
+_LIT( KAppleDisplayName, "CFBundleDisplayName" ); // required
+_LIT( KAppleBundleVersion, "CFBundleVersion" ); // optional
+_LIT( KAppleAllowFullAccess, "AllowFullAccess" ); // optional
+// For Apple, AllowFullAccess is mapped to AllowNetworkAccess unless
+// AllowNetworkAccess appears too.
+
+// Nokia unique key names
+_LIT( KNokiaIdentifier, "Identifier" ); // required
+_LIT( KNokiaDisplayName, "DisplayName" ); // required
+_LIT( KNokiaVersion, "Version" ); // optional
+_LIT( KNokiaMiniViewEnabled, "MiniViewEnabled" ); // optional
+_LIT( KBlanketPermGranted, "BlanketPermissionGranted" );// optional
+
+// Apple/Nokia shared key names
+_LIT( KMainHTML, "MainHTML" ); // required
+_LIT( KAllowNetworkAccess, "AllowNetworkAccess" ); // optional
+_LIT( KHeight, "Height" ); // optional
+_LIT( KWidth, "Width" ); // optional
+
+
+enum TWidgetPropertyFlag
+ {
+ EMandatory = 1,
+ EConfig = 2,
+ EApple = 4,
+ ENokia = 8,
+ ESpecial = 16
+ };
+
+#define CONFIG_MUST ( EMandatory | EConfig )
+#define CONFIG_APPLE_MUST ( EMandatory | EConfig | EApple )
+#define CONFIG_NOKIA_MUST ( EMandatory | EConfig | ENokia )
+
+#define CONFIG_MAY ( EConfig )
+#define CONFIG_APPLE_MAY ( EConfig | EApple )
+#define CONFIG_NOKIA_MAY ( EConfig | ENokia )
+
+#define CONFIG_APPLE_SPECIAL ( EConfig | EApple | ESpecial )
+
+// ============================================================================
+// Traverse to the next Node
+//
+// @param aNode: current node
+// @since 3.1
+// @return next node
+// ============================================================================
+//
+xmlNode* CWidgetConfigHandler::TraverseNextNode( xmlNode* n )
+ {
+ // depth first
+ if ( n->children )
+ {
+ n = n->children;
+ }
+ else
+ {
+ // go up while no sibling
+ while ( n->parent && !n->next )
+ {
+ n = n->parent;
+ }
+ // sibling?
+ if ( n->next )
+ {
+ n = n->next;
+ }
+ else // done
+ {
+ n = NULL;
+ }
+ }
+ return n;
+ }
+
+// ============================================================================
+// CWidgetConfigHandler::NewL()
+// two-phase constructor
+//
+// @since 3.1
+// ============================================================================
+//
+CWidgetConfigHandler* CWidgetConfigHandler::NewL()
+ {
+ CWidgetConfigHandler *self = new (ELeave) CWidgetConfigHandler();
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop();
+ return self;
+ }
+
+// ============================================================================
+// CWidgetConfigHandler::CWidgetConfigHandler()
+// C++ constructor
+//
+// @since 3.1
+// ============================================================================
+//
+CWidgetConfigHandler::CWidgetConfigHandler()
+ {
+ iProperties[EPropertyDescriptionAppleBundleIdentifier].id = EBundleIdentifier;
+ iProperties[EPropertyDescriptionAppleBundleIdentifier].name.Set( KAppleBundleIdentifier );
+ iProperties[EPropertyDescriptionAppleBundleIdentifier].type = EWidgetPropTypeString;
+ iProperties[EPropertyDescriptionAppleBundleIdentifier].flags = CONFIG_APPLE_MUST;
+ //
+ iProperties[EPropertyDescriptionAppleBundleDisplayName].id = EBundleDisplayName;
+ iProperties[EPropertyDescriptionAppleBundleDisplayName].name.Set( KAppleDisplayName );
+ iProperties[EPropertyDescriptionAppleBundleDisplayName].type = EWidgetPropTypeString;
+ iProperties[EPropertyDescriptionAppleBundleDisplayName].flags = CONFIG_APPLE_MUST;
+ //
+ iProperties[EPropertyDescriptionAppleBundleVersion].id = EBundleVersion;
+ iProperties[EPropertyDescriptionAppleBundleVersion].name.Set( KAppleBundleVersion );
+ iProperties[EPropertyDescriptionAppleBundleVersion].type = EWidgetPropTypeString;
+ iProperties[EPropertyDescriptionAppleBundleVersion].flags = CONFIG_APPLE_MAY;
+ //
+ iProperties[EPropertyDescriptionAppleAllowFullAccess].id = EWidgetPropertyIdInvalid;
+ iProperties[EPropertyDescriptionAppleAllowFullAccess].name.Set( KAppleAllowFullAccess );
+ iProperties[EPropertyDescriptionAppleAllowFullAccess].type = EWidgetPropTypeBool;
+ iProperties[EPropertyDescriptionAppleAllowFullAccess].flags = CONFIG_APPLE_SPECIAL;
+ //
+ iProperties[EPropertyDescriptionNokiaIdentifier].id = EBundleIdentifier;
+ iProperties[EPropertyDescriptionNokiaIdentifier].name.Set( KNokiaIdentifier );
+ iProperties[EPropertyDescriptionNokiaIdentifier].type = EWidgetPropTypeString;
+ iProperties[EPropertyDescriptionNokiaIdentifier].flags = CONFIG_NOKIA_MUST;
+ //
+ iProperties[EPropertyDescriptionNokiaDisplayName].id = EBundleDisplayName;
+ iProperties[EPropertyDescriptionNokiaDisplayName].name.Set( KNokiaDisplayName );
+ iProperties[EPropertyDescriptionNokiaDisplayName].type = EWidgetPropTypeString;
+ iProperties[EPropertyDescriptionNokiaDisplayName].flags = CONFIG_NOKIA_MUST;
+ //
+ iProperties[EPropertyDescriptionNokiaVersion].id = EBundleVersion;
+ iProperties[EPropertyDescriptionNokiaVersion].name.Set( KNokiaVersion );
+ iProperties[EPropertyDescriptionNokiaVersion].type = EWidgetPropTypeString;
+ iProperties[EPropertyDescriptionNokiaVersion].flags = CONFIG_NOKIA_MAY;
+ //
+ iProperties[EPropertyDescriptionMainHTML].id = EMainHTML;
+ iProperties[EPropertyDescriptionMainHTML].name.Set( KMainHTML );
+ iProperties[EPropertyDescriptionMainHTML].type = EWidgetPropTypeString;
+ iProperties[EPropertyDescriptionMainHTML].flags = CONFIG_MUST;
+ //
+ iProperties[EPropertyDescriptionAllowNetworkAccess].id = EAllowNetworkAccess;
+ iProperties[EPropertyDescriptionAllowNetworkAccess].name.Set( KAllowNetworkAccess );
+ iProperties[EPropertyDescriptionAllowNetworkAccess].type = EWidgetPropTypeBool;
+ iProperties[EPropertyDescriptionAllowNetworkAccess].flags = CONFIG_MAY;
+ //
+ iProperties[EPropertyDescriptionHeight].id = EHeight;
+ iProperties[EPropertyDescriptionHeight].name.Set( KHeight );
+ iProperties[EPropertyDescriptionHeight].type = EWidgetPropTypeInt;
+ iProperties[EPropertyDescriptionHeight].flags = CONFIG_MAY;
+ //
+ iProperties[EPropertyDescriptionWidth].id = EWidth;
+ iProperties[EPropertyDescriptionWidth].name.Set( KWidth );
+ iProperties[EPropertyDescriptionWidth].type = EWidgetPropTypeInt;
+ iProperties[EPropertyDescriptionWidth].flags = CONFIG_MAY;
+ //
+ iProperties[EPropertyDescriptionNokiaMiniViewEnable].id = EMiniViewEnable;
+ iProperties[EPropertyDescriptionNokiaMiniViewEnable].name.Set( KNokiaMiniViewEnabled );
+ iProperties[EPropertyDescriptionNokiaMiniViewEnable].type = EWidgetPropTypeBool;
+ iProperties[EPropertyDescriptionNokiaMiniViewEnable].flags = CONFIG_NOKIA_MAY;
+ //
+ iProperties[EPropertyDescriptionNokiaPromptNeeded].id = EBlanketPermGranted;
+ iProperties[EPropertyDescriptionNokiaPromptNeeded].name.Set( KBlanketPermGranted );
+ iProperties[EPropertyDescriptionNokiaPromptNeeded].type = EWidgetPropTypeBool;
+ iProperties[EPropertyDescriptionNokiaPromptNeeded].flags = CONFIG_NOKIA_MAY;
+
+ }
+
+// ============================================================================
+// CWidgetConfigHandler::ConstructL()
+// C++ constructor
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetConfigHandler::ConstructL()
+ {
+ }
+
+// ============================================================================
+// CWidgetConfigHandler::~CWidgetConfigHandler()
+// destructor
+//
+// @since 3.1
+// ============================================================================
+//
+CWidgetConfigHandler::~CWidgetConfigHandler()
+ {
+ }
+
+// ============================================================================
+// Get the key type out of the keyname
+//
+// @param aKeyName The name of the key: <key>KeyName</key>
+// @since 3.1
+// @return Key type.
+// ============================================================================
+//
+TWidgetPropertyId CWidgetConfigHandler::GetPropertyId(
+ const TDesC& aKeyName,
+ DtdType aDtdType,
+ TWidgetPropertyDescriptionId& aPropertyDescriptionId )
+ {
+ aPropertyDescriptionId = EPropertyDescriptionIdInvalid;
+ TInt i = 0;
+ for (; i < EPropertyDescriptionIdCount; ++i )
+ {
+ if ( (EDtdTypeApple == aDtdType)
+ && ( iProperties[i].flags & ENokia ) )
+ {
+ continue;
+ }
+ if ( (EDtdTypeNokia == aDtdType)
+ && ( iProperties[i].flags & EApple ) )
+ {
+ continue;
+ }
+ // we use case insensitive match for property names
+ if ( 0 == aKeyName.CompareF( iProperties[i].name ) )
+ {
+ aPropertyDescriptionId = static_cast<TWidgetPropertyDescriptionId>(i);
+ if ( iProperties[i].flags & ESpecial )
+ {
+ return EWidgetPropertyIdInvalid;
+ }
+ return iProperties[i].id;
+ }
+ }
+ return EWidgetPropertyIdInvalid;
+ }
+
+// ============================================================================
+// CWidgetConfigHandler::ToUnicodeL
+// Utility to bundle transcoding to unicode steps.
+//
+// @since 3.1
+// @param aEncoding input buffer encoding
+// @param aUnicodeSizeMultiplier how many bytes of input make one unicode char
+// @param aInBuf input data in encoding
+// @param aOutBuf malloc'ed output buf, caller takes ownership
+// @param aFileSession CCnvCharacterSetConverter requires it
+// ============================================================================
+//
+void CWidgetConfigHandler::ToUnicodeL( TInt aEncoding,
+ TInt aUnicodeSizeMultiplier,
+ TPtrC8 aInBuf, HBufC16** aOutBuf,
+ RFs& aFileSession )
+ {
+ *aOutBuf = NULL;
+
+ // outbuf sizing and alloction
+ HBufC16* outBuf = HBufC16::NewLC(aUnicodeSizeMultiplier * aInBuf.Length());
+ TPtr16 outPtr = outBuf->Des();
+
+ // convert to unicode
+ CCnvCharacterSetConverter* charConv = CCnvCharacterSetConverter::NewLC();
+ charConv->PrepareToConvertToOrFromL( aEncoding, aFileSession );
+ TInt state = CCnvCharacterSetConverter::KStateDefault;
+ TInt rep = 0; // number of unconvertible characters
+ TInt rIndx = 0; // index of first unconvertible character
+ User::LeaveIfError(
+ charConv->ConvertToUnicode( outPtr, aInBuf, state, rep, rIndx ) );
+ CleanupStack::PopAndDestroy( charConv );
+
+ CleanupStack::Pop(); // outBuf
+ *aOutBuf = outBuf;
+ }
+
+// ============================================================================
+// CWidgetConfigHandler::GetContentL
+// Utility to bundle extraction of XML text content
+//
+// @since 3.1
+// @param aEncoding input buffer encoding
+// @param aUnicodeSizeMultiplier how many bytes of input make one unicode char
+// @param aInBuf input data in encoding
+// @param aOutBuf malloc'ed output buf, caller takes ownership
+// @param aFileSession CCnvCharacterSetConverter requires it
+// ============================================================================
+//
+void CWidgetConfigHandler::GetContentL( RFs& aFileSession,
+ xmlDocPtr aDoc,
+ xmlNode* aNode,
+ HBufC** aContent )
+ {
+ // xml uses UTF-8 for the internal representation
+ xmlChar* xmlContent =
+ xmlNodeListGetString( aDoc, aNode, 1 /* expand entities inline */);
+ if ( NULL == xmlContent )
+ {
+ User::Leave( OOM_FLAG ? KErrNoMemory : KErrCorrupt );
+ }
+ // we must transcode UTF-8 to UCS-2 (historical
+ // and now inaccurate name "unicode")
+ CleanupStack::PushL( xmlContent );
+ TPtrC8 content( xmlContent );
+ ToUnicodeL( KCharacterSetIdentifierUtf8, 2,
+ content, aContent, aFileSession );
+ CleanupStack::PopAndDestroy(); // xmlContent equivalent to xmlFree()
+ if ( NULL == *aContent )
+ {
+ User::Leave( KErrCorrupt );
+ }
+ }
+
+// ============================================================================
+// CWidgetConfigHandler::ParseValidateBundleMetadataL
+// Parse the widget info file and create widget entry
+// check for required keys and values
+//
+// @since 3.1
+// @param aBuffer The buffer contains widget info file content.
+// @param aPropertyValues output filled with parsed values from buf
+// ============================================================================
+//
+void CWidgetConfigHandler::ParseValidateBundleMetadataL(
+ TPtr8 aBuffer,
+ RPointerArray<CWidgetPropertyValue>& aPropertyValues,
+ RFs& aFileSession )
+ {
+ /*
+ steps: 1. parse bundle metadata (ex., info.plist) and put
+ results in aPropertyValues; 2. validate the metadata 2a. are
+ required keys present? 2b. are values sane?
+
+ leaves: 1. doesn't parse -> KErrCorrupt; 2. DTD not Nokia and
+ cenrep key KWidgetInstallerStrictMode is 1 -> KErrNotSupported;
+ 3. key type bool but child element not true or false ->
+ KErrCorrupt; 4. key type integer but child element not integer
+ -> KErrCorrupt; 5. key type integer and child element integer
+ but unparsable integer value -> KErrCorrupt; 6. key type string
+ and child element not string -> KErrCorrupt; 7. key type string
+ and child element string but does not contain text ->
+ KErrCorrupt; 8. required keys not present -> KErrNotSupported
+ 9. key values not sane -> KErrNotSupported; 10. Heap allocation
+ failure -> KErrNoMem
+ */
+
+ TInt nokiaOnly = 0;
+ TRAP_IGNORE(
+ CRepository* rep = CRepository::NewL( TUid::Uid( KSWInstWidgetUIUid ) );
+ rep->Get( KWidgetInstallerStrictMode, nokiaOnly );
+ delete rep; );
+
+ // initialize the parser and check compiled code matches lib version
+
+#if 0
+// xmllib has a memory leak, so in order to detect mem leaks outside
+// of the xmllib, this code fills in the values that the parse step
+// would and returns. you have to fill in the values for the specific
+// Info.plist you are installing
+
+ _LIT( KIdentifier, "com.aws.widget.beta1" );
+ _LIT( KName, "WeatherBug" );
+ _LIT( KHtml, "index.html" );
+ *(aPropertyValues[EBundleIdentifier]) = KIdentifier;
+ *(aPropertyValues[EBundleDisplayName]) = KName();
+ *(aPropertyValues[EMainHTML]) = KHtml;
+ *(aPropertyValues[EAllowNetworkAccess]) = 1;
+ *(aPropertyValues[ENokiaWidget]) = 0;
+
+ // TODO: We decided to drop BundleName and just use
+ // DisplayName but the registry code has errors in it and uses
+ // BundleName when it should use DisplayName so as a workaround,
+ // set BundleName to DisplayName. Should eventually remove
+ // BundleName from set of registry values.
+ const TDesC& name = *(aPropertyValues[EBundleDisplayName]);
+ *(aPropertyValues[EBundleName]) = name;
+
+#else
+ LIBXML_TEST_VERSION
+
+ xmlDocPtr doc; // resulting document tree
+
+ doc = xmlReadMemory( (const char *)aBuffer.Ptr(), aBuffer.Length(),
+ NULL, // no base URL
+ NULL, // get encoding from doc
+ XML_PARSE_NOWARNING | XML_PARSE_NONET ); // options
+ // parse failed check
+ if ( !doc )
+ {
+ xmlCleanupParser();
+ User::Leave( KErrCorrupt );
+ }
+
+ // determine doctype
+ xmlNode* n;
+ xmlDtd* dtd = NULL;
+ for ( n = doc->children; n; n = n->next )
+ {
+ if ( XML_DTD_NODE == n->type )
+ {
+ dtd = (xmlDtd*)n;
+ break;
+ }
+ }
+ iDtdType = EDtdTypeUnknown;
+ if ( dtd )
+ {
+ TPtrC8 id( dtd->ExternalID );
+ if ( 0 == id.Left(KNokiaId().Length()).Compare(KNokiaId()) )
+ {
+ iDtdType = EDtdTypeNokia;
+ }
+ else if ( 0 == id.Left(KAppleId().Length()).Compare(KAppleId()) )
+ {
+ iDtdType = EDtdTypeApple;
+ }
+ }
+
+ // save for registry so non-nokia installed on memory cards can be blocked
+ // when inserted in nokia-only configured device
+ *(aPropertyValues[ENokiaWidget]) = ( (EDtdTypeNokia == iDtdType) ? 1 : 0 );
+
+ // handle cenrep nokia only setting
+ if ( (EDtdTypeUnknown == iDtdType)
+ || (nokiaOnly && ( EDtdTypeNokia != iDtdType )) )
+ {
+ User::Leave( KErrNotSupported );
+ }
+
+ xmlNode* rootElement = xmlDocGetRootElement( doc );
+ TWidgetPropertyId valId( EWidgetPropertyIdInvalid );
+ TWidgetPropertyDescriptionId propertyDescriptionId( EPropertyDescriptionIdInvalid );
+
+ for ( n = rootElement; n; n = TraverseNextNode( n ) )
+ {
+ if ( XML_ELEMENT_NODE == n->type )
+ {
+ TPtrC8 element( n->name );
+
+ if ( 0 == element.Compare( KKey() ) )
+ {
+ valId = EWidgetPropertyIdInvalid;
+ HBufC* keyName;
+ GetContentL( aFileSession, doc, n->children, &keyName );
+ CleanupStack::PushL( keyName );
+ TPtr name( keyName->Des() );
+ name.Trim(); // remove surrounding whitespace
+ valId = GetPropertyId( name, iDtdType, propertyDescriptionId );
+ CleanupStack::PopAndDestroy( keyName );
+
+ // reject duplicate keys based on value already being
+ // set (unset values have type unknown)
+ if ( ( EWidgetPropertyIdInvalid != valId )
+ && ( EWidgetPropTypeUnknown
+ != aPropertyValues[valId]->iType ) )
+ {
+ User::Leave( KErrCorrupt );
+ }
+ }
+ else if ( EWidgetPropertyIdInvalid != valId )
+ {
+ switch ( iProperties[propertyDescriptionId].type )
+ {
+ case EWidgetPropTypeBool:
+ // map true to 1 and false to 0
+ if ( 0 == element.Compare( KTrue ) )
+ {
+ *(aPropertyValues[valId]) = 1;
+ }
+ else if ( 0 == element.Compare( KFalse ) )
+ {
+ *(aPropertyValues[valId]) = 0;
+ }
+ else
+ {
+ User::Leave( KErrCorrupt );
+ }
+ break;
+ case EWidgetPropTypeInt:
+ {
+ if ( 0 == element.Compare( KInt() ) )
+ {
+ HBufC* keyVal;
+ GetContentL( aFileSession, doc, n->children, &keyVal );
+ CleanupStack::PushL( keyVal );
+ TPtr value( keyVal->Des() );
+ value.Trim(); // remove surrounding whitespace
+ TLex tlex;
+ tlex.Assign( value );
+ TInt x;
+ TInt e = tlex.Val( x );
+ CleanupStack::PopAndDestroy( keyVal );
+ if ( !e && tlex.Eos() )
+ {
+ *(aPropertyValues[valId]) = x;
+ }
+ else
+ {
+ User::Leave( KErrCorrupt );
+ }
+ }
+ else
+ {
+ User::Leave( KErrCorrupt );
+ }
+ }
+ break;
+ case EWidgetPropTypeString:
+ if ( 0 == element.Compare( KString() ) )
+ {
+ HBufC* keyVal;
+ GetContentL( aFileSession, doc, n->children, &keyVal );
+ CleanupStack::PushL( keyVal );
+ TPtr value( keyVal->Des() );
+ value.Trim(); // remove surrounding whitespace
+ *(aPropertyValues[valId]) = value;
+ CleanupStack::PopAndDestroy( keyVal );
+ }
+ else
+ {
+ User::Leave( KErrCorrupt );
+ }
+ break;
+ default:
+ // ignore other things
+ break;
+ }
+ }
+ else if ( EPropertyDescriptionIdInvalid != propertyDescriptionId )
+ {
+ if ( EPropertyDescriptionAppleAllowFullAccess == propertyDescriptionId )
+ {
+ // only set if AllowNetworkAccess is not yet set
+ if ( aPropertyValues[EAllowNetworkAccess]->iType != EWidgetPropTypeInt )
+ {
+ // map true to 1 and false to 0
+ if ( 0 == element.Compare( KTrue ) )
+ {
+ *(aPropertyValues[EAllowNetworkAccess]) = 1;
+ }
+ else if ( 0 == element.Compare( KFalse ) )
+ {
+ *(aPropertyValues[EAllowNetworkAccess]) = 0;
+ }
+ else
+ {
+ User::Leave( KErrCorrupt );
+ }
+ }
+ // only set if MiniViewEnable is not yet set
+ else if ( aPropertyValues[EMiniViewEnable]->iType != EWidgetPropTypeInt )
+ {
+ // map true to 1 and false to 0
+ if ( 0 == element.Compare( KTrue ) )
+ {
+ *(aPropertyValues[EMiniViewEnable]) = 1;
+ }
+ else if ( 0 == element.Compare( KFalse ) )
+ {
+ *(aPropertyValues[EMiniViewEnable]) = 0;
+ }
+ else
+ {
+ User::Leave( KErrCorrupt );
+ }
+ }
+ }
+ }
+ } // if n is element
+ } // for
+
+ // validate: all required keys are present
+ TInt i = 0;
+ for ( ; i < EPropertyDescriptionIdCount; ++i )
+ {
+ if ( (iProperties[i].flags & EMandatory)
+ && (iProperties[i].flags & EConfig)
+ // a prop name maps to some value id
+ && ((EWidgetPropertyIdInvalid != iProperties[i].id)
+ && (aPropertyValues[iProperties[i].id]->iType
+ != iProperties[i].type)) )
+ {
+ // if cause of mismatch is bool mapped to int, then continue check
+ if ( (EWidgetPropTypeInt != aPropertyValues[iProperties[i].id]->iType)
+ || (EWidgetPropTypeBool != iProperties[i].type) )
+ {
+ User::Leave( KErrNotSupported );
+ }
+ }
+ }
+
+ // TODO: We decided to drop BundleName and just use
+ // DisplayName but the registry code has errors in it and uses
+ // BundleName when it should use DisplayName so as a workaround,
+ // set BundleName to DisplayName. Should eventually remove
+ // BundleName from set of registry values.
+ const TDesC& name = *(aPropertyValues[EBundleDisplayName]);
+ *(aPropertyValues[EBundleName]) = name;
+
+ // validate values are sane
+ ValidateL( aPropertyValues );
+
+ xmlFreeDoc(doc);
+ xmlCleanupParser();
+#endif
+ }
+
+// ============================================================================
+// CWidgetConfigHandler::ValidateL
+// Check values.
+//
+// @since 3.1
+// @param aPropertyValues output filled with parsed values from buf
+// ============================================================================
+//
+void CWidgetConfigHandler::ValidateL(
+ RPointerArray<CWidgetPropertyValue>& aPropertyValues )
+ {
+ // leaves with KErrCorrupt if any values are rejected
+
+ // The limits and their justification:
+ //
+ // Strings are limited to KMaxFileName and must not be empty.
+ //
+ // For values like "Identifier" that will be used in filenames the
+ // fundamental limit in Symbian is KMaxFileName (from e32const.h
+ // and included by essentially all higher level e32*.h). Since
+ // these values will be concatenated with other directory
+ // components, we might think to use a heuristic limit less than
+ // KMaxFileName, but this introduces a needless arbitrary limit
+ // and it will be cleaner to check length against KMaxFileName
+ // after concatenation. Checking here just means detecting a
+ // limit violation earlier and maybe giving a better error
+ // message. Also, the KErrBadName error value from filesystem
+ // operations will signal a pathname problem and MUST be checked.
+ //
+ // For strings like "DisplayName" that will be used in menus there
+ // is no clear predefined value given that displays come in
+ // various sizes and various fonts are used. I'm going to impose
+ // the same limit as for values used in filenames on the belief
+ // that this is useful and not harmfull.
+
+ // Also, check that values are not empty.
+
+ TInt i = 0;
+ for (; i < EPropertyDescriptionIdCount; ++i )
+ {
+ if ( EWidgetPropTypeString == aPropertyValues[i]->iType )
+ {
+ const TDesC& s = *(aPropertyValues[i]);
+ if ( !s.Length() || ( s.Length() > KMaxFileName ) )
+ {
+ User::Leave( KErrCorrupt );
+ }
+ }
+ }
+ }
+
+// ============================================================================
+// CWidgetConfigHandler::ParseInfoLocL()
+//
+// @since 3.1
+// ============================================================================
+//
+void CWidgetConfigHandler::ParseInfoLocL(
+ TPtrC8 aBuffer,
+ RFs& aFileSession,
+ CWidgetPropertyValue& aBundleDisplayName )
+ {
+ // This logic is for localization of the display name. The
+ // display name appears in a localization file in the form:
+ // DisplayName = "something"; (for Nokia DTD) or
+ // CFBundleDisplayName = "something"; (for Apple DTD).
+
+ // The encoding of the localization file is not given so it must
+ // be automatically recognized. The default is UTF-8 but if a
+ // byte-order-mark is the first character then the BOM determines
+ // the encoding.
+
+ // get key name ID for display name depending on DTD
+ TWidgetPropertyDescriptionId displayNameId = EPropertyDescriptionIdInvalid;
+ if ( iDtdType == EDtdTypeNokia )
+ {
+ displayNameId = EPropertyDescriptionNokiaDisplayName;
+ }
+ else if ( iDtdType == EDtdTypeApple )
+ {
+ displayNameId = EPropertyDescriptionAppleBundleDisplayName;
+ }
+ if ( EPropertyDescriptionIdInvalid == displayNameId )
+ {
+ User::Leave( KErrCorrupt );
+ }
+
+ TPtrC8 inBuf;
+
+ // default input encoding, no BOM
+ TInt encoding = KCharacterSetIdentifierUtf8;
+ TInt unicodeSizeMultiplier = 2; // a safe value which may waste some space
+ inBuf.Set( aBuffer );
+
+ // check for BOM, we only recognize UTF-16(BE/LE) and UTF-8,
+ // remove BOM if found
+ if ( aBuffer[0] == 0xFE && aBuffer[1] == 0xFF )
+ {
+ encoding = KCharacterSetIdentifierUnicodeBig;
+ unicodeSizeMultiplier = 1;
+ inBuf.Set( aBuffer.Right( aBuffer.Length() - 2 ) );
+ }
+ else if ( aBuffer[0] == 0xFF && aBuffer[1] == 0xFE )
+ {
+ encoding = KCharacterSetIdentifierUnicodeLittle;
+ unicodeSizeMultiplier = 1;
+ inBuf.Set( aBuffer.Right( aBuffer.Length() - 2 ) );
+ }
+ else if ( aBuffer[0] == 0xEF && aBuffer[1] == 0xBB && aBuffer[2] == 0xBF )
+ {
+ encoding = KCharacterSetIdentifierUtf8;
+ unicodeSizeMultiplier = 2; // a safe value which may waste some space
+ inBuf.Set( aBuffer.Right( aBuffer.Length() - 3 ) );
+ }
+
+ // convert to unicode
+ HBufC16* outBuf;
+ ToUnicodeL( encoding, unicodeSizeMultiplier,
+ inBuf, &outBuf, aFileSession );
+ CleanupStack::PushL( outBuf );
+ TPtr16 outPtr = outBuf->Des();
+ // convert the display name key name to unicode since it is just
+ // _LIT() and so might be 8 bit and we want 16 bit "unicode"
+ TPtrC keyName = iProperties[displayNameId].name;
+ HBufC16* keyNameUnicode = HBufC16::NewLC( keyName.Length() );
+ TPtr16 keyNameUnicodePtr( keyNameUnicode->Des() );
+ keyNameUnicodePtr.Copy( keyName );
+
+ // parse the display name
+ outPtr.TrimLeft(); // remove leading whitespace
+ TInt pos = outPtr.Find( keyNameUnicodePtr );
+ if ( (KErrNotFound == pos) || (0 != pos) )
+ {
+ User::Leave( KErrCorrupt );
+ }
+
+ // rest contains buffer after the DisplayName,
+ // i.e. = "some localized text"
+ TPtr16 rest =
+ outPtr.RightTPtr(
+ outPtr.Length()
+ - pos
+ - keyNameUnicode->Length() );
+ const TUint16* data = rest.Ptr();
+ TBool hasEqual = EFalse; // already pass the = sign?
+
+ // start pos and end pos of localized displayname
+ TUint8 start = 0;
+ TUint8 end = 0;
+ for ( TInt i = 0; i < rest.Length(); i++ )
+ {
+ if ( data[i] == ' ' || data[i] == '\t' )
+ {
+ continue;
+ }
+ if ( data[i] == '=' )
+ {
+ hasEqual = ETrue;
+ continue;
+ }
+ if ( data[i] == '\"' )
+ {
+ if ( !start )
+ {
+ start = i + 1;
+ continue;
+ }
+ // else already inquote, so this is close quote
+ end = i;
+ break;
+ }
+ if ( !hasEqual || !start )
+ {
+ User::Leave( KErrCorrupt );
+ }
+ }
+
+ if ( end <= start )
+ {
+ User::Leave( KErrCorrupt );
+ }
+ TInt left = pos + keyNameUnicode->Length() + start;
+ aBundleDisplayName = outPtr.MidTPtr( left, end - start);
+ CleanupStack::PopAndDestroy( 2 ); // outBuf, keyNameUnicode
+ }
+
+// End of File