|
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 |