|
1 /* |
|
2 * Copyright (c) 2007 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: Utility for parsing upnp items |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 // INCLUDE FILES |
|
24 // System |
|
25 #include <e32std.h> |
|
26 |
|
27 // upnp stack api |
|
28 #include <upnpitem.h> |
|
29 #include <upnpdlnaprotocolinfo.h> |
|
30 |
|
31 // upnpframework / avcontroller helper api |
|
32 #include "upnpconstantdefs.h" // for KValueNotImplemented |
|
33 #include "upnpitemutility.h" |
|
34 |
|
35 _LIT( KComponentLogfile, "upnpavcontrollerhelper.txt"); |
|
36 #include "upnplog.h" |
|
37 |
|
38 // CONSTANTS |
|
39 const TInt KDateStringLength = 10; |
|
40 const TInt KDateTimeStringLength = 19; |
|
41 const TInt KMaxDateStringLength = 30; |
|
42 const TInt KCodeSemicolon = 58; |
|
43 _LIT( KSeparator, ":" ); |
|
44 _LIT( KNullTime, "000000" ); |
|
45 _LIT8( KHttp, "http://" ); |
|
46 _LIT8( KCiParam, "DLNA.ORG_CI" ); |
|
47 |
|
48 /* removed due to M-DMC CTT test case 7.3.26.2 |
|
49 _LIT8( KAudioSupport, "audio/" ); |
|
50 _LIT8( KImageSupport, "image/" ); |
|
51 _LIT8( KVideoSupport, "video/" ); |
|
52 */ |
|
53 |
|
54 // ============================ LOCAL FUNCTIONS ============================= |
|
55 |
|
56 // -------------------------------------------------------------------------- |
|
57 // UPnPItemUtility::BelongsToClass |
|
58 //--------------------------------------------------------------------------- |
|
59 EXPORT_C TBool UPnPItemUtility::BelongsToClass( |
|
60 const CUpnpObject& aObject, |
|
61 const TDesC8& aClass ) |
|
62 { |
|
63 TBool beginsWith = |
|
64 ( aObject.ObjectClass().Find( aClass ) == 0 ); |
|
65 return beginsWith; |
|
66 } |
|
67 |
|
68 // -------------------------------------------------------------------------- |
|
69 // UPnPItemUtility::GetResElements |
|
70 //--------------------------------------------------------------------------- |
|
71 EXPORT_C void UPnPItemUtility::GetResElements( |
|
72 const CUpnpObject& aObject, |
|
73 RUPnPElementsArray& aResElementsArray ) |
|
74 { |
|
75 const RUPnPElementsArray& array = |
|
76 const_cast<CUpnpObject&>(aObject).GetElements(); |
|
77 |
|
78 for( TInt i = 0; i < array.Count(); i++ ) |
|
79 { |
|
80 if( array[ i ]->Name() == KElementRes() ) |
|
81 { |
|
82 aResElementsArray.Append( array[ i ] ); |
|
83 } |
|
84 } |
|
85 } |
|
86 |
|
87 // -------------------------------------------------------------------------- |
|
88 // UPnPItemUtility::ResourceFromItemL |
|
89 //--------------------------------------------------------------------------- |
|
90 EXPORT_C const CUpnpElement& UPnPItemUtility::ResourceFromItemL( |
|
91 const CUpnpItem& aItem ) |
|
92 { |
|
93 __LOG( "UpnpItemUtility:ResourceFromItemL" ); |
|
94 |
|
95 // Obtain list of item's res elements |
|
96 RUPnPElementsArray elms; |
|
97 GetResElements( aItem, elms ); |
|
98 TInt count = elms.Count(); |
|
99 |
|
100 CUpnpDlnaProtocolInfo* pInfo = NULL; |
|
101 TBool found = EFalse; |
|
102 TInt i(0); |
|
103 // bestCandidate is an index of some res element in the list. This res |
|
104 // will be considered as the best candidate for desired res and that |
|
105 // candidate will be returned if no res element contains false CI-flag. |
|
106 |
|
107 const CUpnpElement* bestCandidate = 0; |
|
108 |
|
109 // determine which resource is the original one |
|
110 // 1. In DLNA 1.5 case, parse protocolInfo attribute and see if some res |
|
111 // element has CI-flag false (=not converted so that is what we want) |
|
112 // 2. In non-DLNA 1.5 case and in DLNA 1.5 case where CI-flag does not |
|
113 // exist, do the following: |
|
114 // o filter out other than HTTP GET resources (internal uri's, RTP) |
|
115 // o filter out resources that do not match itemtype (mime type of |
|
116 // audio file resources should start with "audio/" etc.) |
|
117 for( i = 0 ; i < count; i++ ) |
|
118 { |
|
119 // Make sure that it is a HTTP GET resource. Otherwise continue. |
|
120 if( elms[ i ]->Value().Left( KHttp.iTypeLength ).Compare( KHttp() ) |
|
121 != 0 ) |
|
122 { |
|
123 continue; |
|
124 } |
|
125 |
|
126 // Obtain protocolInfo of the res element. |
|
127 const CUpnpAttribute* attr = FindAttributeByName( |
|
128 *elms[i], KAttributeProtocolInfo() ); |
|
129 if ( attr ) |
|
130 { |
|
131 TRAP_IGNORE( pInfo = CUpnpDlnaProtocolInfo::NewL( attr->Value() ) ); |
|
132 if( !pInfo ) |
|
133 { |
|
134 //if pInfo, start next one! |
|
135 continue; |
|
136 } |
|
137 // check if CI parameter is false or it doesn't have CI parameters at all. |
|
138 //for upnp item, always the first res element is the best, resolution |
|
139 // should be checked in the future |
|
140 if ( ( attr->Value().Find( KCiParam() ) != KErrNotFound && |
|
141 pInfo->CiParameter() == EFalse ) || |
|
142 attr->Value().Find( KCiParam() ) == KErrNotFound ) |
|
143 { |
|
144 // end loop, we found what we were looking for. |
|
145 found = ETrue; |
|
146 delete pInfo; pInfo = NULL; |
|
147 break; |
|
148 } |
|
149 |
|
150 /* removed due to M-DMC CTT test case 7.3.26.2 |
|
151 // check that mimetype corresponds to objectType |
|
152 TPtrC8 mime = pInfo->ThirdField(); |
|
153 |
|
154 TPtrC8 objectClass = aItem.ObjectClass(); |
|
155 if ( objectClass.Compare( KClassAudio ) == 0 ) |
|
156 { |
|
157 if ( mime.Left( KAudioSupport().Length() ).CompareF( |
|
158 KAudioSupport() ) != 0 ) |
|
159 { |
|
160 // if mime type does not match to object type, this is |
|
161 // not the correct resource. |
|
162 delete pInfo; pInfo = NULL; |
|
163 continue; |
|
164 } |
|
165 } |
|
166 else if ( objectClass.Compare( KClassVideo ) == 0 ) |
|
167 { |
|
168 if ( mime.Left( KVideoSupport().Length() ).CompareF( |
|
169 KVideoSupport() ) != 0 ) |
|
170 { |
|
171 // if mime type does not match to object type, this is |
|
172 // not the correct resource. |
|
173 delete pInfo; pInfo = NULL; |
|
174 continue; |
|
175 } |
|
176 } |
|
177 else if ( objectClass.Compare( KClassImage ) == 0 ) |
|
178 { |
|
179 if ( mime.Left( KImageSupport().Length() ).CompareF( |
|
180 KImageSupport() ) != 0 ) |
|
181 { |
|
182 // if mime type does not match to object type, this is |
|
183 // not the correct resource. |
|
184 delete pInfo; pInfo = NULL; |
|
185 continue; |
|
186 } |
|
187 } |
|
188 */ |
|
189 // use the first suitable res field as candidate which will be |
|
190 // returned if better is not found. |
|
191 // More sophisticated solution would be to compare resolution |
|
192 // etc. attributes to determine the best candidate, |
|
193 if ( 0 == bestCandidate ) |
|
194 { |
|
195 bestCandidate = elms[i]; |
|
196 } |
|
197 delete pInfo; pInfo = NULL; |
|
198 } |
|
199 else |
|
200 { |
|
201 // No mandatory protocolinfo attribute. This is not what we want. |
|
202 } |
|
203 } |
|
204 if ( found ) |
|
205 { |
|
206 bestCandidate = elms[i]; |
|
207 } |
|
208 |
|
209 // close the elements array |
|
210 elms.Close(); |
|
211 |
|
212 if( bestCandidate == 0 ) |
|
213 { |
|
214 User::Leave( KErrNotFound ); |
|
215 } |
|
216 return *bestCandidate; |
|
217 } |
|
218 |
|
219 |
|
220 // -------------------------------------------------------------------------- |
|
221 // UPnPItemUtility::FindElementByName |
|
222 //--------------------------------------------------------------------------- |
|
223 EXPORT_C const CUpnpElement* UPnPItemUtility::FindElementByName( |
|
224 const CUpnpObject& aObject, const TDesC8& aName ) |
|
225 { |
|
226 __LOG( "UpnpItemUtility:FindElementByName" ); |
|
227 |
|
228 CUpnpElement* element = NULL; |
|
229 const RUPnPElementsArray& array = |
|
230 const_cast<CUpnpObject&>(aObject).GetElements(); |
|
231 for( TInt i = 0; i < array.Count(); i++ ) |
|
232 { |
|
233 if( array[ i ]->Name() == aName ) |
|
234 { |
|
235 element = array[ i ]; |
|
236 i = array.Count(); |
|
237 } |
|
238 } |
|
239 return element; |
|
240 } |
|
241 |
|
242 // -------------------------------------------------------------------------- |
|
243 // UPnPItemUtility::FindElementByNameL |
|
244 //--------------------------------------------------------------------------- |
|
245 EXPORT_C const CUpnpElement& UPnPItemUtility::FindElementByNameL( |
|
246 const CUpnpObject& aObject, const TDesC8& aName ) |
|
247 { |
|
248 __LOG( "UpnpItemUtility:FindElementByNameL" ); |
|
249 |
|
250 const CUpnpElement* element = FindElementByName( |
|
251 aObject, aName ); |
|
252 if( !element ) |
|
253 { |
|
254 User::Leave( KErrNotFound ); |
|
255 } |
|
256 return *element; |
|
257 } |
|
258 |
|
259 // -------------------------------------------------------------------------- |
|
260 // UPnPItemUtility::FindAttributeByName |
|
261 //--------------------------------------------------------------------------- |
|
262 EXPORT_C const CUpnpAttribute* UPnPItemUtility::FindAttributeByName( |
|
263 const CUpnpElement& aElement, const TDesC8& aName ) |
|
264 { |
|
265 __LOG( "UpnpItemUtility:FindAttributeByName" ); |
|
266 |
|
267 CUpnpAttribute* attribute = NULL; |
|
268 const RUPnPAttributesArray& array = |
|
269 const_cast<CUpnpElement&>(aElement).GetAttributes(); |
|
270 |
|
271 for( TInt i = 0; i < array.Count(); i++ ) |
|
272 { |
|
273 |
|
274 TBufC8<255> buf(array[ i ]->Name()); |
|
275 if( array[ i ]->Name() == aName ) |
|
276 { |
|
277 attribute = array[ i ]; |
|
278 i = array.Count(); |
|
279 } |
|
280 } |
|
281 return attribute; |
|
282 } |
|
283 |
|
284 // -------------------------------------------------------------------------- |
|
285 // UPnPItemUtility::FindAttributeByNameL |
|
286 //--------------------------------------------------------------------------- |
|
287 EXPORT_C const CUpnpAttribute& UPnPItemUtility::FindAttributeByNameL( |
|
288 const CUpnpElement& aElement, const TDesC8& aName ) |
|
289 { |
|
290 __LOG( "UpnpItemUtility:FindAttributeByNameL" ); |
|
291 |
|
292 const CUpnpAttribute* attribute = FindAttributeByName( |
|
293 aElement, aName ); |
|
294 if( !attribute ) |
|
295 { |
|
296 User::Leave( KErrNotFound ); |
|
297 } |
|
298 return *attribute; |
|
299 } |
|
300 |
|
301 // -------------------------------------------------------------------------- |
|
302 // UPnPItemUtility::UpnpDateAsTTime |
|
303 //--------------------------------------------------------------------------- |
|
304 EXPORT_C TInt UPnPItemUtility::UPnPDateAsTTime( |
|
305 const TDesC8& aUpnpDate, TTime& aTime ) |
|
306 { |
|
307 __LOG( "UpnpItemUtility:UpnpDateAsTTime" ); |
|
308 |
|
309 TRAPD( err, UPnPItemUtility::UPnPDateAsTTimeL( aUpnpDate, aTime ) ); |
|
310 return err; |
|
311 } |
|
312 |
|
313 // -------------------------------------------------------------------------- |
|
314 // UPnPItemUtility::UpnpDurationAsMilliseconds |
|
315 //--------------------------------------------------------------------------- |
|
316 EXPORT_C TInt UPnPItemUtility::UPnPDurationAsMilliseconds( |
|
317 const TDesC8& aDuration, TInt& aMilliseconds ) |
|
318 { |
|
319 __LOG( "UpnpItemUtility:UpnpDurationAsMilliseconds" ); |
|
320 |
|
321 TInt retVal = KErrNone; |
|
322 if( aDuration.Length() > 0 ) |
|
323 { |
|
324 // Check if information is actually returned by the device |
|
325 if( aDuration.Compare( KValueNotImplemented ) != 0 ) |
|
326 { |
|
327 TInt time = 0; |
|
328 TChar separator( KCodeSemicolon ); |
|
329 TInt lposit = aDuration.Locate( separator ); |
|
330 |
|
331 if ( lposit != KErrNotFound ) |
|
332 { |
|
333 TInt rposit = aDuration.LocateReverse( separator ); |
|
334 if( rposit != lposit ) |
|
335 { |
|
336 // Hours |
|
337 TLex8 lex( aDuration.Left( lposit ) ); |
|
338 retVal = lex.Val( time ); |
|
339 if( retVal == KErrNone ) |
|
340 { |
|
341 // Convert to ms and add |
|
342 aMilliseconds += time * 3600 * 1000; |
|
343 // Minutes |
|
344 lex.Assign( aDuration.Mid( |
|
345 lposit + 1, rposit - lposit - 1 ) ); |
|
346 retVal = lex.Val( time ); |
|
347 if( retVal == KErrNone ) |
|
348 { |
|
349 // Convert to ms and add |
|
350 aMilliseconds += time * 60* 1000; |
|
351 // Seconds |
|
352 lex.Assign( aDuration.Mid( |
|
353 rposit + 1, 2 ) ); |
|
354 retVal = lex.Val( time ); |
|
355 if( retVal == KErrNone ) |
|
356 { |
|
357 // Convert to ms and add |
|
358 aMilliseconds += time * 1000; |
|
359 } |
|
360 } |
|
361 } |
|
362 } |
|
363 else |
|
364 { |
|
365 retVal = KErrNotSupported; |
|
366 } |
|
367 } |
|
368 else |
|
369 { |
|
370 retVal = KErrNotSupported; |
|
371 } |
|
372 } |
|
373 else |
|
374 { |
|
375 retVal = KErrNotSupported; |
|
376 } |
|
377 } |
|
378 else |
|
379 { |
|
380 retVal = KErrNotSupported; |
|
381 } |
|
382 |
|
383 return retVal; |
|
384 } |
|
385 |
|
386 void UPnPItemUtility::UPnPDateAsTTimeL( const TDesC8& aUpnpDate, |
|
387 TTime& aTime ) |
|
388 { |
|
389 // This method is capable of handling the most common dc:date formats: |
|
390 // CCYY-MM-DD and CCYY-MM-DDThh:mm:ss |
|
391 // Rest of the dc:date formats are handled as well, but they might not |
|
392 // be converted precisely |
|
393 |
|
394 TBuf<KMaxDateStringLength> formatDateString; |
|
395 HBufC* dateString = HBufC::NewL( aUpnpDate.Length() ); |
|
396 dateString->Des().Copy( aUpnpDate ); |
|
397 |
|
398 if( aUpnpDate.Length() >= KDateStringLength ) |
|
399 { |
|
400 // CCYY-MM-DD --> CCYYMMDD |
|
401 formatDateString.Copy( dateString->Des().Left( 4 ) ); // Year |
|
402 formatDateString.Append( dateString->Des().Mid( 5,2 ) ); // Month |
|
403 formatDateString.Append( dateString->Des().Mid( 8,2 ) ); // Day |
|
404 |
|
405 if( aUpnpDate.Length() >= KDateTimeStringLength ) |
|
406 { |
|
407 // hh:mm:ss --> hhmmss |
|
408 formatDateString.Append( KSeparator ); |
|
409 // Hours |
|
410 formatDateString.Append( dateString->Des().Mid( 11, 2 ) ); |
|
411 // Minutes |
|
412 formatDateString.Append( dateString->Des().Mid( 14, 2 ) ); |
|
413 // Seconds |
|
414 formatDateString.Append( dateString->Des().Mid( 17, 2 ) ); |
|
415 } |
|
416 else |
|
417 { |
|
418 // hh:mm:ss --> 000000 |
|
419 formatDateString.Append( KSeparator ); |
|
420 formatDateString.Append( KNullTime ); |
|
421 } |
|
422 } |
|
423 delete dateString; |
|
424 |
|
425 User::LeaveIfError( aTime.Set( formatDateString ) ); |
|
426 } |
|
427 |