/*
* Copyright (c) 2006, 2008 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: Holds metadata, one version per widget.
*
*
*/
#include "WidgetEntry.h"
#include "widgetregistryconstants.h"
#include <s32file.h>
#include <f32file.h>
#include <APGTASK.H>
//#include <widgetappdefs.rh>
// EXTERNAL DATA STRUCTURES
// EXTERNAL FUNCTION PROTOTYPES
// CONSTANTS
#define SAPISECURITYPROMPTNEEDED 0x0001
#define SAPIPROMPTLESS 0x0002
#define SAPIACCESSDENIED 0x0003
// MACROS
// LOCAL CONSTANTS AND MACROS
// for externalize
_LIT( KXmlPropStart, "<prop>" );
_LIT( KXmlPropEnd, "</prop>" );
_LIT( KXmlValStart, "<val>" );
_LIT( KXmlValEnd, "</val>" );
_LIT( KXmlTypeStart, "<type>" );
_LIT( KXmlTypeEnd, "</type>" );
_LIT( KXmlNewline, "\x0D\x0A" ); // DOS/Symbian style works with XML parsers
// for internalize
_LIT8( KXmlPropTag, "prop" );
_LIT8( KXmlValTag, "val" );
_LIT8( KXmlTypeTag, "type" );
_LIT( KXmlDataTypeBool, "bool" );
_LIT( KXmlDataTypeInt, "int" );
_LIT( KXmlDataTypeString, "string" );
_LIT( KXmlDataTypeUid, "uid" );
static const TInt KWidgetPropertyListVersion32 = 1;
static const TInt KWidgetPropertyListVersion71 = 3;
// MODULE DATA STRUCTURES
// LOCAL FUNCTION PROTOTYPES
// FORWARD DECLARATIONS
// ============================= LOCAL FUNCTIONS ===============================
// ============================ MEMBER FUNCTIONS ===============================
// ============================================================================
// CWidgetEntry::NewL()
// two-phase constructor
//
// @since 3.1
// ============================================================================
//
CWidgetEntry* CWidgetEntry::NewL()
{
CWidgetEntry *self = new ( ELeave ) CWidgetEntry();
CleanupStack::PushL( self );
self->ConstructL();
CleanupStack::Pop();
return self;
}
// ============================================================================
// CWidgetEntry::NewL()
// two-phase constructor
//
// @since 5.0
// ============================================================================
//
CWidgetEntry* CWidgetEntry::NewL( RPointerArray<CWidgetPropertyValue>** aProps )
{
CWidgetEntry* tmp = NewL();
for ( TInt i = 0; i < (*aProps)->Count(); i++ )
{
CWidgetPropertyValue* value = CWidgetPropertyValue::NewL();
tmp->iPropertyValues.AppendL( value );
(*tmp)[i].iType = (**aProps)[i]->iType;
(*tmp)[i].iValue = (**aProps)[i]->iValue; // shallow copy of strings
(**aProps)[i]->iType = EWidgetPropTypeUnknown;
delete (**aProps)[i];
}
(*aProps)->Close();
delete *aProps;
*aProps = NULL;
return tmp;
}
// ============================================================================
// CWidgetEntry::CWidgetEntry()
// C++ constructor
//
// @since 3.1
// ============================================================================
//
CWidgetEntry::CWidgetEntry()
: iPropertyValues( EWidgetPropertyIdCount ),
iBlanketPermGranted ( EFalse),
iFullView ( EFalse),
iMiniView ( EFalse)
{
}
// ============================================================================
// CWidgetEntry::~CWidgetEntry()
// destructor
//
// @since 3.1
// ============================================================================
//
CWidgetEntry::~CWidgetEntry()
{
iPropertyValues.ResetAndDestroy();
}
// ============================================================================
// CWidgetEntry::ConstructL()
// symbian second phase constructor
//
// @since 3.1
// ============================================================================
//
void CWidgetEntry::ConstructL()
{
}
// ============================================================================
// CWidgetEntry::InternalizeBinaryL()
// read from persistent storage(file)
//
// @since 3.1
// ============================================================================
//
void CWidgetEntry::InternalizeBinaryL( RReadStream& aReadStream )
{
for (TInt i = iPropertyValues.Count() ; i < EWidgetPropertyIdCount; i++)
{
CWidgetPropertyValue* val = CWidgetPropertyValue::NewL();
CleanupStack::PushL(val);
iPropertyValues.AppendL( val );
CleanupStack::Pop( val );
}
// read what should be EWidgetPropertyListVersion
(*this)[0].DeserializeL( aReadStream );
// For now, leave if version doesn't match compiled-in version,
// FUTURE do something smarter
//WIDGETPROPERTYLISTVERSION is 1 in case of Tiger engine and 3 in case of Leopard engine. Therefore, modifying the check such that
//when the Version id is 1 or 3, we do not treat the file as corrupt.
if ( ( EWidgetPropTypeUnknown == (*this)[EWidgetPropertyListVersion].iType )
|| ( (KWidgetPropertyListVersion32 != (*this)[EWidgetPropertyListVersion] ) && (KWidgetPropertyListVersion71 != (*this)[EWidgetPropertyListVersion] )) )
{
User::Leave( KErrCorrupt );
}
// Read only until the ENokiaWidget for the 3.2 widgets
TInt propertyIdCount = (*this)[EWidgetPropertyListVersion] == KWidgetPropertyListVersion32 ? ENokiaWidget+1 : EWidgetPropertyIdCount;
// fill property values array
for ( TInt i = 1; i < propertyIdCount; ++i )
{
(*this)[i].DeserializeL( aReadStream );
}
}
// ============================================================================
// CWidgetEntry::InternalizeXmlL()
// read from persistent storage(file)
//
// @since 5.0
// ============================================================================
//
void CWidgetEntry::InternalizeXmlL( RFs& aFileSession,
xmlDocPtr aDoc,
xmlNode* n,
CWidgetRegistryXml* aXmlProcessor )
{
// <prop>name<val>value<type>typename</type></val></prop>
//
// prop subtree traversal assumes strict adherence to the
// prototype structure, otherwise code leaves with corrupt code
for ( ;
n;
)
{
// permit some non element stuff (comment, whitespace...) before <prop>
while ( n && ( n->type != XML_ELEMENT_NODE ) )
{
n = n->next;
}
if ( NULL == n )
{
for (TInt i = iPropertyValues.Count(); i < EWidgetPropertyIdCount; i++)
{
CWidgetPropertyValue* val = CWidgetPropertyValue::NewL();
CleanupStack::PushL(val);
iPropertyValues.AppendL( val );
CleanupStack::Pop(); // val
}
return;
}
TPtrC8 propTag( n->name );
if ( 0 != propTag.Compare( KXmlPropTag() ) )
{
// TODO unrecognized subtree?
return;
}
// TODO validate n->children != NULL and type XML_TEXT_NODE
HBufC* name;
aXmlProcessor->GetContentL( aFileSession, aDoc, n->children, &name );
// get value array index (TWidgetPropertyId) for name
TPtr namePtr( name->Des() );
TInt propId =
aXmlProcessor->GetPropertyId( namePtr );
delete name;
name = NULL;
if ( EWidgetPropertyIdInvalid == propId )
{
User::Leave( KErrNoMemory );
}
for (TInt i = iPropertyValues.Count(); i <= propId; i++)
{
CWidgetPropertyValue* val = CWidgetPropertyValue::NewL();
CleanupStack::PushL(val);
iPropertyValues.AppendL( val );
CleanupStack::Pop(); // val
}
n = n->children->next; // down to val
if ( NULL == n )
{
User::Leave( KErrCorrupt );
}
TPtrC8 valTag( n->name );
if ( 0 != valTag.Compare( KXmlValTag() ) )
{
User::Leave( KErrCorrupt );
}
if (propId >= EWidgetPropertyIdCount) // unsupported property
{
HBufC* value = NULL;
if (n->children)
{
aXmlProcessor->GetTextContentAsStringL( aFileSession, aDoc, n->children, &value );
}
else
{
value = KNullDesC().AllocL();
}
(*this)[propId].iValue.s = value;
(*this)[propId].iType = EWidgetPropTypeBlob;
n = (n->parent)->next; // up two and next sibling
continue;
}
// TODO validate n->children != NULL and type XML_TEXT_NODE
HBufC* value;
aXmlProcessor->GetContentL( aFileSession, aDoc, n->children, &value );
CleanupStack::PushL( value );
n = n->children->next; // down to type
if ( NULL == n )
{
User::Leave( KErrCorrupt );
}
TPtrC8 typeTag( n->name );
if ( 0 != typeTag.Compare( KXmlTypeTag() ) )
{
User::Leave( KErrCorrupt );
}
// TODO validate n->children != NULL and type XML_TEXT_NODE
HBufC* type;
aXmlProcessor->GetContentL( aFileSession, aDoc, n->children, &type );
CleanupStack::PushL( type );
// now have: name, value, type
// convert type string to TWidgetPropertyType
//
// assume void/unknown is not put in XML format so anything
// not recognized should be handled like other unrecognized
// subtree
TWidgetPropertyType typeEnum = EWidgetPropTypeUnknown;
if ( 0 == type->Des().Compare( KXmlDataTypeBool() ) )
{
typeEnum = EWidgetPropTypeBool;
}
else if ( 0 == type->Des().Compare( KXmlDataTypeInt() ) )
{
typeEnum = EWidgetPropTypeInt;
}
else if ( 0 == type->Des().Compare( KXmlDataTypeString() ) )
{
typeEnum = EWidgetPropTypeString;
}
else if ( 0 == type->Des().Compare( KXmlDataTypeUid() ) )
{
typeEnum = EWidgetPropTypeUid;
}
CleanupStack::PopAndDestroy( type );
// TODO handle unknown type due to future extensions: add prop
// subtree to list of unrecognized subtrees
// set prop according to type
switch ( typeEnum )
{
case EWidgetPropTypeBool:
if ( 0 == value->Des().Compare( _L("0") ) )
{
(*this)[propId].iValue.i = 0;
}
else
{
(*this)[propId].iValue.i = 1;
}
break;
case EWidgetPropTypeInt:
{
TLex toInt( value->Des() );
TInt k;
if ( KErrNone != toInt.Val( k ) )
{
User::Leave( KErrCorrupt );
}
(*this)[propId].iValue.i = k;
}
break;
case EWidgetPropTypeString:
(*this)[propId].iValue.s = value;
break;
case EWidgetPropTypeUid:
{
TLex toUid( value->Des() );
TInt u;
if ( KErrNone != toUid.Val( u ) )
{
User::Leave( KErrCorrupt );
}
(*this)[propId].iValue.uid = TUid::Uid( u );
}
break;
};
(*this)[propId].iType = typeEnum;
CleanupStack::Pop( value );
if ( EWidgetPropTypeString != typeEnum )
{
delete value;
}
n = ((n->parent)->parent)->next; // up two and next sibling
}
}
// ============================================================================
// CWidgetEntry::ExternalizeBinaryL()
// write to persistent storage(file)
//
// @since 3.1
// ============================================================================
//
void CWidgetEntry::ExternalizeBinaryL( RWriteStream& aWriteStream )
{
TInt i = 0;
for ( ; i < EWidgetPropertyIdCount; ++i )
{
(*this)[i].SerializeL( aWriteStream );
}
}
void CWidgetEntry::ExternalizeXmlL( RWriteStream& aWriteStream,
CWidgetRegistryXml* aXmlProcessor,
RFs& aFileSession )
{
xmlDocPtr doc = NULL; // not really used
TInt i = 0;
// For each property, write an XML entry
for ( ; i < EWidgetPropertyIdCount; ++i )
{
// skip props without values
if ( EWidgetPropTypeUnknown == (*this)[i].iType )
{
continue;
}
TBuf<KMaxFileName> str;
// <prop>name
str.Append( KXmlPropStart );
str.Append( aXmlProcessor->XmlPropertyName( i ) );
aWriteStream.WriteL( str );
// <val>value
str.SetLength( 0 );
str.Append( KXmlValStart );
aWriteStream.WriteL( str );
str.SetLength( 0 );
switch ( (*this)[i].iType )
{
case EWidgetPropTypeBool:
{
TInt j = (*this)[i];
if ( 0 == j )
{
str.Append( _L("0") );
}
else
{
str.Append( _L("1") );
}
}
break;
case EWidgetPropTypeInt:
{
TInt k = (*this)[i];
str.AppendFormat( _L("%d"), k );
}
break;
case EWidgetPropTypeString:
{
// start an encoding process for special characters for xml writing
// the special characters are:
// '&', Ampersand: &
// '>', greater-than: >
// '<', less-than: <
// ''', apostrophe: '
// '"', quote: "
TBuf<KMaxFileName> orig;
orig.Append((*this)[i]);
TUint16 * cur = (TUint16 *)orig.Ptr();
TUint16 * out = (TUint16 *)str.Ptr();
TInt len = orig.Length();
for ( TInt i = 0; i < orig.Length(); i++, cur++ )
{
// By default one have to encode at least '<', '>', '"' and '&' !
if (*cur == '<') {
*out++ = '&';
*out++ = 'l';
*out++ = 't';
*out++ = ';';
len += 3;
} else if (*cur == '>') {
*out++ = '&';
*out++ = 'g';
*out++ = 't';
*out++ = ';';
len += 3;
} else if (*cur == '&') {
*out++ = '&';
*out++ = 'a';
*out++ = 'm';
*out++ = 'p';
*out++ = ';';
len += 4;
} else if (*cur == '"') {
*out++ = '&';
*out++ = 'q';
*out++ = 'u';
*out++ = 'o';
*out++ = 't';
*out++ = ';';
len += 5;
} else if (*cur == '\'') {
*out++ = '&';
*out++ = 'a';
*out++ = 'p';
*out++ = 'o';
*out++ = 's';
*out++ = ';';
len += 5;
} else if (*cur == '\r') {
*out++ = '&';
*out++ = '#';
*out++ = '1';
*out++ = '3';
*out++ = ';';
len += 4;
} else {
*out++ = *cur;
}
}
str.SetLength(len );
break;
}
case EWidgetPropTypeUid:
const TUid& u = (*this)[i];
TInt l = u.iUid;
str.AppendFormat( _L("%d"), l );
break;
};
aWriteStream.WriteL( str );
// <type>type
str.SetLength( 0 );
str.Append( KXmlTypeStart );
switch ( (*this)[i].iType )
{
case EWidgetPropTypeBool:
str.Append( _L("bool") );
break;
case EWidgetPropTypeInt:
str.Append( _L("int") );
break;
case EWidgetPropTypeString:
str.Append( _L("string") );
break;
case EWidgetPropTypeUid:
str.Append( _L("uid") );
break;
};
aWriteStream.WriteL( str );
// </type></val></prop>
str.SetLength( 0 );
str.Append( KXmlTypeEnd );
str.Append( KXmlValEnd );
str.Append( KXmlPropEnd );
str.Append( KXmlNewline );
aWriteStream.WriteL( str );
}
for ( ; i < iPropertyValues.Count(); ++i )
{
TBuf<KMaxFileName> str;
// <prop>name
str.Append( KXmlPropStart );
str.Append( aXmlProcessor->XmlPropertyName( i ) );
aWriteStream.WriteL( str );
// <val>value
str.SetLength( 0 );
str.Append( KXmlValStart );
aWriteStream.WriteL( str );
str.SetLength( 0 );
const HBufC* s = (iPropertyValues[i])->iValue.s;
str.Append( *s );
aWriteStream.WriteL( str );
str.SetLength( 0 );
str.Append( KXmlValEnd );
str.Append( KXmlPropEnd );
str.Append( KXmlNewline );
aWriteStream.WriteL( str );
}
}
// ============================================================================
// CWidgetEntry::Active()
// Is widget running? 0 if not, non zero if running.
//
// @since 3.1
// ============================================================================
//
TInt CWidgetEntry::ActiveL()
{
if ( iActive )
{
// check that WidgetUI didn't crash, this assumes all widgets
// in the registry are running under WidgetUI
RWsSession wsSession;
User::LeaveIfError( wsSession.Connect() );
CleanupClosePushL( wsSession );
TApaTaskList taskList( wsSession );
TApaTask task = taskList.FindApp( KUidWidgetUi );
if ( EFalse == task.Exists() )
{
// widget UI crashed, reset active
iActive = 0;
}
CleanupStack::PopAndDestroy( &wsSession );
}
return iActive;
}
// ============================================================================
// CWidgetEntry::SapiAccessState()
// Does widget have sapi access? after accepting security prompt, promptless or no access.
//
// @since 5.0
// ============================================================================
//
TInt CWidgetEntry::SapiAccessState()
{
if( GetFullViewState() && !GetMiniViewState())
{
return SAPISECURITYPROMPTNEEDED;
}
else if ( GetMiniViewState() && GetBlanketPermGranted() )
{
return SAPIPROMPTLESS;
}
else
{
return SAPIACCESSDENIED;
}
}
// End of File