diff -r 3785f754ee62 -r 5360b7ddc251 upnpmediaserver/contentdirectoryservice/src/upnpelementfactory.cpp --- a/upnpmediaserver/contentdirectoryservice/src/upnpelementfactory.cpp Fri Sep 17 08:31:21 2010 +0300 +++ b/upnpmediaserver/contentdirectoryservice/src/upnpelementfactory.cpp Mon Nov 01 12:37:49 2010 +0200 @@ -1,1474 +1,1538 @@ -/** @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 -#include -#include - -#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* array = (RArray*) 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 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 children; - CleanupClosePushL(children); - object.GetChildElements( children ); - - // an exception: we can't have nestEls; - CleanupClosePushL(nestEls); - el.GetChildElements(nestEls); - while(nestEls.HasNext()) - { - TXmlEngElement nestPs = nestEls.Next(); - - // take the properties - RXmlEngNodeList 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& aClassList) -{ - // validate main object's attributes - ValidateMainAttributesL(aObj, aClassList); - - // validate elements - RXmlEngNodeList 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 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& 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& aClassList) -{ - // list of attributes - RXmlEngNodeList 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& aClassList) -{ - // list of attributes - RXmlEngNodeList 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& 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& 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 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 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 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 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 elemAttrs; - CleanupClosePushL(elemAttrs); - RXmlEngNodeList 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 fChildren; - CleanupClosePushL(fChildren); - RXmlEngNodeList 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 and calls -// CountElementsL( const TDesC8& aName, RArray& aArray ) -// ----------------------------------------------------------------------------- -// -TInt CUpnpElementFactory::CountElementsL( const TDesC8& aName, RArray& 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& aArray ) -{ - TInt count(0); - - for (TInt v(0); v 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& 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 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 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.AppendL( objectDescription ); - } - /* This case is valid for any numeric value of containerID used in CreateObject() action - * We do some checking starting from 3rd string of element, if the string isn't - * recognizable, instead of leaving, we trims the value of 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': - * -> 'object.item' or -> '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 +/** @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 +#include +#include + +#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* array = (RArray*) 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)); + + // Load dll file + TFileName objectsXmlFileName( KObjectsXmlFileName() ); + TFileName dllName; + Dll::FileName( dllName ); + TBuf<2> drive = dllName.Left( 2 ); // Drive letter followed by ':' + objectsXmlFileName.Insert( 0, drive ); + + TParse fp; + fp.Set(objectsXmlFileName,&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::CheckRestrictedValue() +// ----------------------------------------------------------------------------- +// +TBool CUpnpElementFactory::CheckRestrictedValue (TPtrC8& restrVal) + { + TBool retVal = EFalse; + + if ( + (UpnpCD::Kfalse().Compare( restrVal ) != 0) && + (UpnpCD::KZero().Compare( restrVal ) != 0) && + (UpnpCD::Ktrue().Compare( restrVal ) != 0) && + (UpnpCD::KOne().Compare( restrVal ) != 0) + ) + { + retVal = ETrue; + } + return retVal; + } + + +// ----------------------------------------------------------------------------- +// 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 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 (CheckRestrictedValue(restrVal)) + { + User::Leave ( EBadMetadata); + } + + // for convenience later, take now a reference to the children of the object + RXmlEngNodeList children; + CleanupClosePushL(children); + object.GetChildElements( children ); + + // an exception: we can't have nestEls; + CleanupClosePushL(nestEls); + aEl.GetChildElements(nestEls); + CheckNestedElementsL(nestEls, child, aLocalSharing); + CleanupStack::PopAndDestroy(&nestEls); + } + CleanupStack::PopAndDestroy( nameWithNs ); + + } + + return elementFound; +} + + +void CUpnpElementFactory::CheckNestedElementsL(RXmlEngNodeList aNestEls, TXmlEngElement aChild, + TBool aLocalSharing) +{ + HBufC8* nameWithNs = NameWithNsLC( aChild ); + while(aNestEls.HasNext()) + { + TXmlEngElement nestPs = aNestEls.Next(); + + // take the properties + RXmlEngNodeList 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( aChild, nestElementName ); + + TPtrC8 nameOfAttr; + TPtrC8 valOfAttr; + nameOfAttr.Set( nestElementName ); + + // Start of 'dlna:profileID' attribute case + if( nameWithNs->Des() == KAlbumArtURI && nestElementName == KDlnaProfileID) // ---------------- 1 ------------ + { + TXmlEngAttr profId = aChild.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(aChild).AllocLC(); + TPtr8 albumArtURIelemValuePtr( albumArtURIelemValue->Des() ); + + albumArtURIelemValuePtr.Trim(); // deletes leading and trailing whitespace characters + aChild.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 + aChild.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() ); + } + + aChild.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 ); + aChild.SetAttributeL( nameOfAttr, valOfAttr ); + CleanupStack::PopAndDestroy( protInfoValue ); + } //------- 3 ----- //------- 3 ----- + } + } + + + // if not main tag mark the attr is required + if( !IsMainObjectTagL(aChild) && nestElementName != KDlnaProfileID) + { + + HBufC8* attrReq = HBufC8::NewLC( + nestElementName.Length() + +KRequiredAtrSuf().Length() ); + TPtr8 attrReqPtr(attrReq->Des()); + attrReqPtr = nestElementName; + attrReqPtr.Append(KRequiredAtrSuf); + aChild.AddNewAttributeL( attrReqPtr, KTrueValue8 ); + CleanupStack::PopAndDestroy(attrReq); + } + } + } + } + + } +} + +void CUpnpElementFactory::ValidateAttributeL(TXmlEngElement aElement, TXmlEngElement aObject) + { + + const TDesC8& required = UpnpDomInterface::GetAttrValueL( aElement, KRequiredObject() ); + if ( required == UpnpCD::KOne() ) + { + + const TDesC8& elementName = UpnpDomInterface::GetAttrValueL( aElement, KName() ); + + const TDesC8& currentValue = UpnpDomInterface::GetAttrValueL( aObject, elementName ); + + if ( !currentValue.Length() ) + { + TXmlEngAttr attr = aObject.AttributeNodeL( elementName ); + + if(attr.NotNull()) + { + attr.SetValueL(KNullDesC8); + } + else + { + aObject.AddNewAttributeL( elementName, KNullDesC8 ); + } + } + // if not main tag mark the attr is required + if(!IsMainObjectTagL(aObject)) + { + HBufC8* attrReq = HBufC8::NewLC( + elementName.Length()+KRequiredAtrSuf().Length() ); + TPtr8 attrReqPtr(attrReq->Des()); + attrReqPtr = elementName; + attrReqPtr.Append(KRequiredAtrSuf); + aObject.AddNewAttributeL( attrReqPtr, KTrueValue8 ); + CleanupStack::PopAndDestroy(attrReq); + } + } + } + +// ----------------------------------------------------------------------------- +// CUpnpElementFactory::ValidatePropertiesL() +// Function leaves on error. +// ----------------------------------------------------------------------------- +// +void CUpnpElementFactory::ValidatePropertiesL( TXmlEngElement aObj, + RArray& aClassList) +{ + // validate main object's attributes + ValidateMainAttributesL(aObj, aClassList); + + // validate elements + RXmlEngNodeList 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 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& 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& aClassList) +{ + // list of attributes + RXmlEngNodeList 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& aClassList) +{ + // list of attributes + RXmlEngNodeList 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& 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& 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 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 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 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 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 elemAttrs; + CleanupClosePushL(elemAttrs); + RXmlEngNodeList 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 fChildren; + CleanupClosePushL(fChildren); + RXmlEngNodeList 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 and calls +// CountElementsL( const TDesC8& aName, RArray& aArray ) +// ----------------------------------------------------------------------------- +// +TInt CUpnpElementFactory::CountElementsL( const TDesC8& aName, RArray& 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& aArray ) +{ + TInt count(0); + + for (TInt v(0); v 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(); + } +} + +void CUpnpElementFactory::CheckElementValidity (TXmlEngElement& aElement) +{ + if ( aElement.IsNull() ) + { + // no 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) + + TPtrC8 content = aElement.Text(); + if( !content.Length() ) + { + User::Leave( EBadMetadata ); + } +} + + +// ----------------------------------------------------------------------------- +// CUpnpElementFactory::ClassesL() +// Gets classes descriptions for given object. +// ----------------------------------------------------------------------------- +// +void CUpnpElementFactory::ClassesL( const TXmlEngElement& aObject, RArray& 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() ); + + CheckElementValidity (type); + RPointerArray objectFields; + + //--- 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 element, if the string isn't + * recognizable, instead of leaving, we trims the value of 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': + * -> 'object.item' or -> '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