webengine/widgetinstaller/Src/WidgetConfigHandler.cpp
changeset 0 dd21522fd290
child 11 c8a366e56285
--- /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