--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/upnpmediaserver/contentdirectoryservice/src/upnpelementfactory.cpp Thu Dec 17 08:52:00 2009 +0200
@@ -0,0 +1,1473 @@
+/** @file
+* Copyright (c) 2005-2006 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "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: Element Factory.
+*
+*/
+
+
+// INCLUDE FILES
+#include <sysutil.h>
+#include <uri8.h>
+#include <xmlengdomparser.h>
+
+#include "upnpelementfactory.h"
+#include "upnpcontentdirectoryglobals.h"
+#include "upnpstring.h"
+#include "upnpprotocolinfo.h"
+#include "upnpcommonupnplits.h"
+#include "upnpcdutils.h"
+#include "upnpprotocolinfolocal.h"
+
+using namespace UpnpDlnaProtocolInfo;
+
+// ============================= LOCAL FUNCTIONS ===============================
+// -----------------------------------------------------------------------------
+// DestroyRPointerArray
+// Used by TCleanupItem to destroy array
+// -----------------------------------------------------------------------------
+//
+void DestroyRArray(TAny* aArray)
+{
+ RArray<RXmlEngDocument>* array = (RArray<RXmlEngDocument>*) aArray;
+ for(TInt i = 0; i < array->Count(); i++ )
+ (*array)[i].Close();
+ (*array).Close();
+}
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::~CUpnpElementFactory()
+// C++ default destructor. (virtual destructor)
+// -----------------------------------------------------------------------------
+//
+CUpnpElementFactory::~CUpnpElementFactory()
+{
+ //Close XML document
+ iDocument.Close();
+
+ iDOMImpl.Close();
+}
+
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::NewL()
+// Two-phased constructor
+// -----------------------------------------------------------------------------
+//
+CUpnpElementFactory* CUpnpElementFactory::NewL( const TDesC& aObjectsXmlPath )
+{
+ CUpnpElementFactory* self = CUpnpElementFactory::NewLC( aObjectsXmlPath );
+ CleanupStack::Pop( self );
+ return self;
+}
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::NewLC()
+// Two-phased constructor
+// -----------------------------------------------------------------------------
+//
+CUpnpElementFactory* CUpnpElementFactory::NewLC( const TDesC& aObjectsXmlPath )
+{
+ CUpnpElementFactory* self = new (ELeave) CUpnpElementFactory();
+ CleanupStack::PushL( self );
+ self->ConstructL( aObjectsXmlPath );
+ return self;
+}
+
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::ConstructL()
+// Two-phased constructor
+// -----------------------------------------------------------------------------
+//
+void CUpnpElementFactory::ConstructL(const TDesC& aObjectsXmlPath)
+{
+
+ iDOMImpl.OpenL();
+
+ RXmlEngDOMParser parser;
+ User::LeaveIfError( parser.Open(iDOMImpl) );
+ CleanupClosePushL(parser);
+
+ if ( aObjectsXmlPath == KNullDesC() )
+ {
+ RFs fs;
+ User::LeaveIfError(fs.Connect());
+ CleanupClosePushL(fs);
+
+ TFileName path;
+ User::LeaveIfError(fs.PrivatePath(path));
+
+ TParse fp;
+ fp.Set(KObjectsXmlFileName(),&path, 0);
+ path = fp.FullName();
+
+ iDocument = parser.ParseFileL( path );
+ CleanupStack::PopAndDestroy(&fs);
+ }
+ else
+ {
+ iDocument = parser.ParseFileL( aObjectsXmlPath );
+ }
+
+
+
+ CleanupStack::PopAndDestroy(&parser);
+}
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::CUpnpElementFactory()
+// Default constructor
+// -----------------------------------------------------------------------------
+//
+CUpnpElementFactory::CUpnpElementFactory()
+{
+
+}
+
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::ValidateNewObjectL()
+// Function to validate a new object given by Control Point, especially
+// upnp:class element field eg. object.item.musictrack
+// IMPORTANT: If objects's description is invalid due to missing elements
+// it tries to repair it by adding those missing elements.
+// -----------------------------------------------------------------------------
+//
+
+TUpnpErrorCode CUpnpElementFactory::ValidateNewObjectL( const TXmlEngElement& aNewElement, TBool aNew, TBool aLocalSharing)
+{
+ TInt i;
+ TPtrC8 objectType = KItem();
+
+ RXmlEngNodeList<TXmlEngElement> elements;
+ CleanupClosePushL(elements);
+ aNewElement.GetChildElements( elements );
+
+ // invalid element if the count of the objects is less than 1 (=0)
+ if ( elements.Count() != 1 )
+ {
+ User::Leave( EInvalidArgs );
+ }
+ CleanupStack::PopAndDestroy(&elements);
+ // try to find the new item from the xml
+ TXmlEngElement object;
+ UpnpDomInterface::GetElementL( aNewElement, object, KItem() );
+ if ( object.IsNull() )
+ {
+
+ // if it's not an item, it's a container
+ UpnpDomInterface::GetElementL( aNewElement, object, KContainer() );
+ if ( object.IsNull() )
+ {
+ // not even a container, leave!
+ User::Leave ( EInvalidArgs );
+ }
+ objectType.Set( KContainer() );
+ }
+
+ // restriced value
+ TPtrC8 restrVal = UpnpDomInterface::GetAttrValueL( object, KRestricted );
+ if (
+ (UpnpCD::Kfalse().Compare( restrVal ) != 0) &&
+ (UpnpCD::KZero().Compare( restrVal ) != 0) &&
+ (UpnpCD::Ktrue().Compare( restrVal ) != 0) &&
+ (UpnpCD::KOne().Compare( restrVal ) != 0)
+ )
+ {
+ User::Leave( EBadMetadata );
+ }
+
+ // for convenience later, take now a reference to the children of the object
+ RXmlEngNodeList<TXmlEngElement> children;
+ CleanupClosePushL(children);
+ object.GetChildElements( children );
+
+ // an exception: we can't have <res importUri=".. element in
+ // a new object (set by control point)
+ while ( children.HasNext() )
+ {
+ TXmlEngElement child = children.Next();
+
+ if ( IsNotEmptyImportUriL( child ) && aNew )
+ {
+ User::Leave ( EBadMetadata );
+ }
+
+ //---- check res@duration, 7.3.22 MM DIDL-Lite res@duration Format
+ CheckDurationOfResElementL(child);
+ CheckSizeOfResElementL(child);
+
+ RXmlEngNodeList<TXmlEngElement> forbiddenChildren;
+ CleanupClosePushL(forbiddenChildren);
+ child.GetChildElements( forbiddenChildren );
+
+ if ( forbiddenChildren.HasNext()
+ && child.Name() != KVendorDescriptor ) // ignore <desc></desc>
+ {
+ User::Leave ( EBadMetadata );
+ }
+ CleanupStack::PopAndDestroy(&forbiddenChildren);
+ if ( child.Name() == KDate8() )
+ {
+ if (!UpnpCdUtils::ValidateDateL(child.Value()))
+ child.Remove();
+ }
+
+ }
+
+ // if survived here, we have the new element of type item or container
+ // let's analyze its type
+
+ // let's inspect each of types
+ // at first, collect object type descriptions from objects xml
+ // to a pointer array
+ RArray<TXmlEngElement> objectDescrs;
+ CleanupClosePushL( objectDescrs );
+ // store class descriptor elements in this array
+ ClassesL( object, objectDescrs, objectType );
+
+ // validate each separately
+
+ ValidatePropertiesL(object, objectDescrs);
+ if(aNew)
+ {
+ ValidateBigImageL(object);
+ }
+
+ // for each type, check that
+ // this new object has all the required fields
+
+ for (i=0; i<objectDescrs.Count(); i++)
+ {
+ // now we have to go through all the fields of the new item
+ // first, for convenience take a pointer to <ps>(properties) element
+
+ RXmlEngNodeList<TXmlEngElement> propElems;
+ CleanupClosePushL(propElems);
+ objectDescrs[i].GetChildElements( propElems );
+
+
+ while ( propElems.HasNext() )
+ {
+
+ TXmlEngElement ps = propElems.Next(); // ps stands for properties
+ if ( ps.Name() == KProperties() )
+ {
+
+ // take the properties
+ RXmlEngNodeList<TXmlEngElement> properties;
+ CleanupClosePushL(properties);
+ ps.GetChildElements( properties );
+
+ const TDesC8& propertyType = UpnpDomInterface::GetAttrValueL( ps, KType() );
+
+ TBool elementFound;
+
+
+ // check each property
+ while ( properties.HasNext() )
+ {
+
+ TXmlEngElement el = properties.Next();
+
+ // Validate element
+ if ( propertyType == KElement() )
+ {
+ elementFound = EFalse;
+
+ // Check if this element is requiered
+ const TDesC8& required = UpnpDomInterface::GetAttrValueL( el, KRequiredObject() );
+
+ TPtrC8 elementName = UpnpDomInterface::GetAttrValueL( el, KName() );
+
+ // If it's required then check it's existence
+
+ if ( required == UpnpCD::KOne() || elementName == KRes() || elementName == KAlbumArtURI() )
+ {
+ if( !KRes().Compare(elementName) || !KAlbumArtURI().Compare(elementName))
+ {
+ elementFound = ETrue;
+ }
+ // get children once more, because this kind of list does not have any reset function
+ object.GetChildElements( children );
+ while ( children.HasNext() )
+ {
+
+ TXmlEngElement child = children.Next();
+
+ HBufC8* nameWithNs = NameWithNsLC( child );
+
+ if ( *nameWithNs == elementName )
+ {
+ // local sharing
+ if(aNew && *nameWithNs == KRes)
+ {
+ TUriParser8 up;
+ TPtrC8 rv(child.Text());
+ if(rv.Length())
+ {
+ User::LeaveIfError( up.Parse(child.Text()) );
+ TPtrC8 path( up.Extract(EUriPath) );
+ TPtrC8 scheme( up.Extract(EUriScheme) );
+
+ if(aLocalSharing)
+ { // local action
+ if( scheme == UpnpHTTP::KSchemeFile8())
+ {
+ // The path can be: /c:/....
+ // or /c/... - without colon.
+ // Both situation are correct but
+ // in further operations we assume
+ // there is not any colon next to the drive letter.
+ // Therefore, remove it if second element of path table equals ':'
+ if(path[2] == KColon8()[0])
+ { // There IS a colon next to the drive letter.
+ // Here is an example uri:
+ // file:///c:/...
+ // As you can see the second colon must be removed
+ HBufC8* uri = child.Text().AllocLC();
+ TPtr8 uriPtr(uri->Des());
+ TPtrC8 tmp(uri->Des());
+ TInt second = 2;
+ TInt colonPos = 0;
+ for(TInt i = 0; i < second; i++)
+ {
+ colonPos += tmp.Find(KColon8) + 1;
+ tmp.Set( uriPtr.Mid(colonPos) );
+ }
+ // remove the colon
+ uriPtr.Replace(colonPos - 1, KColon8().Length(), KNullString8);
+ // set TXmlEngElement value
+ child.SetTextL(uriPtr);
+
+ // clean up
+ CleanupStack::PopAndDestroy(uri);
+ }
+
+ // check other restrictions
+ TUriParser8 up;
+ User::LeaveIfError( up.Parse(child.Text()) );
+ TPtrC8 path( up.Extract(EUriPath) );
+
+ // sharing from Z: drive is forbidden
+ // second character is a drive letter
+ if(path[1] == KForbiddenDrivez()[0] || path[1] == KForbiddenDriveZ()[0])
+ {
+ User::Leave(EArgumentValue);
+ }
+
+ // cannot share from private directory
+ if(!path.Match(KForbiddenPrivatePattern))
+ {
+ User::Leave(EArgumentValue);
+ }
+
+ }
+ }
+ else
+ { // not local action
+ // "file" schema is forbidden here
+ if(scheme == UpnpHTTP::KSchemeFile8())
+ {
+ User::Leave(EArgumentValue);
+ }
+ }
+ }
+ }
+
+
+ if ( elementFound )
+ {
+ // multiple values for one element!
+ const TDesC8& multiple = UpnpDomInterface::GetAttrValueL( el, KMultiple() );
+
+ // if it's not allowed for this element, leave!
+ if ( !multiple.Length() )
+ {
+ User::Leave( EInvalidArgs );
+ }
+ }
+ elementFound = ETrue;
+ // mark the element required - if not res
+ if( KRes().Compare(elementName) && KAlbumArtURI().Compare(elementName))
+ {
+ child.AddNewAttributeL(KRequiredAtrName,KTrueValue8);
+ }
+
+ // nested validation
+ RXmlEngNodeList<TXmlEngElement> nestEls;
+ CleanupClosePushL(nestEls);
+ el.GetChildElements(nestEls);
+ while(nestEls.HasNext())
+ {
+ TXmlEngElement nestPs = nestEls.Next();
+
+ // take the properties
+ RXmlEngNodeList<TXmlEngElement> nestProperties;
+ nestPs.GetChildElements( nestProperties );
+ const TDesC8& nestPropertyType = UpnpDomInterface::GetAttrValueL( nestPs, KType() );
+ // Validate attribute
+ if ( nestPropertyType == KAttribute() )
+ {
+ while(nestProperties.HasNext())
+ {
+ TXmlEngElement nestEl = nestProperties.Next();
+ //TBool nestElementFound;
+
+ //nestElementFound = EFalse;
+
+ const TDesC8& nestRequired = UpnpDomInterface::GetAttrValueL( nestEl, KRequiredObject() );
+ TPtrC8 nestElementName = UpnpDomInterface::GetAttrValueL( nestEl, KName() );
+ if ( nestRequired == UpnpCD::KOne() || nestElementName == KDlnaProfileID)
+ {
+ TPtrC8 nestCurrentValue = UpnpDomInterface::GetAttrValueL( child, nestElementName );
+
+ TPtrC8 nameOfAttr;
+ TPtrC8 valOfAttr;
+ nameOfAttr.Set( nestElementName );
+
+ // Start of 'dlna:profileID' attribute case
+ if( nameWithNs->Des() == KAlbumArtURI && nestElementName == KDlnaProfileID) // ---------------- 1 ------------
+ {
+ TXmlEngAttr profId = child.AttributeNodeL(KProfileID, KXmlnsDlna);
+ if(profId.NotNull())
+ {
+ if (profId.Value().Compare(KDefaultProfileID))
+ {
+ User::Leave( EBadMetadata );
+ }
+ // setting real name of attribute -> localName
+ nestElementName.Set(KProfileID); // descriptor
+ nameOfAttr.Set( nestElementName ); // related TString
+
+ // generating a new value of 'dlna:profileID'
+ HBufC8* albumArtURIelemValue = UpnpDomInterface::GetElementValueL(child).AllocLC();
+ TPtr8 albumArtURIelemValuePtr( albumArtURIelemValue->Des() );
+
+ albumArtURIelemValuePtr.Trim(); // deletes leading and trailing whitespace characters
+ child.SetValueL(albumArtURIelemValuePtr); // sets new trimmed value to albumArtURI
+
+ CUpnpDlnaProtocolInfo* tempProtocolInfo = NULL;
+ TInt error = iContentDirectory->GetProtocolInfoL( albumArtURIelemValuePtr, tempProtocolInfo );
+ TPtrC8 tempPnParam;
+ if( error >=0 )
+ {
+ tempPnParam.Set( tempProtocolInfo->PnParameter() );
+
+ nestCurrentValue.Set(tempPnParam); // descriptor
+ valOfAttr.Set(tempPnParam); // related TString
+ }
+ else
+ {
+ User::Leave( EBadMetadata );
+ }
+ CleanupStack::PopAndDestroy(albumArtURIelemValue);
+
+ // if albumArtURI doesn't contain profileID -> it creates one and also related namespace
+ // if albumArtURI contains profileID -> it modifies profileID's value
+ child.SetAttributeL( nameOfAttr, valOfAttr, KXmlnsDlna(), KDlnaPrefix() );
+
+ delete tempProtocolInfo;
+ tempProtocolInfo = NULL;
+ }
+
+ } // End of 'dlna:profileID' attribute case
+ else
+ {
+ if ( !nestCurrentValue.Length() )
+ {
+
+ if(nestElementName == KprotocolInfo)
+ {
+ if( ! aLocalSharing )
+ {
+ valOfAttr.Set( KEmptyProtocolInfoVal8() );
+ }
+ else
+ {
+ User::Leave( EBadMetadata );
+ }
+ } //------- 2 ----- //------- 2 -----
+ else
+ {
+ valOfAttr.Set( KNullDesC8() );
+ }
+
+ child.AddNewAttributeL( nameOfAttr, valOfAttr );
+ }
+ else
+ {
+ if(nestElementName == KprotocolInfo)
+ {
+ HBufC8* protInfoValue = NULL;
+ TRAPD(err, protInfoValue = ValidateProtocolInfoInResL( nestCurrentValue, aLocalSharing ));
+ if(err)
+ {
+ User::Leave(EBadMetadata);
+ }
+ CleanupStack::PushL( protInfoValue );
+ valOfAttr.Set( *protInfoValue );
+ child.SetAttributeL( nameOfAttr, valOfAttr );
+ CleanupStack::PopAndDestroy( protInfoValue );
+ } //------- 3 ----- //------- 3 -----
+ }
+ }
+
+
+ // if not main tag mark the attr is required
+ if( !IsMainObjectTagL(child) && nestElementName != KDlnaProfileID)
+ {
+
+ HBufC8* attrReq = HBufC8::NewLC(
+ nestElementName.Length()
+ +KRequiredAtrSuf().Length() );
+ TPtr8 attrReqPtr(attrReq->Des());
+ attrReqPtr = nestElementName;
+ attrReqPtr.Append(KRequiredAtrSuf);
+ child.AddNewAttributeL( attrReqPtr, KTrueValue8 );
+ CleanupStack::PopAndDestroy(attrReq);
+ }
+ }
+ }
+ }
+
+ }
+ CleanupStack::PopAndDestroy(&nestEls);
+ }
+ CleanupStack::PopAndDestroy( nameWithNs );
+
+ }
+
+ // If not found, add it
+ if ( !elementFound )
+ {
+ User::Leave(EBadMetadata);
+ }
+ }
+ }
+
+ // Validate attribute
+ if ( propertyType == KAttribute() )
+ {
+ elementFound = EFalse;
+
+ const TDesC8& required = UpnpDomInterface::GetAttrValueL( el, KRequiredObject() );
+ if ( required == UpnpCD::KOne() )
+ {
+
+ const TDesC8& elementName = UpnpDomInterface::GetAttrValueL( el, KName() );
+
+ const TDesC8& currentValue = UpnpDomInterface::GetAttrValueL( object, elementName );
+
+ if ( !currentValue.Length() )
+ {
+ TXmlEngAttr attr = object.AttributeNodeL( elementName );
+
+ if(attr.NotNull())
+ {
+ attr.SetValueL(KNullDesC8);
+ }
+ else
+ {
+ object.AddNewAttributeL( elementName, KNullDesC8 );
+ }
+ }
+ // if not main tag mark the attr is required
+ if(!IsMainObjectTagL(object))
+ {
+ HBufC8* attrReq = HBufC8::NewLC(
+ elementName.Length()+KRequiredAtrSuf().Length() );
+ TPtr8 attrReqPtr(attrReq->Des());
+ attrReqPtr = elementName;
+ attrReqPtr.Append(KRequiredAtrSuf);
+ object.AddNewAttributeL( attrReqPtr, KTrueValue8 );
+ CleanupStack::PopAndDestroy(attrReq);
+ }
+ }
+ }
+ }
+ CleanupStack::PopAndDestroy(&properties);
+ }
+ }
+ CleanupStack::PopAndDestroy(&propElems);
+ }
+ CleanupStack::PopAndDestroy(); //objectDescrs.Close();
+ CleanupStack::PopAndDestroy(&children);
+
+ // now the object
+ // * has the all required fields (if some were missing, they are added)
+ // * had a proper xml structure (_not_ using UpnpDomInterface:: functions that do not care)
+ // * has for sure a mostly proper object structure
+
+ return EUndefined;
+}
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::ValidatePropertiesL()
+// Function leaves on error.
+// -----------------------------------------------------------------------------
+//
+void CUpnpElementFactory::ValidatePropertiesL( TXmlEngElement aObj,
+ RArray<TXmlEngElement>& aClassList)
+{
+ // validate main object's attributes
+ ValidateMainAttributesL(aObj, aClassList);
+
+ // validate elements
+ RXmlEngNodeList<TXmlEngElement> elements;
+ CleanupClosePushL(elements);
+ aObj.GetChildElements (elements);
+
+ // for each element
+ while(elements.HasNext())
+ {
+ TXmlEngElement el = elements.Next();
+ ValidateElementL(el, aClassList);
+ }
+ CleanupStack::PopAndDestroy(&elements);
+}
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::ValidateBigImageL()
+// Function leaves on error.
+// -----------------------------------------------------------------------------
+//
+void CUpnpElementFactory::ValidateBigImageL( TXmlEngElement aObj)
+{
+ RArray<TXmlEngElement> elms;
+ CleanupClosePushL(elms);
+
+ if( UpnpDomInterface::GetElementListL(aObj, elms, KRes) )
+ {
+ for(TInt i = 0; i < elms.Count(); i++)
+ {
+
+ TXmlEngAttr prInfAttr = elms[i].AttributeNodeL(KprotocolInfo());
+ if(prInfAttr.NotNull())
+ {
+ CUpnpProtocolInfoLocal* protInf = CUpnpProtocolInfoLocal::NewL(
+ UpnpDomInterface::GetAttrValueL(elms[i], KprotocolInfo) );
+ CleanupStack::PushL(protInf);
+
+ /* Only support for DLNA pn-params:
+ * 1) JPEG_SM
+ * 2) MP3
+ * 3) AAC_ISO_320
+ * 4) AVC_MP4_BL_CIF15_AAC_520
+ */
+ if( protInf->PnParameter() != KDLNA_PN_JPEG_SM &&
+ protInf->PnParameter() != KDLNA_PN_MP3 &&
+ protInf->PnParameter() != KDLNA_PN_AAC_ISO_320 &&
+ protInf->PnParameter() != KDLNA_PN_AVC_MP4_BL_CIF15_AAC_520
+ )
+ {
+ // set 4th parameter to "*"
+ protInf->SetFourthFieldL(KAsterisk8);
+ TPtrC8 prInfo = protInf->ProtocolInfoL();
+ HBufC8* prInfTmp = prInfo.Alloc();
+ CleanupStack::PushL(prInfTmp);
+ prInfAttr.SetValueL( *prInfTmp );
+ CleanupStack::PopAndDestroy(prInfTmp);
+ }
+ // clean up
+ CleanupStack::PopAndDestroy(protInf);
+ }
+ }
+ }
+
+ // clean up
+ CleanupStack::PopAndDestroy(&elms);
+}
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::ValidateElementL()
+// Function leaves on error.
+// -----------------------------------------------------------------------------
+//
+void CUpnpElementFactory::ValidateElementL( TXmlEngElement aElement,
+ RArray<TXmlEngElement>& aClassList)
+{
+ if(aElement.Name() == KRes)
+ {
+ ValidateResElL(aElement, aClassList);
+ }
+ else
+ {
+ // get pattern
+ HBufC8* name = UpnpCdUtils::GetElmNameWithNsL(aElement);
+ CleanupStack::PushL(name);
+ TXmlEngElement pattern = GetPatternL(*name, aClassList, KElement);
+ if(pattern.NotNull())
+ {
+ ValidateElWithPatternL(aElement, pattern); // leaves on error
+ }
+ else
+ { // attr is not supported - remove
+ aElement.Remove();
+ }
+ // clean up
+ CleanupStack::PopAndDestroy(name);
+ }
+}
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::ValidateMainAttributesL()
+// Function leaves on error.
+// -----------------------------------------------------------------------------
+//
+void CUpnpElementFactory::ValidateMainAttributesL( TXmlEngElement aObj,
+ RArray<TXmlEngElement>& aClassList)
+{
+ // list of attributes
+ RXmlEngNodeList<TXmlEngAttr> attrList;
+ CleanupClosePushL(attrList);
+ aObj.GetAttributes(attrList);
+
+ // for each attr
+ while(attrList.HasNext())
+ {
+ // get attr
+ TXmlEngAttr attr = attrList.Next();
+
+ // get pattern
+ TXmlEngElement pattern = GetPatternL(attr.Name(), aClassList, KAttribute);
+ if(pattern.NotNull())
+ {
+ ValidateAttrWithPatternL(attr, pattern); // leaves on error
+ }
+ else
+ { // attr is not supported - remove
+ attr.Remove();
+ }
+ }
+ CleanupStack::PopAndDestroy(&attrList);
+}
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::ValidateElWithPatternL()
+// Function leaves on error.
+// -----------------------------------------------------------------------------
+//
+void CUpnpElementFactory::ValidateResElL( TXmlEngElement aElement,
+ RArray<TXmlEngElement>& aClassList)
+{
+ // list of attributes
+ RXmlEngNodeList<TXmlEngAttr> attrList;
+ CleanupClosePushL(attrList);
+ aElement.GetAttributes(attrList);
+
+ // for each attr
+ while(attrList.HasNext())
+ {
+ // get attr
+ TXmlEngAttr attr = attrList.Next();
+
+ // get pattern
+ TXmlEngElement pattern = GetPatternForResAttrL(attr.Name(), aClassList);
+ if(pattern.NotNull())
+ {
+ ValidateAttrWithPatternL(attr, pattern); // leaves on error
+ }
+ else
+ { // attr is not supported - remove
+ attr.Remove();
+ }
+ }
+ CleanupStack::PopAndDestroy(&attrList);
+}
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::ValidateElWithPatternL()
+// Function leaves on error.
+// -----------------------------------------------------------------------------
+//
+void CUpnpElementFactory::ValidateElWithPatternL( TXmlEngElement aElement,
+ TXmlEngElement aPattern )
+{
+ // is required?
+ if(IsRequiredL(aPattern) )
+ { // cannot be empty
+ if( !aElement.Value().Length() ||
+ UpnpCdUtils::IsWhiteString( aElement.Value() ) )
+ {
+ User::Leave(EBadMetadata);
+ }
+ }
+}
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::ValidateAttrWithPatternL()
+// Function leaves on error.
+// -----------------------------------------------------------------------------
+//
+void CUpnpElementFactory::ValidateAttrWithPatternL( TXmlEngAttr aAttr,
+ TXmlEngElement aPattern )
+{
+ // is required?
+ if(IsRequiredL(aPattern) )
+ { // cannot be empty
+ if( !aAttr.Value().Length() ||
+ UpnpCdUtils::IsWhiteString( aAttr.Value() ) )
+ {
+ User::Leave(EBadMetadata);
+ }
+ }
+}
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::ValidateAttrWithPatternL()
+// Function leaves on error.
+// -----------------------------------------------------------------------------
+//
+TBool CUpnpElementFactory::IsRequiredL(TXmlEngElement aPattern)
+{
+ TXmlEngAttr reqAttr = aPattern.AttributeNodeL(KRequiredObject());
+ TBool ret = EFalse;
+ if( reqAttr.NotNull() &&
+ reqAttr.Value().Length() &&
+ reqAttr.Value() == KTrueValue8() )
+ {
+ ret = ETrue;
+ }
+ return ret;
+}
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::GetPatternForElL()
+// Function leaves on error.
+// -----------------------------------------------------------------------------
+//
+TXmlEngElement CUpnpElementFactory::GetPatternL( const TDesC8& aPropertyName,
+ RArray<TXmlEngElement>& aClassList,
+ const TDesC8& aType )
+{
+ TXmlEngElement retEl;
+
+ // for each class
+ for(TInt i = 0; i < aClassList.Count(); i++)
+ {
+ TXmlEngElement elPattEl;
+ UpnpDomInterface::GetDirectoryElementL(aClassList[i], elPattEl, KProperties, KType, aType);
+ if(elPattEl.NotNull())
+ {
+ UpnpDomInterface::GetDirectoryElementL(elPattEl, retEl, KObjectProperty, KObjectName, aPropertyName);
+
+ // break if found
+ if(retEl.NotNull())
+ {
+ break;
+ }
+ }
+ }
+
+ return retEl;
+}
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::GetPatternForResAttrL()
+// Function leaves on error.
+// -----------------------------------------------------------------------------
+//
+TXmlEngElement CUpnpElementFactory::GetPatternForResAttrL(const TDesC8& aPropertyName,
+ RArray<TXmlEngElement>& aClassList )
+{
+ TXmlEngElement retEl;
+
+ // for each class
+ for(TInt i = 0; i < aClassList.Count(); i++)
+ {
+ TXmlEngElement resAttrPattEl;
+ UpnpDomInterface::GetDirectoryElementL(aClassList[i], resAttrPattEl, KProperties, KType, KResAttr);
+ if(resAttrPattEl.NotNull())
+ {
+ UpnpDomInterface::GetDirectoryElementL(resAttrPattEl, retEl, KObjectProperty, KObjectName, aPropertyName);
+
+ // break if found
+ if(retEl.NotNull())
+ {
+ break;
+ }
+ }
+ }
+
+ return retEl;
+}
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::IsMainObjectTagL()
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CUpnpElementFactory::IsMainObjectTagL(TXmlEngElement aElement)
+{
+ TXmlEngElement notNeeded;
+ return UpnpDomInterface::GetElementL(aElement, notNeeded, KClassTagName);
+}
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::ActiveElementL()
+// Gets active element from XML document. An active element
+// is a first element different from <DIDL-Lite> element.
+// -----------------------------------------------------------------------------
+//
+TXmlEngElement CUpnpElementFactory::ActiveElementL( const RXmlEngDocument& aDocument )
+{
+ if( aDocument.IsNull() || aDocument.DocumentElement().IsNull() )
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ if ( aDocument.DocumentElement().Name().CompareF( KDidlLite() ) != 0 )
+ {
+ return aDocument.DocumentElement();
+ }
+ else
+ {
+ TXmlEngElement root = aDocument.DocumentElement();
+ RXmlEngNodeList<TXmlEngElement> children;
+ CleanupClosePushL(children);
+ root.GetChildElements( children );
+ children.HasNext();
+ CleanupStack::PopAndDestroy(&children);
+ return children.Next();
+ }
+}
+
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::ExtractActiveElementL()
+// Extracts active element from XML document.
+// An active element is a first element different from <DIDL-Lite> element.
+// IMPORTANT: Caller takes responsibility for returned element.
+// -----------------------------------------------------------------------------
+//
+RXmlEngDocument CUpnpElementFactory::ExtractActiveElementL( const RXmlEngDocument& aDocument )
+{
+ TXmlEngElement active;
+ RXmlEngDocument ret;
+ ret.OpenL(iDOMImpl);
+ CleanupClosePushL(ret);
+
+ if( aDocument.IsNull() || aDocument.DocumentElement().IsNull() )
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ if ( aDocument.DocumentElement().Name().CompareF( KDidlLite() ) != 0 )
+ {
+ active = aDocument.DocumentElement().Unlink().AsElement();
+ }
+ else
+ {
+ TXmlEngElement root = aDocument.DocumentElement();
+ RXmlEngNodeList<TXmlEngElement> children;
+ CleanupClosePushL(children);
+ root.GetChildElements( children );
+ children.HasNext();
+ active = children.Next().Unlink().AsElement();
+ CleanupStack::PopAndDestroy(&children);
+ }
+ ret.SetDocumentElement(active);
+
+ CleanupStack::Pop(&ret);
+
+ return ret;
+}
+
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::ElementsMatchL()
+// Checks if two elements are equal and have exactly the same subtrees.
+// -----------------------------------------------------------------------------
+//
+TBool CUpnpElementFactory::ElementsMatchL( TXmlEngElement aFirst, TXmlEngElement aSecond )
+{
+ // this function checks following things:
+ // 1. element names
+ // 2. contents of the elements
+ // 3. attributes of the elements
+ // 4. child elements of the elements
+
+ if ( aFirst.Name().Compare(aSecond.Name()) == 0 )
+ {
+ // aFirst names match. next: check namespace
+ if ( aFirst.Prefix().Compare( aSecond.Prefix()) == 0 )
+ {
+ if (!aFirst.Text().Compare(aSecond.Text()))
+ {
+
+ // namespacess match, next: check attributes
+ RXmlEngNodeList<TXmlEngAttr> elemAttrs;
+ CleanupClosePushL(elemAttrs);
+ RXmlEngNodeList<TXmlEngAttr> currAttrs;
+ CleanupClosePushL(currAttrs);
+
+ aFirst.GetAttributes( elemAttrs );
+ aSecond.GetAttributes( currAttrs );
+
+ if ( elemAttrs.Count() == currAttrs.Count() )
+ {
+ // first step in comparing attributes ready (counts match!)
+ // next, check names and values (for each attribute)
+
+ while( elemAttrs.HasNext() && currAttrs.HasNext() )
+ {
+ TXmlEngAttr elemAttr = elemAttrs.Next();
+ TXmlEngAttr currAttr = currAttrs.Next();
+
+ // compare names and values
+ if ( elemAttr.Name().Compare( currAttr.Name() ) )
+ {
+ CleanupStack::PopAndDestroy(&currAttrs);
+ CleanupStack::PopAndDestroy(&elemAttrs);
+ return EFalse;
+ }
+ if ( elemAttr.Value().Compare( currAttr.Value() ) )
+ {
+ CleanupStack::PopAndDestroy(&currAttrs);
+ CleanupStack::PopAndDestroy(&elemAttrs);
+ return EFalse;
+ }
+
+ }
+
+ // compare child elements (recursive function call)
+ RXmlEngNodeList<TXmlEngElement> fChildren;
+ CleanupClosePushL(fChildren);
+ RXmlEngNodeList<TXmlEngElement> sChildren;
+ CleanupClosePushL(sChildren);
+
+ aFirst.GetChildElements( fChildren );
+ aSecond.GetChildElements( sChildren );
+
+
+ if ( fChildren.Count() == sChildren.Count() )
+ {
+ while ( fChildren.HasNext() && sChildren.HasNext() )
+ {
+ // call this function again for children
+ TBool matching = ElementsMatchL( fChildren.Next(), sChildren.Next() );
+
+ // if some of the elements do not match, return false!
+ if (matching == EFalse)
+ {
+ CleanupStack::PopAndDestroy(&sChildren);
+ CleanupStack::PopAndDestroy(&fChildren);
+ CleanupStack::PopAndDestroy(&currAttrs);
+ CleanupStack::PopAndDestroy(&elemAttrs);
+ return EFalse;
+ }
+ }
+ // only place to return ETrue
+ // all the checks are made; if survived here, elements match!
+ CleanupStack::PopAndDestroy(&sChildren);
+ CleanupStack::PopAndDestroy(&fChildren);
+ CleanupStack::PopAndDestroy(&currAttrs);
+ CleanupStack::PopAndDestroy(&elemAttrs);
+ return ETrue;
+ }
+ CleanupStack::PopAndDestroy(&sChildren);
+ CleanupStack::PopAndDestroy(&fChildren);
+ }
+ CleanupStack::PopAndDestroy(&currAttrs);
+ CleanupStack::PopAndDestroy(&elemAttrs);
+ }
+ }
+ }
+
+ return EFalse;
+}
+
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::CountElementsL()
+// Prepares corresponding RArray<TXmlEngElements> and calls
+// CountElementsL( const TDesC8& aName, RArray<TXmlEngElement>& aArray )
+// -----------------------------------------------------------------------------
+//
+TInt CUpnpElementFactory::CountElementsL( const TDesC8& aName, RArray<RXmlEngDocument>& aArray )
+{
+ TInt count(0);
+
+ for(TInt i = 0; i < aArray.Count(); i++)
+ {
+ if ( aArray[i].DocumentElement().NotNull() )
+ {
+ if ( aArray[i].DocumentElement().Name() == aName )
+ {
+ count++;
+ }
+ }
+
+ }
+ return count;
+}
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::CountElementsL()
+// Counts elements in array that have the same name.
+// -----------------------------------------------------------------------------
+//
+TInt CUpnpElementFactory::CountElementsL( const TDesC8& aName, RArray<TXmlEngElement>& aArray )
+{
+ TInt count(0);
+
+ for (TInt v(0); v<aArray.Count(); v++)
+ {
+ if ( aArray[v].NotNull() )
+ {
+ if ( aArray[v].Name() == aName )
+ {
+ count++;
+ }
+ }
+ }
+
+ return count;
+}
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::NameWithNsLC()
+// Constructs descriptor with element's name and namespace prefix separated with colon.
+// IMPORTANT: As the function name indicates, it leaves pointer to heap descriptor on
+// cleanup stack.
+// -----------------------------------------------------------------------------
+//
+HBufC8* CUpnpElementFactory::NameWithNsLC(const TXmlEngElement& aElement)
+{
+ const TDesC8& localName = aElement.Name();
+ TPtrC8 prefix = aElement.Prefix();
+
+ if ( prefix.Length() > 0)
+ {
+
+ HBufC8* nameWithNs = HBufC8::NewLC(
+ localName.Length() +
+ UpnpString::KColon().Length() +
+ prefix.Length() );
+
+ nameWithNs->Des().Append( prefix );
+ nameWithNs->Des().Append( UpnpString::KColon() );
+ nameWithNs->Des().Append( localName );
+
+ return nameWithNs;
+ }
+ else
+ {
+ return localName.AllocLC();
+ }
+}
+
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::ClassesL()
+// Gets classes descriptions for given object.
+// -----------------------------------------------------------------------------
+//
+void CUpnpElementFactory::ClassesL( const TXmlEngElement& aObject, RArray<TXmlEngElement>& aArray, const TDesC8& aObjType )
+{
+ TInt i(0);
+
+ // if survived here, we have the new element of type item or container
+ // let's analyze its type
+ TXmlEngElement type;
+ UpnpDomInterface::GetElementL ( aObject, type, KClass() );
+
+ if ( type.IsNull() )
+ {
+ // no <class> element! leave
+ User::Leave( EBadMetadata );
+ }
+
+ // check that does the new element have all the required fields for its type
+ // and also check that it does not have whatever fields (only optional allowed)
+ RPointerArray<TPtrC8> objectFields;
+
+ TPtrC8 content = type.Text();
+ if( !content.Length() )
+ {
+ User::Leave( EBadMetadata );
+ }
+ //--- removing white spaces ------------------
+ HBufC8* tempBuffer = type.Text().AllocLC();
+ TPtr8 tmpPtr(tempBuffer->Des());
+ UpnpCdUtils::RemoveWhiteSpacesL(tmpPtr);
+ CleanupStack::Check(tempBuffer);
+ type.SetTextL(tmpPtr);
+ //--------------------------------------------
+
+ UpnpString::CutToPiecesL(tmpPtr, TChar('.'), objectFields );
+ CleanupStack::Check(tempBuffer);
+ // let's inspect each of types
+ // at first, collect object type descriptions from objects xml
+ // to a pointer array
+
+ TInt NumberOfObjectFields = objectFields.Count();
+
+ for ( i=0; i < NumberOfObjectFields; i++ )
+ {
+ // seek for such object type
+ TXmlEngElement objectDescription;
+
+ UpnpDomInterface::GetDirectoryElementL(
+ iDocument.DocumentElement(),
+ objectDescription,
+ KElement,
+ KType,
+ *objectFields[i] );
+ CleanupStack::Check(tempBuffer);
+ // if such type found
+ if ( objectDescription.NotNull() )
+ {
+ aArray.Append( objectDescription );
+ }
+ /* This case is valid for any numeric value of containerID used in CreateObject() action
+ * We do some checking starting from 3rd string of <upnp:class> element, if the string isn't
+ * recognizable, instead of leaving, we trims the value of <upnp:class> element, e.g:
+ * 'object.item.imageItem.abcd' -> is trimmed into -> 'object.item.imageItem'
+ * DLNA 7.3.120.4 requirement
+ */
+ else if( i >= 2 )
+ {
+ for( TInt j = NumberOfObjectFields - 1; j >= i; j-- )
+ {
+ TInt pos = tmpPtr.LocateReverse( TChar('.') );
+ if( pos > KErrNotFound )
+ {
+ tmpPtr.Copy( tmpPtr.Left(pos) );
+
+ delete objectFields[j];
+ objectFields.Remove(j);
+ }
+ }
+ type.SetTextL(tmpPtr); // changing xml
+
+ break;
+ }
+ else
+ {
+ objectFields.ResetAndDestroy();
+ objectFields.Close();
+ User::Leave( EBadMetadata );
+ }
+ }
+ CleanupStack::Check(tempBuffer);
+ /* for each type, check that:
+ * 1. it is referenced to its current parent type (e.g. audioItem -> item)
+ * 2. this new object has all the required fields
+ * 3. relations between object types and values of 'upnp:class':
+ * <item> -> 'object.item' or <container> -> 'object.container'
+ */
+
+ // we count the number of elements once again, because size of the array might change
+ NumberOfObjectFields = objectFields.Count();
+
+ for ( i=0; i < NumberOfObjectFields; i++ )
+ {
+ const TDesC8& field = *objectFields[i];
+
+ // 1. first, check the parent relation
+ // first type must be "object"!
+ if ( i==0 )
+ {
+ /* Leave if:
+ * 1. first type isn't the 'object' OR
+ * 2. 'upnp:class' contains only 'object' type [which in matter of fact isn't instantiable]
+ */
+ if ( field != KObject() ||
+ field == KObject() && NumberOfObjectFields == 1
+ )
+ {
+ // if not "item", leave!
+ objectFields.ResetAndDestroy();
+ objectFields.Close();
+ User::Leave( EBadMetadata );
+ }
+ }
+ // for later types, check the relation really
+ else
+ {
+ // checking relations between object types and values of 'upnp:class'
+ if( i == 1 && aObjType.Length() > 0 )
+ {
+ if( !field.Compare(KItem) && aObjType.Compare(KItem) ||
+ !field.Compare(KContainer) && aObjType.Compare(KContainer)
+ )
+ {
+ objectFields.ResetAndDestroy();
+ objectFields.Close();
+ User::Leave( EBadMetadata );
+ }
+ }
+ //----------------------------------------
+ const TDesC8& parent = *objectFields[i-1];
+
+ // if we've survived to this point, this parent string
+ // should match with the one in the previous object description xml element
+ TXmlEngElement iparent;
+ UpnpDomInterface::GetElementL ( aArray[i], iparent, KIParent() );
+ CleanupStack::Check(tempBuffer);
+ TPtrC8 cont = iparent.Text();
+
+ // now check the actual relation. leave if strings do not match!
+ if ( cont.Length() && parent != cont )
+ {
+ objectFields.ResetAndDestroy();
+ objectFields.Close();
+ User::Leave( EBadMetadata );
+ }
+ }
+ }
+ CleanupStack::PopAndDestroy(tempBuffer);
+ objectFields.ResetAndDestroy();
+ objectFields.Close();
+ return;
+}
+
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::IsNotEmptyImportUriL()
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CUpnpElementFactory::IsNotEmptyImportUriL( const TXmlEngElement& aElement )
+{
+ TXmlEngAttr importUri;
+
+ if ( aElement.Name() == KRes() )
+ {
+ importUri = aElement.AttributeNodeL( KImportUri8() );
+
+ // remove if empty importUri: DLNA Requirement [7.3.134.5]
+ TPtrC8 val( importUri.Value() );
+ if( UpnpCdUtils::IsWhiteString( val ) )
+ {
+ importUri.Remove();
+ }
+ }
+
+ return importUri.NotNull();
+}
+
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::IsClassElement()
+// (other items were commented in a header).
+// -----------------------------------------------------------------------------
+//
+TBool CUpnpElementFactory::IsClassElement( const TXmlEngElement& aElement )
+{
+ if ( aElement.Name() == KClass() )
+ {
+ return ETrue;
+ }
+ else
+ {
+ return EFalse;
+ }
+}
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::ValidateProtocolInfoInResL
+// Allocates string, which is object type for this object.
+// -----------------------------------------------------------------------------
+HBufC8* CUpnpElementFactory::ValidateProtocolInfoInResL( const TDesC8& aProtocolInfo, TBool aLocalSharing )
+{
+ HBufC8* result = NULL;
+ // CUpnpDlnaProtocolInfo* protocolInfo = CUpnpDlnaProtocolInfo::NewL( (TDesC8&)aProtocolInfo );
+ CUpnpProtocolInfoLocal* protocolInfo = CUpnpProtocolInfoLocal::NewL( (TDesC8&)aProtocolInfo );
+ CleanupStack::PushL( protocolInfo );
+ _LIT8(KProtocolInfoHttpGet, "http-get");
+ protocolInfo->SetFirstFieldL( (TDesC8&)KProtocolInfoHttpGet() );
+ protocolInfo->SetSecondFieldL( (TDesC8&)KAsterisk8() );
+ TPtrC8 third = protocolInfo->ThirdField();
+ if(( third.Find( KSlash8()) == KErrNotFound) &&
+ ( third.Compare( KAsterisk8()) != KErrNone))
+ {
+ if( aLocalSharing)
+ {
+ User::Leave( EBadMetadata );
+ }
+ protocolInfo->SetThirdFieldL( (TDesC8&) KAsterisk8());
+ }
+ // if( protocolInfo->IsDlnaInformationIncluded() ) // Check it !!!
+ {
+ protocolInfo->SetOpParameterL( UpnpDlnaProtocolInfo::B_VAL , ETrue );
+ protocolInfo->SetOpParameterL( UpnpDlnaProtocolInfo::A_VAL , EFalse );
+ }
+ TPtrC8 prInfo = protocolInfo->ProtocolInfoL();
+ result = prInfo.Alloc();
+ CleanupStack::PopAndDestroy( protocolInfo );
+ return result;
+}
+
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::GetContentDirectoryReference
+// Function gets pointer to CUpnpContentDirectory and puts it into CUpnpElementFactory object
+// -----------------------------------------------------------------------------
+void CUpnpElementFactory::GetContentDirectoryReference(CUpnpContentDirectory* aCD)
+{
+ iContentDirectory = aCD;
+}
+
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::CheckDurationOfResElement
+// If res@duration attribute exists, the method checks whether it has valid format
+// -----------------------------------------------------------------------------
+
+void CUpnpElementFactory::CheckDurationOfResElementL(const TXmlEngElement& aElement)
+{
+ TXmlEngAttr duration;
+
+ // if this is the 'res' element
+ if( aElement.Name() == KRes() )
+ {
+ // and it has res@duration attribute
+ duration = aElement.AttributeNodeL( KDuration8() );
+ if( duration.NotNull() )
+ {
+ TCurrentAction action = iContentDirectory->ExecutedAction();
+ TPtrC8 val( duration.Value() );
+
+ // if res@duration atrribute value is invalid [has improper format]
+ if( !UpnpCdUtils::ValidateDurationValue(val) )
+ {
+ // remove it from 'res' element if it is CreateObject()
+ if( action == ECreateObjectAction )
+ {
+ duration.Remove();
+ }
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+// CUpnpElementFactory::CheckSizeOfResElement
+// If res@size attribute exists, the method checks whether it has valid format
+// size should be unsigned int.
+// -----------------------------------------------------------------------------
+void CUpnpElementFactory::CheckSizeOfResElementL(
+ const TXmlEngElement& aElement )
+ {
+ TXmlEngAttr sizeAttr;
+
+ // if this is the 'res' element
+ if ( aElement.Name() == KRes() )
+ {
+ // and it has res@size attribute
+ sizeAttr = aElement.AttributeNodeL( KSize() );
+ if ( sizeAttr.NotNull() )
+ {
+ TCurrentAction action = iContentDirectory->ExecutedAction();
+ TPtrC8 val( sizeAttr.Value() );
+
+ // if res@size atrribute value is invalid [is not an unsigned long]
+ TUint32 unsignedLong = 0;
+
+ TLex8 lexULong(val);
+ TInt error = lexULong.Val( unsignedLong, EDecimal );
+
+ TInt remainder = lexULong.Remainder().Length();
+
+ if ( error != KErrNone || remainder )
+ {
+ // remove it from 'res' element if it is CreateObject()
+ if ( action == ECreateObjectAction )
+ {
+ sizeAttr.Remove();
+ }
+ }
+ }
+ }
+
+ }
+
+// End of File