upnpmediaserver/contentdirectoryservice/src/upnpelementfactory.cpp
changeset 0 7f85d04be362
child 25 52826dcbed74
equal deleted inserted replaced
-1:000000000000 0:7f85d04be362
       
     1 /** @file
       
     2 * Copyright (c) 2005-2006 Nokia Corporation and/or its subsidiary(-ies). 
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies  this distribution, and is available 
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  Element Factory.
       
    15 *
       
    16 */
       
    17  
       
    18 
       
    19 // INCLUDE FILES
       
    20 #include <sysutil.h>
       
    21 #include <uri8.h>
       
    22 #include <xmlengdomparser.h>
       
    23 
       
    24 #include "upnpelementfactory.h"
       
    25 #include "upnpcontentdirectoryglobals.h"
       
    26 #include "upnpstring.h"
       
    27 #include "upnpprotocolinfo.h"
       
    28 #include "upnpcommonupnplits.h"
       
    29 #include "upnpcdutils.h"
       
    30 #include "upnpprotocolinfolocal.h"
       
    31 
       
    32 using namespace UpnpDlnaProtocolInfo;
       
    33 
       
    34 // ============================= LOCAL FUNCTIONS ===============================
       
    35 // -----------------------------------------------------------------------------
       
    36 // DestroyRPointerArray
       
    37 // Used by TCleanupItem to destroy array
       
    38 // -----------------------------------------------------------------------------
       
    39 //
       
    40 void DestroyRArray(TAny* aArray)
       
    41 {
       
    42     RArray<RXmlEngDocument>* array = (RArray<RXmlEngDocument>*) aArray;
       
    43     for(TInt i = 0; i < array->Count(); i++ )
       
    44             (*array)[i].Close();
       
    45     (*array).Close();
       
    46 }
       
    47 
       
    48 // ============================ MEMBER FUNCTIONS ===============================
       
    49 
       
    50 // -----------------------------------------------------------------------------
       
    51 // CUpnpElementFactory::~CUpnpElementFactory()
       
    52 // C++ default destructor. (virtual destructor)
       
    53 // -----------------------------------------------------------------------------
       
    54 //
       
    55 CUpnpElementFactory::~CUpnpElementFactory()
       
    56 {
       
    57     //Close XML document
       
    58     iDocument.Close();
       
    59     
       
    60     iDOMImpl.Close(); 
       
    61 }
       
    62 
       
    63 // -----------------------------------------------------------------------------
       
    64 // CUpnpElementFactory::NewL()
       
    65 // Two-phased constructor
       
    66 // -----------------------------------------------------------------------------
       
    67 //
       
    68 CUpnpElementFactory* CUpnpElementFactory::NewL( const TDesC& aObjectsXmlPath )
       
    69 {
       
    70     CUpnpElementFactory* self = CUpnpElementFactory::NewLC( aObjectsXmlPath );
       
    71     CleanupStack::Pop( self );
       
    72     return self;
       
    73 }
       
    74 // -----------------------------------------------------------------------------
       
    75 // CUpnpElementFactory::NewLC()
       
    76 // Two-phased constructor
       
    77 // -----------------------------------------------------------------------------
       
    78 //
       
    79 CUpnpElementFactory* CUpnpElementFactory::NewLC( const TDesC& aObjectsXmlPath )
       
    80 {
       
    81     CUpnpElementFactory* self = new (ELeave) CUpnpElementFactory();
       
    82     CleanupStack::PushL( self );
       
    83     self->ConstructL( aObjectsXmlPath );
       
    84     return self;
       
    85 }
       
    86 
       
    87 // -----------------------------------------------------------------------------
       
    88 // CUpnpElementFactory::ConstructL()
       
    89 // Two-phased constructor
       
    90 // -----------------------------------------------------------------------------
       
    91 //
       
    92 void CUpnpElementFactory::ConstructL(const TDesC& aObjectsXmlPath)
       
    93 {
       
    94 
       
    95     iDOMImpl.OpenL();
       
    96 
       
    97     RXmlEngDOMParser parser;
       
    98     User::LeaveIfError( parser.Open(iDOMImpl) );
       
    99     CleanupClosePushL(parser);
       
   100     
       
   101     if ( aObjectsXmlPath == KNullDesC() )
       
   102         {
       
   103         RFs fs;
       
   104         User::LeaveIfError(fs.Connect());
       
   105         CleanupClosePushL(fs);
       
   106 
       
   107         TFileName path;
       
   108         User::LeaveIfError(fs.PrivatePath(path));
       
   109 
       
   110         TParse fp;
       
   111         fp.Set(KObjectsXmlFileName(),&path, 0);
       
   112         path = fp.FullName();
       
   113 
       
   114         iDocument = parser.ParseFileL( path );        
       
   115         CleanupStack::PopAndDestroy(&fs);
       
   116         }
       
   117     else
       
   118         {
       
   119         iDocument = parser.ParseFileL( aObjectsXmlPath );                
       
   120         }
       
   121         
       
   122     
       
   123 
       
   124     CleanupStack::PopAndDestroy(&parser);
       
   125 }
       
   126 // -----------------------------------------------------------------------------
       
   127 // CUpnpElementFactory::CUpnpElementFactory()
       
   128 // Default constructor
       
   129 // -----------------------------------------------------------------------------
       
   130 //
       
   131 CUpnpElementFactory::CUpnpElementFactory()
       
   132 {
       
   133 
       
   134 }
       
   135 
       
   136 // -----------------------------------------------------------------------------
       
   137 // CUpnpElementFactory::ValidateNewObjectL()
       
   138 // Function to validate a new object given by Control Point, especially 
       
   139 // upnp:class element field eg. object.item.musictrack
       
   140 // IMPORTANT: If objects's description is invalid due to missing elements
       
   141 // it tries to repair it by adding those missing elements.
       
   142 // -----------------------------------------------------------------------------
       
   143 //
       
   144 
       
   145 TUpnpErrorCode CUpnpElementFactory::ValidateNewObjectL( const TXmlEngElement& aNewElement, TBool aNew, TBool aLocalSharing)
       
   146 {
       
   147     TInt i;    
       
   148     TPtrC8 objectType = KItem();
       
   149 
       
   150     RXmlEngNodeList<TXmlEngElement> elements;
       
   151     CleanupClosePushL(elements);
       
   152     aNewElement.GetChildElements( elements );
       
   153     
       
   154     // invalid element if the count of the objects is less than 1 (=0)
       
   155     if ( elements.Count() != 1 )
       
   156     {
       
   157         User::Leave( EInvalidArgs );
       
   158     }
       
   159     CleanupStack::PopAndDestroy(&elements);
       
   160     // try to find the new item from the xml
       
   161     TXmlEngElement object;
       
   162     UpnpDomInterface::GetElementL( aNewElement, object, KItem() );
       
   163     if ( object.IsNull() ) 
       
   164     {   
       
   165         
       
   166         // if it's not an item, it's a container
       
   167         UpnpDomInterface::GetElementL( aNewElement, object, KContainer() );
       
   168         if ( object.IsNull() )
       
   169         {
       
   170             // not even a container, leave!
       
   171             User::Leave ( EInvalidArgs );
       
   172         }
       
   173         objectType.Set( KContainer() );
       
   174     }
       
   175                            
       
   176     // restriced value
       
   177     TPtrC8 restrVal = UpnpDomInterface::GetAttrValueL( object,  KRestricted );
       
   178     if ( 
       
   179     (UpnpCD::Kfalse().Compare( restrVal ) != 0) &&
       
   180     (UpnpCD::KZero().Compare( restrVal ) != 0) &&
       
   181     (UpnpCD::Ktrue().Compare( restrVal ) != 0) &&
       
   182     (UpnpCD::KOne().Compare( restrVal ) != 0)
       
   183     )
       
   184     {
       
   185         User::Leave( EBadMetadata );
       
   186     }
       
   187     
       
   188     // for convenience later, take now a reference to the children of the object
       
   189     RXmlEngNodeList<TXmlEngElement> children;
       
   190     CleanupClosePushL(children);
       
   191     object.GetChildElements( children );
       
   192             
       
   193     // an exception: we can't have <res importUri=".. element in 
       
   194     // a new object (set by control point)
       
   195     while ( children.HasNext() )
       
   196     {
       
   197         TXmlEngElement child = children.Next();
       
   198         
       
   199         if ( IsNotEmptyImportUriL( child ) && aNew ) 
       
   200         {
       
   201             User::Leave ( EBadMetadata );
       
   202         }
       
   203         
       
   204         //---- check res@duration, 7.3.22 MM DIDL-Lite res@duration Format        
       
   205         CheckDurationOfResElementL(child);
       
   206         CheckSizeOfResElementL(child);
       
   207                     
       
   208         RXmlEngNodeList<TXmlEngElement> forbiddenChildren;
       
   209         CleanupClosePushL(forbiddenChildren);
       
   210         child.GetChildElements( forbiddenChildren );
       
   211 
       
   212         if ( forbiddenChildren.HasNext() 
       
   213             && child.Name() != KVendorDescriptor ) // ignore <desc></desc>
       
   214         {
       
   215             User::Leave ( EBadMetadata );
       
   216         }
       
   217         CleanupStack::PopAndDestroy(&forbiddenChildren);
       
   218         if ( child.Name() == KDate8() )
       
   219         {
       
   220             if (!UpnpCdUtils::ValidateDateL(child.Value())) 
       
   221              child.Remove();
       
   222         }
       
   223         
       
   224     }
       
   225 
       
   226     // if survived here, we have the new element of type item or container
       
   227     // let's analyze its type
       
   228 
       
   229     // let's inspect each of types
       
   230     // at first, collect object type descriptions from objects xml    
       
   231     // to a pointer array
       
   232     RArray<TXmlEngElement> objectDescrs;
       
   233     CleanupClosePushL( objectDescrs );
       
   234     // store class descriptor elements in this array
       
   235     ClassesL( object, objectDescrs, objectType );
       
   236     
       
   237     // validate each separately
       
   238     
       
   239     ValidatePropertiesL(object, objectDescrs);
       
   240     if(aNew)
       
   241     {
       
   242         ValidateBigImageL(object);
       
   243     }
       
   244     
       
   245     // for each type, check that 
       
   246     // this new object has all the required fields
       
   247         
       
   248     for (i=0; i<objectDescrs.Count(); i++)
       
   249     {
       
   250         // now we have to go through all the fields of the new item
       
   251         // first, for convenience take a pointer to <ps>(properties) element
       
   252         
       
   253         RXmlEngNodeList<TXmlEngElement> propElems;
       
   254         CleanupClosePushL(propElems);
       
   255         objectDescrs[i].GetChildElements( propElems );
       
   256     
       
   257 
       
   258         while ( propElems.HasNext() )
       
   259         {
       
   260             
       
   261             TXmlEngElement ps = propElems.Next(); // ps stands for properties
       
   262             if ( ps.Name() == KProperties() )
       
   263             {
       
   264 
       
   265                 // take the properties
       
   266                 RXmlEngNodeList<TXmlEngElement> properties;
       
   267                 CleanupClosePushL(properties);
       
   268                 ps.GetChildElements( properties );
       
   269         
       
   270                 const TDesC8& propertyType = UpnpDomInterface::GetAttrValueL( ps, KType() );
       
   271 
       
   272                 TBool elementFound;
       
   273                 
       
   274 
       
   275                 // check each property
       
   276                 while ( properties.HasNext() )
       
   277                 {
       
   278                     
       
   279                     TXmlEngElement el = properties.Next();
       
   280 
       
   281                     // Validate element
       
   282                     if ( propertyType == KElement() )
       
   283                     {
       
   284                         elementFound = EFalse;
       
   285                         
       
   286                         // Check if this element is requiered
       
   287                         const TDesC8& required = UpnpDomInterface::GetAttrValueL( el, KRequiredObject() );
       
   288 
       
   289                         TPtrC8 elementName = UpnpDomInterface::GetAttrValueL( el, KName() );
       
   290 
       
   291                         // If it's required then check it's existence
       
   292 
       
   293                         if ( required == UpnpCD::KOne() || elementName == KRes()  ||  elementName == KAlbumArtURI() )
       
   294                         {
       
   295                         if( !KRes().Compare(elementName) ||  !KAlbumArtURI().Compare(elementName))
       
   296                         {
       
   297                             elementFound = ETrue;
       
   298                         }
       
   299                             // get children once more, because this kind of list does not have any reset function
       
   300                             object.GetChildElements( children );
       
   301                             while ( children.HasNext() )
       
   302                             {
       
   303                                 
       
   304                                 TXmlEngElement child = children.Next();
       
   305                                 
       
   306                                 HBufC8* nameWithNs = NameWithNsLC( child );
       
   307 
       
   308                                 if ( *nameWithNs == elementName )
       
   309                                 {
       
   310                                     // local sharing
       
   311                                     if(aNew && *nameWithNs == KRes)
       
   312                                     {
       
   313                                         TUriParser8 up;
       
   314                                         TPtrC8 rv(child.Text());
       
   315                                         if(rv.Length())
       
   316                                         {
       
   317                                             User::LeaveIfError( up.Parse(child.Text()) );
       
   318                                             TPtrC8 path( up.Extract(EUriPath) );
       
   319                                             TPtrC8 scheme( up.Extract(EUriScheme) );
       
   320 
       
   321                                             if(aLocalSharing)
       
   322                                             { // local action
       
   323                                                 if( scheme == UpnpHTTP::KSchemeFile8())
       
   324                                                 {
       
   325                                                     // The path can be: /c:/....
       
   326                                                     // or /c/... - without colon.
       
   327                                                     // Both situation are correct but 
       
   328                                                     // in further operations we assume 
       
   329                                                     // there is not any colon next to the drive letter.
       
   330                                                     // Therefore, remove it if second element of path table equals ':'
       
   331                                                     if(path[2] == KColon8()[0])
       
   332                                                     { // There IS a colon next to the drive letter.
       
   333                                                         // Here is an example uri:
       
   334                                                         // file:///c:/...
       
   335                                                         // As you can see the second colon must be removed
       
   336                                                         HBufC8* uri = child.Text().AllocLC();
       
   337                                                         TPtr8 uriPtr(uri->Des());
       
   338                                                         TPtrC8 tmp(uri->Des());
       
   339                                                         TInt second = 2;
       
   340                                                         TInt colonPos = 0;
       
   341                                                         for(TInt i = 0; i < second; i++)
       
   342                                                         {
       
   343                                                             colonPos += tmp.Find(KColon8) + 1;
       
   344                                                             tmp.Set( uriPtr.Mid(colonPos) );                                                    
       
   345                                                         }
       
   346                                                         // remove the colon
       
   347                                                         uriPtr.Replace(colonPos - 1, KColon8().Length(), KNullString8);
       
   348                                                         // set TXmlEngElement value
       
   349                                                         child.SetTextL(uriPtr);
       
   350                                                         
       
   351                                                         // clean up             
       
   352                                                         CleanupStack::PopAndDestroy(uri);                                               
       
   353                                                     }
       
   354                         
       
   355                                                     // check other  restrictions
       
   356                                                     TUriParser8 up;
       
   357                                                     User::LeaveIfError( up.Parse(child.Text()) );
       
   358                                                     TPtrC8 path( up.Extract(EUriPath) );
       
   359 
       
   360                                                     // sharing from Z: drive is forbidden
       
   361                                                     // second character is a drive letter
       
   362                                                     if(path[1] == KForbiddenDrivez()[0] || path[1] == KForbiddenDriveZ()[0])
       
   363                                                     {
       
   364                                                         User::Leave(EArgumentValue);
       
   365                                                     }
       
   366                                                     
       
   367                                                     // cannot share from private directory
       
   368                                                     if(!path.Match(KForbiddenPrivatePattern))
       
   369                                                     {
       
   370                                                         User::Leave(EArgumentValue);
       
   371                                                     }
       
   372                                                     
       
   373                                                 }
       
   374                                             }
       
   375                                             else
       
   376                                             { // not local action
       
   377                                                 // "file" schema is forbidden here
       
   378                                                 if(scheme == UpnpHTTP::KSchemeFile8())
       
   379                                                 {
       
   380                                                     User::Leave(EArgumentValue);
       
   381                                                 }
       
   382                                             }
       
   383                                         }
       
   384                                     }
       
   385 
       
   386 
       
   387                                     if ( elementFound ) 
       
   388                                     {
       
   389                                         // multiple values for one element!
       
   390                                         const TDesC8& multiple = UpnpDomInterface::GetAttrValueL( el, KMultiple() );
       
   391                                         
       
   392                                         // if it's not allowed for this element, leave!
       
   393                                         if ( !multiple.Length() )
       
   394                                         {
       
   395                                             User::Leave( EInvalidArgs );
       
   396                                         }
       
   397                                     }
       
   398                                     elementFound = ETrue;
       
   399                                     // mark the element required - if not res
       
   400                                     if( KRes().Compare(elementName) && KAlbumArtURI().Compare(elementName))
       
   401                                     {
       
   402                                         child.AddNewAttributeL(KRequiredAtrName,KTrueValue8);
       
   403                                     }
       
   404                                     
       
   405                                     // nested validation 
       
   406                                     RXmlEngNodeList<TXmlEngElement> nestEls;
       
   407                                     CleanupClosePushL(nestEls);
       
   408                                     el.GetChildElements(nestEls);
       
   409                                     while(nestEls.HasNext())
       
   410                                     {
       
   411                                         TXmlEngElement nestPs = nestEls.Next();
       
   412 
       
   413                                         // take the properties
       
   414                                         RXmlEngNodeList<TXmlEngElement> nestProperties;
       
   415                                         nestPs.GetChildElements( nestProperties );
       
   416                                         const TDesC8& nestPropertyType = UpnpDomInterface::GetAttrValueL( nestPs, KType() );
       
   417                                         // Validate attribute   
       
   418                                         if ( nestPropertyType == KAttribute() )
       
   419                                         {
       
   420                                             while(nestProperties.HasNext())
       
   421                                             {   
       
   422                                                 TXmlEngElement nestEl = nestProperties.Next();
       
   423                                                 //TBool nestElementFound;
       
   424 
       
   425                                                 //nestElementFound = EFalse;
       
   426                                                 
       
   427                                                 const TDesC8& nestRequired = UpnpDomInterface::GetAttrValueL( nestEl, KRequiredObject() );
       
   428                                                 TPtrC8 nestElementName = UpnpDomInterface::GetAttrValueL( nestEl, KName() );
       
   429                                                 if ( nestRequired == UpnpCD::KOne() || nestElementName == KDlnaProfileID)
       
   430                                                 {
       
   431                                                     TPtrC8 nestCurrentValue = UpnpDomInterface::GetAttrValueL( child, nestElementName );
       
   432                                                     
       
   433                                                     TPtrC8 nameOfAttr;
       
   434                                                     TPtrC8 valOfAttr;
       
   435                                                     nameOfAttr.Set( nestElementName );
       
   436                                                     
       
   437                                                     // Start of 'dlna:profileID' attribute case                                                 
       
   438                                                     if( nameWithNs->Des() == KAlbumArtURI && nestElementName == KDlnaProfileID) // ---------------- 1 ------------
       
   439                                                     {   
       
   440                                                         TXmlEngAttr profId = child.AttributeNodeL(KProfileID, KXmlnsDlna);
       
   441                                                         if(profId.NotNull())
       
   442                                                         {
       
   443                                                             if (profId.Value().Compare(KDefaultProfileID))
       
   444                                                             {
       
   445                                                                 User::Leave( EBadMetadata );
       
   446                                                             }
       
   447                                                             // setting real name of attribute -> localName
       
   448                                                             nestElementName.Set(KProfileID); // descriptor  
       
   449                                                             nameOfAttr.Set( nestElementName ); // related TString
       
   450                                                                                                                                                                                                                                                                                             
       
   451                                                             // generating a new value of 'dlna:profileID'
       
   452                                                             HBufC8* albumArtURIelemValue = UpnpDomInterface::GetElementValueL(child).AllocLC();
       
   453                                                             TPtr8 albumArtURIelemValuePtr( albumArtURIelemValue->Des() );                                                       
       
   454                                                             
       
   455                                                             albumArtURIelemValuePtr.Trim(); // deletes leading and trailing whitespace characters                                                   
       
   456                                                             child.SetValueL(albumArtURIelemValuePtr); // sets new trimmed value to albumArtURI
       
   457                                                                                                                                                         
       
   458                                                             CUpnpDlnaProtocolInfo* tempProtocolInfo = NULL;
       
   459                                                             TInt error = iContentDirectory->GetProtocolInfoL( albumArtURIelemValuePtr, tempProtocolInfo );
       
   460                                                             TPtrC8 tempPnParam;
       
   461                                                             if( error >=0 )
       
   462                                                             {
       
   463                                                                 tempPnParam.Set( tempProtocolInfo->PnParameter() );
       
   464                                                                     
       
   465                                                                 nestCurrentValue.Set(tempPnParam); // descriptor
       
   466                                                                 valOfAttr.Set(tempPnParam); // related TString                                                         
       
   467                                                             }
       
   468                                                             else 
       
   469                                                             {
       
   470                                                                 User::Leave( EBadMetadata );
       
   471                                                             }                                                       
       
   472                                                             CleanupStack::PopAndDestroy(albumArtURIelemValue);
       
   473                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
       
   474                                                             // if albumArtURI doesn't contain profileID -> it creates one and also related namespace
       
   475                                                             // if albumArtURI contains profileID -> it modifies profileID's value
       
   476                                                             child.SetAttributeL( nameOfAttr, valOfAttr, KXmlnsDlna(), KDlnaPrefix() );
       
   477                                                                                                                     
       
   478                                                             delete tempProtocolInfo;
       
   479                                                             tempProtocolInfo = NULL;    
       
   480                                                         }
       
   481                                                         
       
   482                                                     } // End of 'dlna:profileID' attribute case
       
   483                                                     else                    
       
   484                                                     {
       
   485                                                         if ( !nestCurrentValue.Length() )  
       
   486                                                         {
       
   487                                                             
       
   488                                                             if(nestElementName == KprotocolInfo)
       
   489                                                             {
       
   490                                                                 if( ! aLocalSharing )
       
   491                                                                 {
       
   492                                                                     valOfAttr.Set( KEmptyProtocolInfoVal8() );
       
   493                                                                 }
       
   494                                                                 else 
       
   495                                                                 {
       
   496                                                                     User::Leave( EBadMetadata );
       
   497                                                                 }
       
   498                                                             }                                                                                                   //------- 2 -----                                                                                    //------- 2 -----                  
       
   499                                                             else
       
   500                                                             {
       
   501                                                                 valOfAttr.Set( KNullDesC8() );
       
   502                                                             }
       
   503                                 
       
   504                                                             child.AddNewAttributeL( nameOfAttr, valOfAttr );                                                            
       
   505                                                         }
       
   506                                                         else 
       
   507                                                         {
       
   508                                                             if(nestElementName == KprotocolInfo) 
       
   509                                                             {
       
   510                                                                 HBufC8* protInfoValue = NULL;
       
   511                                                                 TRAPD(err, protInfoValue = ValidateProtocolInfoInResL( nestCurrentValue, aLocalSharing ));
       
   512                                                                 if(err)
       
   513                                                                 {
       
   514                                                                     User::Leave(EBadMetadata);
       
   515                                                                 }
       
   516                                                                 CleanupStack::PushL( protInfoValue );
       
   517                                                                 valOfAttr.Set( *protInfoValue );
       
   518                                                                 child.SetAttributeL( nameOfAttr, valOfAttr );
       
   519                                                                 CleanupStack::PopAndDestroy( protInfoValue );                                                           
       
   520                                                             }                                                                                                 //------- 3 -----                                                                                         //------- 3 -----
       
   521                                                         }
       
   522                                                     }                                                                                                                                                                                                                                                                                                                                                                                       
       
   523                                                                                                         
       
   524 
       
   525                                                     // if not main tag mark the attr is required
       
   526                                                     if( !IsMainObjectTagL(child) && nestElementName != KDlnaProfileID)
       
   527                                                     {
       
   528                                                        
       
   529                                                         HBufC8* attrReq = HBufC8::NewLC(
       
   530                                                             nestElementName.Length()
       
   531                                                             +KRequiredAtrSuf().Length() );
       
   532                                                         TPtr8 attrReqPtr(attrReq->Des());
       
   533                                                         attrReqPtr = nestElementName;
       
   534                                                         attrReqPtr.Append(KRequiredAtrSuf);
       
   535                                                         child.AddNewAttributeL( attrReqPtr, KTrueValue8 );
       
   536                                                         CleanupStack::PopAndDestroy(attrReq);
       
   537                                                     }
       
   538                                                 }
       
   539                                             }
       
   540                                         }
       
   541                                     
       
   542                                     }
       
   543                                     CleanupStack::PopAndDestroy(&nestEls);
       
   544                                 }
       
   545                                 CleanupStack::PopAndDestroy( nameWithNs );
       
   546                                 
       
   547                             }
       
   548                                 
       
   549                             // If not found, add it
       
   550                             if ( !elementFound )
       
   551                             {
       
   552                                 User::Leave(EBadMetadata);
       
   553                             }
       
   554                         } 
       
   555                     }
       
   556                         
       
   557                     // Validate attribute   
       
   558                     if ( propertyType == KAttribute() )
       
   559                     {
       
   560                         elementFound = EFalse;
       
   561                         
       
   562                         const TDesC8& required = UpnpDomInterface::GetAttrValueL( el, KRequiredObject() );
       
   563                         if ( required == UpnpCD::KOne() )
       
   564                         {
       
   565 
       
   566                             const TDesC8& elementName = UpnpDomInterface::GetAttrValueL( el, KName() );
       
   567 
       
   568                             const TDesC8& currentValue = UpnpDomInterface::GetAttrValueL( object, elementName );
       
   569                             
       
   570                             if ( !currentValue.Length() )  
       
   571                             {
       
   572                                 TXmlEngAttr attr = object.AttributeNodeL( elementName );
       
   573 
       
   574                                 if(attr.NotNull())
       
   575                                 {
       
   576                                     attr.SetValueL(KNullDesC8);
       
   577                                 }
       
   578                                 else
       
   579                                 {
       
   580                                     object.AddNewAttributeL( elementName, KNullDesC8 );
       
   581                                 }                               
       
   582                             }
       
   583                             // if not main tag mark the attr is required
       
   584                             if(!IsMainObjectTagL(object))
       
   585                             {
       
   586                                 HBufC8* attrReq = HBufC8::NewLC(
       
   587                                     elementName.Length()+KRequiredAtrSuf().Length() );
       
   588                                 TPtr8 attrReqPtr(attrReq->Des());
       
   589                                 attrReqPtr = elementName;
       
   590                                 attrReqPtr.Append(KRequiredAtrSuf);
       
   591                                 object.AddNewAttributeL( attrReqPtr, KTrueValue8 );
       
   592                                 CleanupStack::PopAndDestroy(attrReq);
       
   593                             }
       
   594                         }
       
   595                     }
       
   596                 }
       
   597                 CleanupStack::PopAndDestroy(&properties);
       
   598             }
       
   599         }
       
   600         CleanupStack::PopAndDestroy(&propElems);
       
   601     }
       
   602     CleanupStack::PopAndDestroy(); //objectDescrs.Close();
       
   603     CleanupStack::PopAndDestroy(&children);
       
   604     
       
   605     // now the object 
       
   606     // * has the all required fields (if some were missing, they are added)
       
   607     // * had a proper xml structure (_not_ using UpnpDomInterface:: functions that do not care)
       
   608     // * has for sure a mostly proper object structure 
       
   609 
       
   610     return EUndefined;
       
   611 }
       
   612 // -----------------------------------------------------------------------------
       
   613 // CUpnpElementFactory::ValidatePropertiesL()
       
   614 // Function leaves on error.
       
   615 // -----------------------------------------------------------------------------
       
   616 //
       
   617 void CUpnpElementFactory::ValidatePropertiesL( TXmlEngElement aObj,
       
   618                                                RArray<TXmlEngElement>& aClassList)
       
   619 {
       
   620     // validate main object's attributes
       
   621     ValidateMainAttributesL(aObj, aClassList);
       
   622     
       
   623     // validate elements
       
   624     RXmlEngNodeList<TXmlEngElement> elements;
       
   625     CleanupClosePushL(elements);
       
   626     aObj.GetChildElements (elements);
       
   627     
       
   628     // for each element
       
   629     while(elements.HasNext())
       
   630     {
       
   631         TXmlEngElement el = elements.Next();
       
   632         ValidateElementL(el, aClassList);
       
   633     }
       
   634     CleanupStack::PopAndDestroy(&elements);
       
   635 }
       
   636 // -----------------------------------------------------------------------------
       
   637 // CUpnpElementFactory::ValidateBigImageL()
       
   638 // Function leaves on error.
       
   639 // -----------------------------------------------------------------------------
       
   640 //
       
   641 void CUpnpElementFactory::ValidateBigImageL( TXmlEngElement aObj)
       
   642 {
       
   643     RArray<TXmlEngElement> elms;
       
   644     CleanupClosePushL(elms);
       
   645     
       
   646     if( UpnpDomInterface::GetElementListL(aObj, elms, KRes) )
       
   647     {
       
   648         for(TInt i = 0; i < elms.Count(); i++)
       
   649         {
       
   650                 
       
   651             TXmlEngAttr prInfAttr = elms[i].AttributeNodeL(KprotocolInfo());
       
   652             if(prInfAttr.NotNull())
       
   653             {
       
   654                 CUpnpProtocolInfoLocal* protInf = CUpnpProtocolInfoLocal::NewL(
       
   655                         UpnpDomInterface::GetAttrValueL(elms[i], KprotocolInfo) );
       
   656                 CleanupStack::PushL(protInf);
       
   657                                                                                    
       
   658                 /* Only support for DLNA pn-params:
       
   659                 *  1) JPEG_SM
       
   660                 *  2) MP3 
       
   661                 *  3) AAC_ISO_320
       
   662                 *  4) AVC_MP4_BL_CIF15_AAC_520
       
   663                 */
       
   664                 if( protInf->PnParameter() != KDLNA_PN_JPEG_SM &&
       
   665                     protInf->PnParameter() != KDLNA_PN_MP3 &&
       
   666                     protInf->PnParameter() != KDLNA_PN_AAC_ISO_320 &&
       
   667                     protInf->PnParameter() != KDLNA_PN_AVC_MP4_BL_CIF15_AAC_520                     
       
   668                   )
       
   669                 {           
       
   670                     // set 4th parameter to "*"
       
   671                     protInf->SetFourthFieldL(KAsterisk8);
       
   672                     TPtrC8 prInfo = protInf->ProtocolInfoL();
       
   673                     HBufC8* prInfTmp = prInfo.Alloc();
       
   674                     CleanupStack::PushL(prInfTmp);
       
   675                     prInfAttr.SetValueL( *prInfTmp );
       
   676                     CleanupStack::PopAndDestroy(prInfTmp);
       
   677                 }
       
   678                 // clean up
       
   679                 CleanupStack::PopAndDestroy(protInf);
       
   680             }
       
   681         }
       
   682     }
       
   683     
       
   684     // clean up
       
   685     CleanupStack::PopAndDestroy(&elms);
       
   686 }
       
   687 // -----------------------------------------------------------------------------
       
   688 // CUpnpElementFactory::ValidateElementL()
       
   689 // Function leaves on error.
       
   690 // -----------------------------------------------------------------------------
       
   691 //
       
   692 void CUpnpElementFactory::ValidateElementL( TXmlEngElement aElement,
       
   693                                             RArray<TXmlEngElement>& aClassList)
       
   694 {
       
   695     if(aElement.Name() == KRes)
       
   696     {
       
   697         ValidateResElL(aElement, aClassList);
       
   698     }
       
   699     else
       
   700     {
       
   701         //  get pattern 
       
   702         HBufC8* name = UpnpCdUtils::GetElmNameWithNsL(aElement);
       
   703         CleanupStack::PushL(name);
       
   704         TXmlEngElement pattern = GetPatternL(*name, aClassList, KElement);
       
   705         if(pattern.NotNull())
       
   706         {
       
   707             ValidateElWithPatternL(aElement, pattern); // leaves on error
       
   708         }
       
   709         else
       
   710         { // attr is not supported - remove
       
   711             aElement.Remove();
       
   712         }
       
   713         // clean up
       
   714         CleanupStack::PopAndDestroy(name);
       
   715     }
       
   716 }
       
   717 // -----------------------------------------------------------------------------
       
   718 // CUpnpElementFactory::ValidateMainAttributesL()
       
   719 // Function leaves on error.
       
   720 // -----------------------------------------------------------------------------
       
   721 //
       
   722 void CUpnpElementFactory::ValidateMainAttributesL( TXmlEngElement aObj, 
       
   723                                                    RArray<TXmlEngElement>& aClassList)
       
   724 {
       
   725     // list of attributes
       
   726     RXmlEngNodeList<TXmlEngAttr> attrList;
       
   727     CleanupClosePushL(attrList);
       
   728     aObj.GetAttributes(attrList);
       
   729     
       
   730     // for each attr
       
   731     while(attrList.HasNext())
       
   732     {
       
   733         // get attr
       
   734         TXmlEngAttr attr = attrList.Next();
       
   735         
       
   736         //  get pattern 
       
   737         TXmlEngElement pattern = GetPatternL(attr.Name(), aClassList, KAttribute);
       
   738         if(pattern.NotNull())
       
   739         {
       
   740             ValidateAttrWithPatternL(attr, pattern); // leaves on error
       
   741         }
       
   742         else
       
   743         { // attr is not supported - remove
       
   744             attr.Remove();
       
   745         }
       
   746     }
       
   747     CleanupStack::PopAndDestroy(&attrList);
       
   748 }
       
   749 // -----------------------------------------------------------------------------
       
   750 // CUpnpElementFactory::ValidateElWithPatternL()
       
   751 // Function leaves on error.
       
   752 // -----------------------------------------------------------------------------
       
   753 //
       
   754 void CUpnpElementFactory::ValidateResElL( TXmlEngElement aElement, 
       
   755                                          RArray<TXmlEngElement>& aClassList)
       
   756 {
       
   757     // list of attributes
       
   758     RXmlEngNodeList<TXmlEngAttr> attrList;
       
   759     CleanupClosePushL(attrList);
       
   760     aElement.GetAttributes(attrList);
       
   761     
       
   762     // for each attr
       
   763     while(attrList.HasNext())
       
   764     {
       
   765         // get attr
       
   766         TXmlEngAttr attr = attrList.Next();
       
   767         
       
   768         //  get pattern 
       
   769         TXmlEngElement pattern = GetPatternForResAttrL(attr.Name(), aClassList);
       
   770         if(pattern.NotNull())
       
   771         {
       
   772             ValidateAttrWithPatternL(attr, pattern); // leaves on error
       
   773         }
       
   774         else
       
   775         { // attr is not supported - remove
       
   776             attr.Remove();
       
   777         }
       
   778     }
       
   779     CleanupStack::PopAndDestroy(&attrList);
       
   780 }
       
   781 // -----------------------------------------------------------------------------
       
   782 // CUpnpElementFactory::ValidateElWithPatternL()
       
   783 // Function leaves on error.
       
   784 // -----------------------------------------------------------------------------
       
   785 //
       
   786 void CUpnpElementFactory::ValidateElWithPatternL(   TXmlEngElement aElement, 
       
   787                                                     TXmlEngElement aPattern )
       
   788 {
       
   789     // is required?
       
   790     if(IsRequiredL(aPattern) )
       
   791     { // cannot be empty
       
   792         if( !aElement.Value().Length() || 
       
   793             UpnpCdUtils::IsWhiteString( aElement.Value() ) )
       
   794         {
       
   795             User::Leave(EBadMetadata);
       
   796         }
       
   797     }
       
   798 }
       
   799 // -----------------------------------------------------------------------------
       
   800 // CUpnpElementFactory::ValidateAttrWithPatternL()
       
   801 // Function leaves on error.
       
   802 // -----------------------------------------------------------------------------
       
   803 //
       
   804 void CUpnpElementFactory::ValidateAttrWithPatternL( TXmlEngAttr aAttr, 
       
   805                                                     TXmlEngElement aPattern )
       
   806 {
       
   807     // is required?
       
   808     if(IsRequiredL(aPattern) )
       
   809     { // cannot be empty
       
   810         if( !aAttr.Value().Length() || 
       
   811             UpnpCdUtils::IsWhiteString( aAttr.Value() ) )
       
   812         {
       
   813             User::Leave(EBadMetadata);
       
   814         }
       
   815     }
       
   816 }
       
   817 // -----------------------------------------------------------------------------
       
   818 // CUpnpElementFactory::ValidateAttrWithPatternL()
       
   819 // Function leaves on error.
       
   820 // -----------------------------------------------------------------------------
       
   821 //
       
   822 TBool CUpnpElementFactory::IsRequiredL(TXmlEngElement aPattern) 
       
   823 {
       
   824     TXmlEngAttr reqAttr = aPattern.AttributeNodeL(KRequiredObject());
       
   825     TBool ret = EFalse;
       
   826     if( reqAttr.NotNull() &&
       
   827         reqAttr.Value().Length() && 
       
   828         reqAttr.Value() == KTrueValue8() )
       
   829     {
       
   830         ret = ETrue;
       
   831     }
       
   832     return ret;
       
   833 }
       
   834 // -----------------------------------------------------------------------------
       
   835 // CUpnpElementFactory::GetPatternForElL()
       
   836 // Function leaves on error.
       
   837 // -----------------------------------------------------------------------------
       
   838 //
       
   839 TXmlEngElement CUpnpElementFactory::GetPatternL( const TDesC8& aPropertyName,
       
   840                                                 RArray<TXmlEngElement>& aClassList,
       
   841                                                 const TDesC8& aType )
       
   842 {
       
   843     TXmlEngElement retEl;
       
   844     
       
   845     // for each class
       
   846     for(TInt i = 0; i < aClassList.Count(); i++)
       
   847     {
       
   848         TXmlEngElement elPattEl;      
       
   849         UpnpDomInterface::GetDirectoryElementL(aClassList[i], elPattEl, KProperties, KType, aType);
       
   850         if(elPattEl.NotNull())
       
   851         {   
       
   852             UpnpDomInterface::GetDirectoryElementL(elPattEl, retEl, KObjectProperty, KObjectName, aPropertyName);
       
   853             
       
   854             // break if found
       
   855             if(retEl.NotNull())
       
   856             {
       
   857                 break;
       
   858             }
       
   859         }
       
   860     }
       
   861     
       
   862     return retEl;
       
   863 }
       
   864 // -----------------------------------------------------------------------------
       
   865 // CUpnpElementFactory::GetPatternForResAttrL()
       
   866 // Function leaves on error.
       
   867 // -----------------------------------------------------------------------------
       
   868 //
       
   869 TXmlEngElement CUpnpElementFactory::GetPatternForResAttrL(const TDesC8& aPropertyName,
       
   870                                                     RArray<TXmlEngElement>& aClassList )
       
   871 {
       
   872     TXmlEngElement retEl;
       
   873     
       
   874     // for each class
       
   875     for(TInt i = 0; i < aClassList.Count(); i++)
       
   876     {
       
   877         TXmlEngElement resAttrPattEl;     
       
   878         UpnpDomInterface::GetDirectoryElementL(aClassList[i], resAttrPattEl, KProperties, KType, KResAttr);
       
   879         if(resAttrPattEl.NotNull())
       
   880         {   
       
   881             UpnpDomInterface::GetDirectoryElementL(resAttrPattEl, retEl, KObjectProperty, KObjectName, aPropertyName);
       
   882             
       
   883             // break if found
       
   884             if(retEl.NotNull())
       
   885             {
       
   886                 break;
       
   887             }
       
   888         }
       
   889     }
       
   890     
       
   891     return retEl;
       
   892 }
       
   893 // -----------------------------------------------------------------------------
       
   894 // CUpnpElementFactory::IsMainObjectTagL()
       
   895 // (other items were commented in a header).
       
   896 // -----------------------------------------------------------------------------
       
   897 //
       
   898 TBool CUpnpElementFactory::IsMainObjectTagL(TXmlEngElement aElement)
       
   899 {
       
   900     TXmlEngElement notNeeded;
       
   901     return UpnpDomInterface::GetElementL(aElement, notNeeded, KClassTagName);
       
   902 }
       
   903 // -----------------------------------------------------------------------------
       
   904 // CUpnpElementFactory::ActiveElementL()
       
   905 // Gets active element from XML document. An active element
       
   906 // is a first element different from <DIDL-Lite> element.
       
   907 // -----------------------------------------------------------------------------
       
   908 //
       
   909 TXmlEngElement CUpnpElementFactory::ActiveElementL( const RXmlEngDocument& aDocument )
       
   910 {
       
   911     if( aDocument.IsNull() || aDocument.DocumentElement().IsNull() )
       
   912     {
       
   913         User::Leave( KErrNotFound );            
       
   914     }
       
   915         
       
   916     if ( aDocument.DocumentElement().Name().CompareF( KDidlLite() ) != 0 )
       
   917     {
       
   918         return aDocument.DocumentElement();
       
   919     }
       
   920     else
       
   921     {
       
   922         TXmlEngElement root = aDocument.DocumentElement();
       
   923         RXmlEngNodeList<TXmlEngElement> children;
       
   924         CleanupClosePushL(children);
       
   925         root.GetChildElements( children );
       
   926         children.HasNext();
       
   927         CleanupStack::PopAndDestroy(&children);
       
   928         return children.Next();
       
   929     }
       
   930 }
       
   931 
       
   932 // -----------------------------------------------------------------------------
       
   933 // CUpnpElementFactory::ExtractActiveElementL()
       
   934 // Extracts active element from XML document. 
       
   935 // An active element is a first element different from <DIDL-Lite> element.
       
   936 // IMPORTANT: Caller takes responsibility for returned element. 
       
   937 // -----------------------------------------------------------------------------
       
   938 //
       
   939 RXmlEngDocument CUpnpElementFactory::ExtractActiveElementL( const RXmlEngDocument& aDocument )
       
   940 {
       
   941     TXmlEngElement active;
       
   942     RXmlEngDocument ret;
       
   943     ret.OpenL(iDOMImpl);
       
   944     CleanupClosePushL(ret);
       
   945 
       
   946     if( aDocument.IsNull() || aDocument.DocumentElement().IsNull() )
       
   947     {
       
   948         User::Leave( KErrNotFound );            
       
   949     }
       
   950         
       
   951     if ( aDocument.DocumentElement().Name().CompareF( KDidlLite() ) != 0 )
       
   952     {
       
   953         active = aDocument.DocumentElement().Unlink().AsElement();
       
   954     }
       
   955     else
       
   956     {
       
   957         TXmlEngElement root = aDocument.DocumentElement();
       
   958         RXmlEngNodeList<TXmlEngElement> children;
       
   959         CleanupClosePushL(children);
       
   960         root.GetChildElements( children );
       
   961         children.HasNext();
       
   962         active = children.Next().Unlink().AsElement();
       
   963         CleanupStack::PopAndDestroy(&children);
       
   964     }
       
   965     ret.SetDocumentElement(active);
       
   966     
       
   967     CleanupStack::Pop(&ret);
       
   968     
       
   969     return ret;
       
   970 }
       
   971 
       
   972 // -----------------------------------------------------------------------------
       
   973 // CUpnpElementFactory::ElementsMatchL()
       
   974 // Checks if two elements are equal and have exactly the same subtrees.
       
   975 // -----------------------------------------------------------------------------
       
   976 //
       
   977 TBool CUpnpElementFactory::ElementsMatchL( TXmlEngElement aFirst, TXmlEngElement aSecond )
       
   978 {
       
   979     // this function checks following things:
       
   980     // 1. element names
       
   981     // 2. contents of the elements
       
   982     // 3. attributes of the elements
       
   983     // 4. child elements of the elements
       
   984     
       
   985     if ( aFirst.Name().Compare(aSecond.Name()) == 0 )
       
   986     {
       
   987         // aFirst names match. next: check namespace
       
   988         if ( aFirst.Prefix().Compare( aSecond.Prefix()) == 0 )
       
   989         {
       
   990             if (!aFirst.Text().Compare(aSecond.Text()))
       
   991             {
       
   992                 
       
   993                 // namespacess match, next: check attributes
       
   994                 RXmlEngNodeList<TXmlEngAttr> elemAttrs;
       
   995                 CleanupClosePushL(elemAttrs);
       
   996                 RXmlEngNodeList<TXmlEngAttr> currAttrs;
       
   997                 CleanupClosePushL(currAttrs);
       
   998                 
       
   999                 aFirst.GetAttributes( elemAttrs );
       
  1000                 aSecond.GetAttributes( currAttrs );
       
  1001                 
       
  1002                 if ( elemAttrs.Count() == currAttrs.Count() )
       
  1003                 {
       
  1004                     // first step in comparing attributes ready (counts match!)
       
  1005                     // next, check names and values (for each attribute)
       
  1006 
       
  1007                     while( elemAttrs.HasNext() && currAttrs.HasNext() )
       
  1008                     {
       
  1009                         TXmlEngAttr elemAttr = elemAttrs.Next();
       
  1010                         TXmlEngAttr currAttr = currAttrs.Next();
       
  1011                         
       
  1012                         // compare names and values
       
  1013                         if ( elemAttr.Name().Compare( currAttr.Name() ) )
       
  1014                         {
       
  1015                             CleanupStack::PopAndDestroy(&currAttrs);
       
  1016                             CleanupStack::PopAndDestroy(&elemAttrs);
       
  1017                             return EFalse;
       
  1018                         }
       
  1019                         if ( elemAttr.Value().Compare( currAttr.Value() ) )
       
  1020                         {
       
  1021                             CleanupStack::PopAndDestroy(&currAttrs);
       
  1022                             CleanupStack::PopAndDestroy(&elemAttrs);
       
  1023                             return EFalse;
       
  1024                         }
       
  1025                         
       
  1026                     }
       
  1027                     
       
  1028                     // compare child elements (recursive function call)
       
  1029                     RXmlEngNodeList<TXmlEngElement> fChildren;
       
  1030                     CleanupClosePushL(fChildren);
       
  1031                     RXmlEngNodeList<TXmlEngElement> sChildren;
       
  1032                     CleanupClosePushL(sChildren);
       
  1033                                         
       
  1034                     aFirst.GetChildElements( fChildren );
       
  1035                     aSecond.GetChildElements( sChildren );
       
  1036                 
       
  1037                     
       
  1038                     if ( fChildren.Count() == sChildren.Count() )
       
  1039                     {
       
  1040                             while ( fChildren.HasNext() && sChildren.HasNext() )
       
  1041                             {
       
  1042                             // call this function again for children
       
  1043                                 TBool matching = ElementsMatchL( fChildren.Next(), sChildren.Next() );
       
  1044 
       
  1045                             // if some of the elements do not match, return false!
       
  1046                                 if (matching == EFalse)
       
  1047                                 {
       
  1048                                     CleanupStack::PopAndDestroy(&sChildren);
       
  1049                                     CleanupStack::PopAndDestroy(&fChildren);
       
  1050                                     CleanupStack::PopAndDestroy(&currAttrs);
       
  1051                                     CleanupStack::PopAndDestroy(&elemAttrs);
       
  1052                                     return EFalse;
       
  1053                                 }
       
  1054                             }
       
  1055                         // only place to return ETrue
       
  1056                         // all the checks are made; if survived here, elements match!
       
  1057                         CleanupStack::PopAndDestroy(&sChildren);
       
  1058                         CleanupStack::PopAndDestroy(&fChildren);
       
  1059                         CleanupStack::PopAndDestroy(&currAttrs);
       
  1060                         CleanupStack::PopAndDestroy(&elemAttrs);
       
  1061                         return ETrue;
       
  1062                     }
       
  1063                     CleanupStack::PopAndDestroy(&sChildren);
       
  1064                     CleanupStack::PopAndDestroy(&fChildren);
       
  1065                 }
       
  1066                 CleanupStack::PopAndDestroy(&currAttrs);
       
  1067                 CleanupStack::PopAndDestroy(&elemAttrs);
       
  1068             }
       
  1069         }
       
  1070     }
       
  1071     
       
  1072     return EFalse;
       
  1073 }
       
  1074 
       
  1075 // -----------------------------------------------------------------------------
       
  1076 // CUpnpElementFactory::CountElementsL()
       
  1077 // Prepares corresponding RArray<TXmlEngElements> and calls 
       
  1078 // CountElementsL( const TDesC8& aName, RArray<TXmlEngElement>& aArray )
       
  1079 // -----------------------------------------------------------------------------
       
  1080 //
       
  1081 TInt CUpnpElementFactory::CountElementsL( const TDesC8& aName, RArray<RXmlEngDocument>& aArray )
       
  1082 {
       
  1083     TInt count(0);
       
  1084         
       
  1085     for(TInt i = 0; i < aArray.Count(); i++)
       
  1086     {            
       
  1087         if ( aArray[i].DocumentElement().NotNull() )
       
  1088         {
       
  1089             if ( aArray[i].DocumentElement().Name() == aName )
       
  1090             {
       
  1091                 count++;
       
  1092             }
       
  1093         }
       
  1094             
       
  1095     }
       
  1096     return count;
       
  1097 }
       
  1098 // -----------------------------------------------------------------------------
       
  1099 // CUpnpElementFactory::CountElementsL()
       
  1100 // Counts elements in array that have the same name.
       
  1101 // -----------------------------------------------------------------------------
       
  1102 //
       
  1103 TInt CUpnpElementFactory::CountElementsL( const TDesC8& aName, RArray<TXmlEngElement>& aArray )
       
  1104 {
       
  1105     TInt count(0);
       
  1106     
       
  1107     for (TInt v(0); v<aArray.Count(); v++)
       
  1108     {
       
  1109         if ( aArray[v].NotNull() )
       
  1110         {
       
  1111             if ( aArray[v].Name() == aName )
       
  1112             {
       
  1113                 count++;
       
  1114             }
       
  1115         }
       
  1116     }
       
  1117     
       
  1118     return count;
       
  1119 }
       
  1120 // -----------------------------------------------------------------------------
       
  1121 // CUpnpElementFactory::NameWithNsLC()
       
  1122 // Constructs descriptor with element's name and namespace prefix separated with colon.
       
  1123 // IMPORTANT: As the function name indicates, it leaves pointer to heap descriptor on 
       
  1124 // cleanup stack.
       
  1125 // -----------------------------------------------------------------------------
       
  1126 //
       
  1127 HBufC8* CUpnpElementFactory::NameWithNsLC(const TXmlEngElement& aElement)
       
  1128 {
       
  1129     const TDesC8& localName = aElement.Name();
       
  1130     TPtrC8 prefix = aElement.Prefix();
       
  1131 
       
  1132     if ( prefix.Length() > 0)
       
  1133     {
       
  1134 
       
  1135         HBufC8* nameWithNs = HBufC8::NewLC( 
       
  1136             localName.Length() + 
       
  1137             UpnpString::KColon().Length() +
       
  1138             prefix.Length() );
       
  1139 
       
  1140         nameWithNs->Des().Append( prefix );
       
  1141         nameWithNs->Des().Append( UpnpString::KColon() );
       
  1142         nameWithNs->Des().Append( localName );
       
  1143 
       
  1144         return nameWithNs;
       
  1145     }
       
  1146     else
       
  1147     {
       
  1148         return localName.AllocLC();
       
  1149     }
       
  1150 }
       
  1151 
       
  1152 // -----------------------------------------------------------------------------
       
  1153 // CUpnpElementFactory::ClassesL()
       
  1154 // Gets classes descriptions for given object.
       
  1155 // -----------------------------------------------------------------------------
       
  1156 //
       
  1157 void CUpnpElementFactory::ClassesL( const TXmlEngElement& aObject, RArray<TXmlEngElement>& aArray, const TDesC8& aObjType )
       
  1158 {
       
  1159     TInt i(0);
       
  1160     
       
  1161     // if survived here, we have the new element of type item or container
       
  1162     // let's analyze its type
       
  1163     TXmlEngElement type;
       
  1164     UpnpDomInterface::GetElementL ( aObject, type, KClass() );
       
  1165 
       
  1166     if ( type.IsNull() ) 
       
  1167     {
       
  1168         // no <class> element! leave
       
  1169         User::Leave( EBadMetadata );
       
  1170     }
       
  1171 
       
  1172     // check that does the new element have all the required fields for its type
       
  1173     // and also check that it does not have whatever fields (only optional allowed)
       
  1174     RPointerArray<TPtrC8> objectFields;
       
  1175     
       
  1176     TPtrC8 content = type.Text();
       
  1177     if( !content.Length() )
       
  1178     {
       
  1179         User::Leave( EBadMetadata );
       
  1180     }
       
  1181     //--- removing white spaces ------------------      
       
  1182     HBufC8* tempBuffer = type.Text().AllocLC(); 
       
  1183     TPtr8 tmpPtr(tempBuffer->Des());
       
  1184     UpnpCdUtils::RemoveWhiteSpacesL(tmpPtr);        
       
  1185     CleanupStack::Check(tempBuffer);
       
  1186     type.SetTextL(tmpPtr);  
       
  1187     //--------------------------------------------
       
  1188     
       
  1189     UpnpString::CutToPiecesL(tmpPtr, TChar('.'), objectFields );    
       
  1190     CleanupStack::Check(tempBuffer);
       
  1191     // let's inspect each of types
       
  1192     // at first, collect object type descriptions from objects xml    
       
  1193     // to a pointer array
       
  1194     
       
  1195     TInt NumberOfObjectFields = objectFields.Count();
       
  1196     
       
  1197     for ( i=0; i < NumberOfObjectFields; i++ ) 
       
  1198     {
       
  1199         // seek for such object type
       
  1200         TXmlEngElement objectDescription;
       
  1201 
       
  1202         UpnpDomInterface::GetDirectoryElementL( 
       
  1203                 iDocument.DocumentElement(), 
       
  1204                 objectDescription, 
       
  1205                 KElement, 
       
  1206                 KType, 
       
  1207                 *objectFields[i] );
       
  1208         CleanupStack::Check(tempBuffer);
       
  1209         // if such type found
       
  1210         if ( objectDescription.NotNull() ) 
       
  1211         {
       
  1212             aArray.Append( objectDescription );
       
  1213         }
       
  1214         /* This case is valid for any numeric value of containerID used in CreateObject() action
       
  1215         *  We do some checking starting from 3rd string of <upnp:class> element, if the string isn't
       
  1216         *  recognizable, instead of leaving, we trims the value of <upnp:class> element, e.g:
       
  1217         *  'object.item.imageItem.abcd' -> is trimmed into -> 'object.item.imageItem'
       
  1218         *  DLNA 7.3.120.4 requirement
       
  1219         */
       
  1220         else if( i >= 2 )
       
  1221         {            
       
  1222             for( TInt j = NumberOfObjectFields - 1; j >= i; j-- )
       
  1223             {                            
       
  1224                 TInt pos = tmpPtr.LocateReverse( TChar('.') );                    
       
  1225                 if( pos > KErrNotFound )
       
  1226                 {
       
  1227                     tmpPtr.Copy( tmpPtr.Left(pos) );                   
       
  1228                                                 
       
  1229                     delete objectFields[j];
       
  1230                     objectFields.Remove(j);   
       
  1231                 }                    
       
  1232             }                                                
       
  1233             type.SetTextL(tmpPtr); // changing xml                        
       
  1234             
       
  1235             break;
       
  1236         }
       
  1237         else 
       
  1238         {
       
  1239             objectFields.ResetAndDestroy();
       
  1240             objectFields.Close();
       
  1241             User::Leave( EBadMetadata );
       
  1242         }
       
  1243     }
       
  1244     CleanupStack::Check(tempBuffer);
       
  1245     /*  for each type, check that: 
       
  1246     *   1. it is referenced to its current parent type (e.g. audioItem -> item)
       
  1247     *   2. this new object has all the required fields
       
  1248     *   3. relations between object types and values of 'upnp:class':
       
  1249     *      <item> -> 'object.item' or <container> -> 'object.container'
       
  1250     */
       
  1251        
       
  1252     // we count the number of elements once again, because size of the array might change
       
  1253     NumberOfObjectFields = objectFields.Count(); 
       
  1254 
       
  1255     for ( i=0; i < NumberOfObjectFields; i++ )
       
  1256     {
       
  1257         const TDesC8& field = *objectFields[i];
       
  1258 
       
  1259         // 1. first, check the parent relation 
       
  1260         // first type must be "object"!
       
  1261         if ( i==0 ) 
       
  1262         {
       
  1263             /* Leave if:
       
  1264             *  1. first type isn't the 'object' OR
       
  1265             *  2. 'upnp:class' contains only 'object' type [which in matter of fact isn't instantiable]
       
  1266             */
       
  1267             if ( field != KObject() || 
       
  1268                  field == KObject() && NumberOfObjectFields == 1
       
  1269             ) 
       
  1270             {
       
  1271                 // if not "item", leave!
       
  1272                 objectFields.ResetAndDestroy();
       
  1273                 objectFields.Close();
       
  1274                 User::Leave( EBadMetadata );
       
  1275             }
       
  1276         }
       
  1277         // for later types, check the relation really
       
  1278         else 
       
  1279         {   
       
  1280             // checking relations between object types and values of 'upnp:class'
       
  1281             if( i == 1 && aObjType.Length() > 0 )
       
  1282             {
       
  1283                 if(  !field.Compare(KItem) && aObjType.Compare(KItem) ||
       
  1284                      !field.Compare(KContainer) && aObjType.Compare(KContainer)
       
  1285                 )
       
  1286                 {          
       
  1287                     objectFields.ResetAndDestroy();
       
  1288                     objectFields.Close();                              
       
  1289                     User::Leave( EBadMetadata );
       
  1290                 }
       
  1291             }            
       
  1292             //----------------------------------------    
       
  1293             const TDesC8& parent = *objectFields[i-1];
       
  1294             
       
  1295             // if we've survived to this point, this parent string
       
  1296             // should match with the one in the previous object description xml element
       
  1297             TXmlEngElement iparent;
       
  1298             UpnpDomInterface::GetElementL ( aArray[i], iparent, KIParent() );
       
  1299             CleanupStack::Check(tempBuffer);
       
  1300             TPtrC8 cont = iparent.Text();
       
  1301         
       
  1302             // now check the actual relation. leave if strings do not match!
       
  1303             if ( cont.Length() && parent != cont )
       
  1304             {
       
  1305                 objectFields.ResetAndDestroy();
       
  1306                 objectFields.Close();
       
  1307                 User::Leave( EBadMetadata );
       
  1308             }
       
  1309         }
       
  1310     }
       
  1311     CleanupStack::PopAndDestroy(tempBuffer);
       
  1312     objectFields.ResetAndDestroy();
       
  1313     objectFields.Close();
       
  1314     return;
       
  1315 }
       
  1316 
       
  1317 // -----------------------------------------------------------------------------
       
  1318 // CUpnpElementFactory::IsNotEmptyImportUriL()
       
  1319 // (other items were commented in a header).
       
  1320 // -----------------------------------------------------------------------------
       
  1321 //
       
  1322 TBool CUpnpElementFactory::IsNotEmptyImportUriL( const TXmlEngElement& aElement )
       
  1323 {
       
  1324     TXmlEngAttr importUri;
       
  1325     
       
  1326     if ( aElement.Name() == KRes() )
       
  1327     {
       
  1328         importUri = aElement.AttributeNodeL( KImportUri8() );
       
  1329         
       
  1330         // remove if empty importUri: DLNA Requirement [7.3.134.5]
       
  1331         TPtrC8 val( importUri.Value() );
       
  1332         if( UpnpCdUtils::IsWhiteString( val ) )
       
  1333         {
       
  1334             importUri.Remove();
       
  1335         }
       
  1336     }
       
  1337 
       
  1338     return importUri.NotNull();
       
  1339 }
       
  1340 
       
  1341 // -----------------------------------------------------------------------------
       
  1342 // CUpnpElementFactory::IsClassElement()
       
  1343 // (other items were commented in a header).
       
  1344 // -----------------------------------------------------------------------------
       
  1345 //
       
  1346 TBool CUpnpElementFactory::IsClassElement( const TXmlEngElement& aElement )
       
  1347 {
       
  1348     if ( aElement.Name() == KClass() )
       
  1349     {
       
  1350         return ETrue;
       
  1351     }
       
  1352     else
       
  1353     {
       
  1354         return EFalse;
       
  1355     }
       
  1356 }
       
  1357 // -----------------------------------------------------------------------------
       
  1358 // CUpnpElementFactory::ValidateProtocolInfoInResL
       
  1359 //  Allocates string, which is object type for this object. 
       
  1360 // -----------------------------------------------------------------------------
       
  1361 HBufC8* CUpnpElementFactory::ValidateProtocolInfoInResL( const TDesC8& aProtocolInfo, TBool aLocalSharing )
       
  1362 {
       
  1363     HBufC8* result = NULL; 
       
  1364    // CUpnpDlnaProtocolInfo* protocolInfo = CUpnpDlnaProtocolInfo::NewL( (TDesC8&)aProtocolInfo );
       
  1365     CUpnpProtocolInfoLocal* protocolInfo = CUpnpProtocolInfoLocal::NewL( (TDesC8&)aProtocolInfo );
       
  1366     CleanupStack::PushL( protocolInfo ); 
       
  1367     _LIT8(KProtocolInfoHttpGet, "http-get"); 
       
  1368     protocolInfo->SetFirstFieldL( (TDesC8&)KProtocolInfoHttpGet() ); 
       
  1369     protocolInfo->SetSecondFieldL( (TDesC8&)KAsterisk8() ); 
       
  1370     TPtrC8 third = protocolInfo->ThirdField(); 
       
  1371     if(( third.Find( KSlash8()) == KErrNotFound) && 
       
  1372       ( third.Compare( KAsterisk8()) != KErrNone))
       
  1373     {
       
  1374         if( aLocalSharing)
       
  1375         {
       
  1376         User::Leave( EBadMetadata );
       
  1377         }
       
  1378         protocolInfo->SetThirdFieldL( (TDesC8&) KAsterisk8());                                  
       
  1379     }
       
  1380    // if( protocolInfo->IsDlnaInformationIncluded() ) // Check it !!!
       
  1381     {
       
  1382         protocolInfo->SetOpParameterL( UpnpDlnaProtocolInfo::B_VAL , ETrue );
       
  1383         protocolInfo->SetOpParameterL( UpnpDlnaProtocolInfo::A_VAL , EFalse ); 
       
  1384     }
       
  1385     TPtrC8 prInfo = protocolInfo->ProtocolInfoL();
       
  1386     result =  prInfo.Alloc();
       
  1387     CleanupStack::PopAndDestroy( protocolInfo ); 
       
  1388     return result; 
       
  1389 }
       
  1390 
       
  1391 // -----------------------------------------------------------------------------
       
  1392 // CUpnpElementFactory::GetContentDirectoryReference
       
  1393 // Function gets pointer to CUpnpContentDirectory and puts it into CUpnpElementFactory object  
       
  1394 // -----------------------------------------------------------------------------
       
  1395 void CUpnpElementFactory::GetContentDirectoryReference(CUpnpContentDirectory* aCD)
       
  1396 {
       
  1397     iContentDirectory = aCD;
       
  1398 }
       
  1399 
       
  1400 // -----------------------------------------------------------------------------
       
  1401 // CUpnpElementFactory::CheckDurationOfResElement
       
  1402 // If res@duration attribute exists, the method checks whether it has valid format
       
  1403 // -----------------------------------------------------------------------------
       
  1404 
       
  1405 void CUpnpElementFactory::CheckDurationOfResElementL(const TXmlEngElement& aElement)
       
  1406 {
       
  1407     TXmlEngAttr duration;
       
  1408     
       
  1409     // if this is the 'res' element            
       
  1410     if( aElement.Name() == KRes() )
       
  1411     {
       
  1412         // and it has res@duration attribute
       
  1413         duration = aElement.AttributeNodeL( KDuration8() );                                        
       
  1414         if( duration.NotNull() )
       
  1415         {
       
  1416             TCurrentAction action = iContentDirectory->ExecutedAction();                                         
       
  1417             TPtrC8 val( duration.Value() );
       
  1418             
       
  1419             // if res@duration atrribute value is invalid [has improper format]
       
  1420             if( !UpnpCdUtils::ValidateDurationValue(val) )
       
  1421             {            
       
  1422                 // remove it from 'res' element if it is CreateObject()
       
  1423                 if( action == ECreateObjectAction )
       
  1424                 {
       
  1425                     duration.Remove();
       
  1426                 }                
       
  1427             }
       
  1428         }
       
  1429     }   
       
  1430 }
       
  1431 
       
  1432 // -----------------------------------------------------------------------------
       
  1433 // CUpnpElementFactory::CheckSizeOfResElement
       
  1434 // If res@size attribute exists, the method checks whether it has valid format
       
  1435 // size should be unsigned int.
       
  1436 // -----------------------------------------------------------------------------
       
  1437 void CUpnpElementFactory::CheckSizeOfResElementL(
       
  1438     const TXmlEngElement& aElement )
       
  1439     {
       
  1440     TXmlEngAttr sizeAttr;
       
  1441 
       
  1442     // if this is the 'res' element            
       
  1443     if ( aElement.Name() == KRes() )
       
  1444         {
       
  1445         // and it has res@size attribute
       
  1446         sizeAttr = aElement.AttributeNodeL( KSize() );
       
  1447         if ( sizeAttr.NotNull() )
       
  1448             {
       
  1449             TCurrentAction action = iContentDirectory->ExecutedAction();
       
  1450             TPtrC8 val( sizeAttr.Value() );
       
  1451 
       
  1452             // if res@size atrribute value is invalid [is not an unsigned long]
       
  1453             TUint32 unsignedLong = 0;
       
  1454 
       
  1455             TLex8 lexULong(val);
       
  1456             TInt error = lexULong.Val( unsignedLong, EDecimal );
       
  1457                          
       
  1458             TInt remainder = lexULong.Remainder().Length();
       
  1459 
       
  1460             if ( error != KErrNone || remainder )
       
  1461                 {
       
  1462                 // remove it from 'res' element if it is CreateObject()
       
  1463                 if ( action == ECreateObjectAction )
       
  1464                     {
       
  1465                     sizeAttr.Remove();
       
  1466                     }
       
  1467                 }
       
  1468             }
       
  1469         }
       
  1470 
       
  1471     }
       
  1472 
       
  1473 //  End of File