|
1 /* |
|
2 * Copyright (c) 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 the License "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: Widget installer info file parsing. |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include <e32base.h> |
|
20 #include <f32file.h> |
|
21 #include <centralrepository.h> |
|
22 #include <libxml2_globals.h> |
|
23 #include <libxml2_parser.h> |
|
24 #include "WidgetUIConfigHandler.h" |
|
25 #include "SWInstWidgetUid.h" |
|
26 #include "WidgetInstallerInternalCRKeys.h" |
|
27 #include <charconv.h> |
|
28 #include <WidgetRegistryConstants.h> |
|
29 |
|
30 |
|
31 // DTD |
|
32 |
|
33 _LIT8( KNokiaId, "-//Nokia//DTD PLIST" ); // only the first part without version |
|
34 _LIT8( KAppleId, "-//Apple Computer//DTD PLIST" ); // only the first part without version |
|
35 |
|
36 // parsed elements in the DTD (XML element names are case sensitive) |
|
37 |
|
38 _LIT8( KKey,"key" ); |
|
39 _LIT8( KString,"string" ); |
|
40 _LIT8( KInt,"integer" ); |
|
41 _LIT8( KTrue,"true" ); |
|
42 _LIT8( KFalse,"false" ); |
|
43 |
|
44 // properties from widget metadata file |
|
45 |
|
46 // NOTE: Comments "required" and "optional" apply to our requirements |
|
47 // for registering a widget. |
|
48 |
|
49 // NOTE: These property names are not XML element names, they are text |
|
50 // content for the <key> element, so we have made the match case |
|
51 // insensitive and capitalization here is just for readability. |
|
52 |
|
53 // Apple unique key names |
|
54 _LIT( KAppleBundleIdentifier, "CFBundleIdentifier" ); // required |
|
55 _LIT( KAppleDisplayName, "CFBundleDisplayName" ); // required |
|
56 _LIT( KAppleBundleVersion, "CFBundleVersion" ); // optional |
|
57 _LIT( KAppleAllowFullAccess, "AllowFullAccess" ); // optional |
|
58 // For Apple, AllowFullAccess is mapped to AllowNetworkAccess unless |
|
59 // AllowNetworkAccess appears too. |
|
60 |
|
61 // Nokia unique key names |
|
62 _LIT( KNokiaIdentifier, "Identifier" ); // required |
|
63 _LIT( KNokiaDisplayName, "DisplayName" ); // required |
|
64 _LIT( KNokiaVersion, "Version" ); // optional |
|
65 _LIT( KNokiaMiniViewEnabled, "MiniViewEnabled" ); // optional |
|
66 _LIT( KBlanketPermGranted, "BlanketPermissionGranted" ); |
|
67 |
|
68 // Apple/Nokia shared key names |
|
69 _LIT( KMainHTML, "MainHTML" ); // required |
|
70 _LIT( KAllowNetworkAccess, "AllowNetworkAccess" ); // optional |
|
71 _LIT( KHeight, "Height" ); // optional |
|
72 _LIT( KWidth, "Width" ); // optional |
|
73 |
|
74 |
|
75 enum TWidgetPropertyFlag |
|
76 { |
|
77 EMandatory = 1, |
|
78 EConfig = 2, |
|
79 EApple = 4, |
|
80 ENokia = 8, |
|
81 ESpecial = 16 |
|
82 }; |
|
83 |
|
84 #define CONFIG_MUST ( EMandatory | EConfig ) |
|
85 #define CONFIG_APPLE_MUST ( EMandatory | EConfig | EApple ) |
|
86 #define CONFIG_NOKIA_MUST ( EMandatory | EConfig | ENokia ) |
|
87 |
|
88 #define CONFIG_MAY ( EConfig ) |
|
89 #define CONFIG_APPLE_MAY ( EConfig | EApple ) |
|
90 #define CONFIG_NOKIA_MAY ( EConfig | ENokia ) |
|
91 |
|
92 #define CONFIG_APPLE_SPECIAL ( EConfig | EApple | ESpecial ) |
|
93 |
|
94 using namespace SwiUI; |
|
95 |
|
96 // ============================================================================ |
|
97 // Traverse to the next Node |
|
98 // |
|
99 // @param aNode: current node |
|
100 // @since 3.1 |
|
101 // @return next node |
|
102 // ============================================================================ |
|
103 // |
|
104 xmlNode* CWidgetUIConfigHandler::TraverseNextNode( xmlNode* n ) |
|
105 { |
|
106 // depth first |
|
107 if ( n->children ) |
|
108 { |
|
109 n = n->children; |
|
110 } |
|
111 else |
|
112 { |
|
113 // go up while no sibling |
|
114 while ( n->parent && !n->next ) |
|
115 { |
|
116 n = n->parent; |
|
117 } |
|
118 // sibling? |
|
119 if ( n->next ) |
|
120 { |
|
121 n = n->next; |
|
122 } |
|
123 else // done |
|
124 { |
|
125 n = NULL; |
|
126 } |
|
127 } |
|
128 return n; |
|
129 } |
|
130 |
|
131 // ============================================================================ |
|
132 // CWidgetUIConfigHandler::NewL() |
|
133 // two-phase constructor |
|
134 // |
|
135 // @since 3.1 |
|
136 // ============================================================================ |
|
137 // |
|
138 CWidgetUIConfigHandler* CWidgetUIConfigHandler::NewL() |
|
139 { |
|
140 CWidgetUIConfigHandler *self = new (ELeave) CWidgetUIConfigHandler(); |
|
141 CleanupStack::PushL( self ); |
|
142 self->ConstructL(); |
|
143 CleanupStack::Pop(); |
|
144 return self; |
|
145 } |
|
146 |
|
147 // ============================================================================ |
|
148 // CWidgetUIConfigHandler::CWidgetUIConfigHandler() |
|
149 // C++ constructor |
|
150 // |
|
151 // @since 3.1 |
|
152 // ============================================================================ |
|
153 // |
|
154 CWidgetUIConfigHandler::CWidgetUIConfigHandler() |
|
155 { |
|
156 iProperties[EPropertyDescriptionAppleBundleIdentifier].id = EBundleIdentifier; |
|
157 iProperties[EPropertyDescriptionAppleBundleIdentifier].name.Set( KAppleBundleIdentifier ); |
|
158 iProperties[EPropertyDescriptionAppleBundleIdentifier].type = EWidgetPropTypeString; |
|
159 iProperties[EPropertyDescriptionAppleBundleIdentifier].flags = CONFIG_APPLE_MUST; |
|
160 // |
|
161 iProperties[EPropertyDescriptionAppleBundleDisplayName].id = EBundleDisplayName; |
|
162 iProperties[EPropertyDescriptionAppleBundleDisplayName].name.Set( KAppleDisplayName ); |
|
163 iProperties[EPropertyDescriptionAppleBundleDisplayName].type = EWidgetPropTypeString; |
|
164 iProperties[EPropertyDescriptionAppleBundleDisplayName].flags = CONFIG_APPLE_MUST; |
|
165 // |
|
166 iProperties[EPropertyDescriptionAppleBundleVersion].id = EBundleVersion; |
|
167 iProperties[EPropertyDescriptionAppleBundleVersion].name.Set( KAppleBundleVersion ); |
|
168 iProperties[EPropertyDescriptionAppleBundleVersion].type = EWidgetPropTypeString; |
|
169 iProperties[EPropertyDescriptionAppleBundleVersion].flags = CONFIG_APPLE_MAY; |
|
170 // |
|
171 iProperties[EPropertyDescriptionAppleAllowFullAccess].id = EWidgetPropertyIdInvalid; |
|
172 iProperties[EPropertyDescriptionAppleAllowFullAccess].name.Set( KAppleAllowFullAccess ); |
|
173 iProperties[EPropertyDescriptionAppleAllowFullAccess].type = EWidgetPropTypeBool; |
|
174 iProperties[EPropertyDescriptionAppleAllowFullAccess].flags = CONFIG_APPLE_SPECIAL; |
|
175 // |
|
176 iProperties[EPropertyDescriptionNokiaIdentifier].id = EBundleIdentifier; |
|
177 iProperties[EPropertyDescriptionNokiaIdentifier].name.Set( KNokiaIdentifier ); |
|
178 iProperties[EPropertyDescriptionNokiaIdentifier].type = EWidgetPropTypeString; |
|
179 iProperties[EPropertyDescriptionNokiaIdentifier].flags = CONFIG_NOKIA_MUST; |
|
180 // |
|
181 iProperties[EPropertyDescriptionNokiaDisplayName].id = EBundleDisplayName; |
|
182 iProperties[EPropertyDescriptionNokiaDisplayName].name.Set( KNokiaDisplayName ); |
|
183 iProperties[EPropertyDescriptionNokiaDisplayName].type = EWidgetPropTypeString; |
|
184 iProperties[EPropertyDescriptionNokiaDisplayName].flags = CONFIG_NOKIA_MUST; |
|
185 // |
|
186 iProperties[EPropertyDescriptionNokiaVersion].id = EBundleVersion; |
|
187 iProperties[EPropertyDescriptionNokiaVersion].name.Set( KNokiaVersion ); |
|
188 iProperties[EPropertyDescriptionNokiaVersion].type = EWidgetPropTypeString; |
|
189 iProperties[EPropertyDescriptionNokiaVersion].flags = CONFIG_NOKIA_MAY; |
|
190 // |
|
191 iProperties[EPropertyDescriptionMainHTML].id = EMainHTML; |
|
192 iProperties[EPropertyDescriptionMainHTML].name.Set( KMainHTML ); |
|
193 iProperties[EPropertyDescriptionMainHTML].type = EWidgetPropTypeString; |
|
194 iProperties[EPropertyDescriptionMainHTML].flags = CONFIG_MUST; |
|
195 // |
|
196 iProperties[EPropertyDescriptionAllowNetworkAccess].id = EAllowNetworkAccess; |
|
197 iProperties[EPropertyDescriptionAllowNetworkAccess].name.Set( KAllowNetworkAccess ); |
|
198 iProperties[EPropertyDescriptionAllowNetworkAccess].type = EWidgetPropTypeBool; |
|
199 iProperties[EPropertyDescriptionAllowNetworkAccess].flags = CONFIG_MAY; |
|
200 // |
|
201 iProperties[EPropertyDescriptionHeight].id = EHeight; |
|
202 iProperties[EPropertyDescriptionHeight].name.Set( KHeight ); |
|
203 iProperties[EPropertyDescriptionHeight].type = EWidgetPropTypeInt; |
|
204 iProperties[EPropertyDescriptionHeight].flags = CONFIG_MAY; |
|
205 // |
|
206 iProperties[EPropertyDescriptionWidth].id = EWidth; |
|
207 iProperties[EPropertyDescriptionWidth].name.Set( KWidth ); |
|
208 iProperties[EPropertyDescriptionWidth].type = EWidgetPropTypeInt; |
|
209 iProperties[EPropertyDescriptionWidth].flags = CONFIG_MAY; |
|
210 // |
|
211 iProperties[EPropertyDescriptionNokiaMiniViewEnable].id = EMiniViewEnable; |
|
212 iProperties[EPropertyDescriptionNokiaMiniViewEnable].name.Set( KNokiaMiniViewEnabled ); |
|
213 iProperties[EPropertyDescriptionNokiaMiniViewEnable].type = EWidgetPropTypeBool; |
|
214 iProperties[EPropertyDescriptionNokiaMiniViewEnable].flags = CONFIG_NOKIA_MAY; |
|
215 // |
|
216 iProperties[EPropertyDescriptionNokiaPromptNeeded].id = EBlanketPermGranted; |
|
217 iProperties[EPropertyDescriptionNokiaPromptNeeded].name.Set( KBlanketPermGranted ); |
|
218 iProperties[EPropertyDescriptionNokiaPromptNeeded].type = EWidgetPropTypeBool; |
|
219 iProperties[EPropertyDescriptionNokiaPromptNeeded].flags = CONFIG_NOKIA_MAY; |
|
220 } |
|
221 |
|
222 // ============================================================================ |
|
223 // CWidgetUIConfigHandler::ConstructL() |
|
224 // C++ constructor |
|
225 // |
|
226 // @since 3.1 |
|
227 // ============================================================================ |
|
228 // |
|
229 void CWidgetUIConfigHandler::ConstructL() |
|
230 { |
|
231 } |
|
232 |
|
233 // ============================================================================ |
|
234 // CWidgetUIConfigHandler::~CWidgetUIConfigHandler() |
|
235 // destructor |
|
236 // |
|
237 // @since 3.1 |
|
238 // ============================================================================ |
|
239 // |
|
240 CWidgetUIConfigHandler::~CWidgetUIConfigHandler() |
|
241 { |
|
242 } |
|
243 |
|
244 // ============================================================================ |
|
245 // Get the key type out of the keyname |
|
246 // |
|
247 // @param aKeyName The name of the key: <key>KeyName</key> |
|
248 // @since 3.1 |
|
249 // @return Key type. |
|
250 // ============================================================================ |
|
251 // |
|
252 TWidgetPropertyId CWidgetUIConfigHandler::GetPropertyId( |
|
253 const TDesC& aKeyName, |
|
254 DtdType aDtdType, |
|
255 TWidgetPropertyDescriptionId& aPropertyDescriptionId ) |
|
256 { |
|
257 aPropertyDescriptionId = EPropertyDescriptionIdInvalid; |
|
258 TInt i = 0; |
|
259 for (; i < EPropertyDescriptionIdCount; ++i ) |
|
260 { |
|
261 if ( (EDtdTypeApple == aDtdType) |
|
262 && ( iProperties[i].flags & ENokia ) ) |
|
263 { |
|
264 continue; |
|
265 } |
|
266 if ( (EDtdTypeNokia == aDtdType) |
|
267 && ( iProperties[i].flags & EApple ) ) |
|
268 { |
|
269 continue; |
|
270 } |
|
271 // we use case insensitive match for property names |
|
272 if ( 0 == aKeyName.CompareF( iProperties[i].name ) ) |
|
273 { |
|
274 aPropertyDescriptionId = static_cast<TWidgetPropertyDescriptionId>(i); |
|
275 if ( iProperties[i].flags & ESpecial ) |
|
276 { |
|
277 return EWidgetPropertyIdInvalid; |
|
278 } |
|
279 return iProperties[i].id; |
|
280 } |
|
281 } |
|
282 return EWidgetPropertyIdInvalid; |
|
283 } |
|
284 |
|
285 // ============================================================================ |
|
286 // CWidgetUIConfigHandler::ToUnicodeL |
|
287 // Utility to bundle transcoding to unicode steps. |
|
288 // |
|
289 // @since 3.1 |
|
290 // @param aEncoding input buffer encoding |
|
291 // @param aUnicodeSizeMultiplier how many bytes of input make one unicode char |
|
292 // @param aInBuf input data in encoding |
|
293 // @param aOutBuf malloc'ed output buf, caller takes ownership |
|
294 // @param aFileSession CCnvCharacterSetConverter requires it |
|
295 // ============================================================================ |
|
296 // |
|
297 void CWidgetUIConfigHandler::ToUnicodeL( TInt aEncoding, |
|
298 TInt aUnicodeSizeMultiplier, |
|
299 TPtrC8 aInBuf, HBufC16** aOutBuf, |
|
300 RFs& aFileSession ) |
|
301 { |
|
302 *aOutBuf = NULL; |
|
303 |
|
304 // outbuf sizing and alloction |
|
305 HBufC16* outBuf = HBufC16::NewLC(aUnicodeSizeMultiplier * aInBuf.Length()); |
|
306 TPtr16 outPtr = outBuf->Des(); |
|
307 |
|
308 // convert to unicode |
|
309 CCnvCharacterSetConverter* charConv = CCnvCharacterSetConverter::NewLC(); |
|
310 charConv->PrepareToConvertToOrFromL( aEncoding, aFileSession ); |
|
311 TInt state = CCnvCharacterSetConverter::KStateDefault; |
|
312 TInt rep = 0; // number of unconvertible characters |
|
313 TInt rIndx = 0; // index of first unconvertible character |
|
314 User::LeaveIfError( |
|
315 charConv->ConvertToUnicode( outPtr, aInBuf, state, rep, rIndx ) ); |
|
316 CleanupStack::PopAndDestroy( charConv ); |
|
317 |
|
318 CleanupStack::Pop(); // outBuf |
|
319 *aOutBuf = outBuf; |
|
320 } |
|
321 |
|
322 // ============================================================================ |
|
323 // CWidgetUIConfigHandler::GetContentL |
|
324 // Utility to bundle extraction of XML text content |
|
325 // |
|
326 // @since 3.1 |
|
327 // @param aEncoding input buffer encoding |
|
328 // @param aUnicodeSizeMultiplier how many bytes of input make one unicode char |
|
329 // @param aInBuf input data in encoding |
|
330 // @param aOutBuf malloc'ed output buf, caller takes ownership |
|
331 // @param aFileSession CCnvCharacterSetConverter requires it |
|
332 // ============================================================================ |
|
333 // |
|
334 void CWidgetUIConfigHandler::GetContentL( RFs& aFileSession, |
|
335 xmlDocPtr aDoc, |
|
336 xmlNode* aNode, |
|
337 HBufC** aContent ) |
|
338 { |
|
339 // xml uses UTF-8 for the internal representation |
|
340 xmlChar* xmlContent = |
|
341 xmlNodeListGetString( aDoc, aNode, 1 /* expand entities inline */); |
|
342 if ( NULL == xmlContent ) |
|
343 { |
|
344 User::Leave( OOM_FLAG ? KErrNoMemory : KErrCorrupt ); |
|
345 } |
|
346 // we must transcode UTF-8 to UCS-2 (historical |
|
347 // and now inaccurate name "unicode") |
|
348 CleanupStack::PushL( xmlContent ); |
|
349 TPtrC8 content( xmlContent ); |
|
350 ToUnicodeL( KCharacterSetIdentifierUtf8, 2, |
|
351 content, aContent, aFileSession ); |
|
352 CleanupStack::PopAndDestroy(); // xmlContent equivalent to xmlFree() |
|
353 if ( NULL == *aContent ) |
|
354 { |
|
355 User::Leave( KErrCorrupt ); |
|
356 } |
|
357 } |
|
358 |
|
359 // ============================================================================ |
|
360 // CWidgetUIConfigHandler::ParseValidateBundleMetadataL |
|
361 // Parse the widget info file and create widget entry |
|
362 // check for required keys and values |
|
363 // |
|
364 // @since 3.1 |
|
365 // @param aBuffer The buffer contains widget info file content. |
|
366 // @param aPropertyValues output filled with parsed values from buf |
|
367 // ============================================================================ |
|
368 // |
|
369 void CWidgetUIConfigHandler::ParseValidateBundleMetadataL( |
|
370 TPtr8 aBuffer, |
|
371 RPointerArray<CWidgetPropertyValue>& aPropertyValues, |
|
372 RFs& aFileSession ) |
|
373 { |
|
374 /* |
|
375 steps: 1. parse bundle metadata (ex., info.plist) and put |
|
376 results in aPropertyValues; 2. validate the metadata 2a. are |
|
377 required keys present? 2b. are values sane? |
|
378 |
|
379 leaves: 1. doesn't parse -> KErrCorrupt; 2. DTD not Nokia and |
|
380 cenrep key KWidgetInstallerStrictMode is 1 -> KErrNotSupported; |
|
381 3. key type bool but child element not true or false -> |
|
382 KErrCorrupt; 4. key type integer but child element not integer |
|
383 -> KErrCorrupt; 5. key type integer and child element integer |
|
384 but unparsable integer value -> KErrCorrupt; 6. key type string |
|
385 and child element not string -> KErrCorrupt; 7. key type string |
|
386 and child element string but does not contain text -> |
|
387 KErrCorrupt; 8. required keys not present -> KErrNotSupported |
|
388 9. key values not sane -> KErrNotSupported; 10. Heap allocation |
|
389 failure -> KErrNoMem |
|
390 */ |
|
391 |
|
392 TInt nokiaOnly = 0; |
|
393 TRAP_IGNORE( |
|
394 CRepository* rep = CRepository::NewL( TUid::Uid( KSWInstWidgetUIUid ) ); |
|
395 rep->Get( KWidgetInstallerStrictMode, nokiaOnly ); |
|
396 delete rep; ); |
|
397 |
|
398 // initialize the parser and check compiled code matches lib version |
|
399 |
|
400 #if 0 |
|
401 // xmllib has a memory leak, so in order to detect mem leaks outside |
|
402 // of the xmllib, this code fills in the values that the parse step |
|
403 // would and returns. you have to fill in the values for the specific |
|
404 // Info.plist you are installing |
|
405 |
|
406 _LIT( KIdentifier, "com.aws.widget.beta1" ); |
|
407 _LIT( KName, "WeatherBug" ); |
|
408 _LIT( KHtml, "index.html" ); |
|
409 *(aPropertyValues[EBundleIdentifier]) = KIdentifier; |
|
410 *(aPropertyValues[EBundleDisplayName]) = KName(); |
|
411 *(aPropertyValues[EMainHTML]) = KHtml; |
|
412 *(aPropertyValues[EAllowNetworkAccess]) = 1; |
|
413 *(aPropertyValues[ENokiaWidget]) = 0; |
|
414 |
|
415 // TODO: We decided to drop BundleName and just use |
|
416 // DisplayName but the registry code has errors in it and uses |
|
417 // BundleName when it should use DisplayName so as a workaround, |
|
418 // set BundleName to DisplayName. Should eventually remove |
|
419 // BundleName from set of registry values. |
|
420 const TDesC& name = *(aPropertyValues[EBundleDisplayName]); |
|
421 *(aPropertyValues[EBundleName]) = name; |
|
422 |
|
423 #else |
|
424 LIBXML_TEST_VERSION |
|
425 |
|
426 xmlDocPtr doc; // resulting document tree |
|
427 |
|
428 doc = xmlReadMemory( (const char *)aBuffer.Ptr(), aBuffer.Length(), |
|
429 NULL, // no base URL |
|
430 NULL, // get encoding from doc |
|
431 XML_PARSE_NOWARNING | XML_PARSE_NONET ); // options |
|
432 // parse failed check |
|
433 if ( !doc ) |
|
434 { |
|
435 xmlCleanupParser(); |
|
436 User::Leave( KErrCorrupt ); |
|
437 } |
|
438 |
|
439 // determine doctype |
|
440 xmlNode* n; |
|
441 xmlDtd* dtd = NULL; |
|
442 for ( n = doc->children; n; n = n->next ) |
|
443 { |
|
444 if ( XML_DTD_NODE == n->type ) |
|
445 { |
|
446 dtd = (xmlDtd*)n; |
|
447 break; |
|
448 } |
|
449 } |
|
450 iDtdType = EDtdTypeUnknown; |
|
451 if ( dtd ) |
|
452 { |
|
453 TPtrC8 id( dtd->ExternalID ); |
|
454 if ( 0 == id.Left(KNokiaId().Length()).Compare(KNokiaId()) ) |
|
455 { |
|
456 iDtdType = EDtdTypeNokia; |
|
457 } |
|
458 else if ( 0 == id.Left(KAppleId().Length()).Compare(KAppleId()) ) |
|
459 { |
|
460 iDtdType = EDtdTypeApple; |
|
461 } |
|
462 } |
|
463 |
|
464 // save for registry so non-nokia installed on memory cards can be blocked |
|
465 // when inserted in nokia-only configured device |
|
466 *(aPropertyValues[ENokiaWidget]) = ( (EDtdTypeNokia == iDtdType) ? 1 : 0 ); |
|
467 |
|
468 // handle cenrep nokia only setting |
|
469 if ( (EDtdTypeUnknown == iDtdType) |
|
470 || (nokiaOnly && ( EDtdTypeNokia != iDtdType )) ) |
|
471 { |
|
472 User::Leave( KErrNotSupported ); |
|
473 } |
|
474 |
|
475 xmlNode* rootElement = xmlDocGetRootElement( doc ); |
|
476 TWidgetPropertyId valId( EWidgetPropertyIdInvalid ); |
|
477 TWidgetPropertyDescriptionId propertyDescriptionId( EPropertyDescriptionIdInvalid ); |
|
478 |
|
479 for ( n = rootElement; n; n = TraverseNextNode( n ) ) |
|
480 { |
|
481 if ( XML_ELEMENT_NODE == n->type ) |
|
482 { |
|
483 TPtrC8 element( n->name ); |
|
484 |
|
485 if ( 0 == element.Compare( KKey() ) ) |
|
486 { |
|
487 valId = EWidgetPropertyIdInvalid; |
|
488 HBufC* keyName; |
|
489 GetContentL( aFileSession, doc, n->children, &keyName ); |
|
490 CleanupStack::PushL( keyName ); |
|
491 TPtr name( keyName->Des() ); |
|
492 name.Trim(); // remove surrounding whitespace |
|
493 valId = GetPropertyId( name, iDtdType, propertyDescriptionId ); |
|
494 CleanupStack::PopAndDestroy( keyName ); |
|
495 |
|
496 // reject duplicate keys based on value already being |
|
497 // set (unset values have type unknown) |
|
498 if ( ( EWidgetPropertyIdInvalid != valId ) |
|
499 && ( EWidgetPropTypeUnknown |
|
500 != aPropertyValues[valId]->iType ) ) |
|
501 { |
|
502 User::Leave( KErrCorrupt ); |
|
503 } |
|
504 } |
|
505 else if ( EWidgetPropertyIdInvalid != valId ) |
|
506 { |
|
507 switch ( iProperties[propertyDescriptionId].type ) |
|
508 { |
|
509 case EWidgetPropTypeBool: |
|
510 // map true to 1 and false to 0 |
|
511 if ( 0 == element.Compare( KTrue ) ) |
|
512 { |
|
513 *(aPropertyValues[valId]) = 1; |
|
514 } |
|
515 else if ( 0 == element.Compare( KFalse ) ) |
|
516 { |
|
517 *(aPropertyValues[valId]) = 0; |
|
518 } |
|
519 else |
|
520 { |
|
521 User::Leave( KErrCorrupt ); |
|
522 } |
|
523 break; |
|
524 case EWidgetPropTypeInt: |
|
525 { |
|
526 if ( 0 == element.Compare( KInt() ) ) |
|
527 { |
|
528 HBufC* keyVal; |
|
529 GetContentL( aFileSession, doc, n->children, &keyVal ); |
|
530 CleanupStack::PushL( keyVal ); |
|
531 TPtr value( keyVal->Des() ); |
|
532 value.Trim(); // remove surrounding whitespace |
|
533 TLex tlex; |
|
534 tlex.Assign( value ); |
|
535 TInt x; |
|
536 TInt e = tlex.Val( x ); |
|
537 CleanupStack::PopAndDestroy( keyVal ); |
|
538 if ( !e && tlex.Eos() ) |
|
539 { |
|
540 *(aPropertyValues[valId]) = x; |
|
541 } |
|
542 else |
|
543 { |
|
544 User::Leave( KErrCorrupt ); |
|
545 } |
|
546 } |
|
547 else |
|
548 { |
|
549 User::Leave( KErrCorrupt ); |
|
550 } |
|
551 } |
|
552 break; |
|
553 case EWidgetPropTypeString: |
|
554 if ( 0 == element.Compare( KString() ) ) |
|
555 { |
|
556 HBufC* keyVal; |
|
557 GetContentL( aFileSession, doc, n->children, &keyVal ); |
|
558 CleanupStack::PushL( keyVal ); |
|
559 TPtr value( keyVal->Des() ); |
|
560 value.Trim(); // remove surrounding whitespace |
|
561 *(aPropertyValues[valId]) = value; |
|
562 CleanupStack::PopAndDestroy( keyVal ); |
|
563 } |
|
564 else |
|
565 { |
|
566 User::Leave( KErrCorrupt ); |
|
567 } |
|
568 break; |
|
569 default: |
|
570 // ignore other things |
|
571 break; |
|
572 } |
|
573 } |
|
574 else if ( EPropertyDescriptionIdInvalid != propertyDescriptionId ) |
|
575 { |
|
576 if ( EPropertyDescriptionAppleAllowFullAccess == propertyDescriptionId ) |
|
577 { |
|
578 // only set if AllowNetworkAccess is not yet set |
|
579 if ( aPropertyValues[EAllowNetworkAccess]->iType != EWidgetPropTypeInt ) |
|
580 { |
|
581 // map true to 1 and false to 0 |
|
582 if ( 0 == element.Compare( KTrue ) ) |
|
583 { |
|
584 *(aPropertyValues[EAllowNetworkAccess]) = 1; |
|
585 } |
|
586 else if ( 0 == element.Compare( KFalse ) ) |
|
587 { |
|
588 *(aPropertyValues[EAllowNetworkAccess]) = 0; |
|
589 } |
|
590 else |
|
591 { |
|
592 User::Leave( KErrCorrupt ); |
|
593 } |
|
594 } |
|
595 } |
|
596 } |
|
597 } // if n is element |
|
598 } // for |
|
599 |
|
600 // validate: all required keys are present |
|
601 TInt i = 0; |
|
602 for ( ; i < EPropertyDescriptionIdCount; ++i ) |
|
603 { |
|
604 if ( (iProperties[i].flags & EMandatory) |
|
605 && (iProperties[i].flags & EConfig) |
|
606 // a prop name maps to some value id |
|
607 && ((EWidgetPropertyIdInvalid != iProperties[i].id) |
|
608 && (aPropertyValues[iProperties[i].id]->iType |
|
609 != iProperties[i].type)) ) |
|
610 { |
|
611 // if cause of mismatch is bool mapped to int, then continue check |
|
612 if ( (EWidgetPropTypeInt != aPropertyValues[iProperties[i].id]->iType) |
|
613 || (EWidgetPropTypeBool != iProperties[i].type) ) |
|
614 { |
|
615 User::Leave( KErrNotSupported ); |
|
616 } |
|
617 } |
|
618 } |
|
619 |
|
620 // TODO: We decided to drop BundleName and just use |
|
621 // DisplayName but the registry code has errors in it and uses |
|
622 // BundleName when it should use DisplayName so as a workaround, |
|
623 // set BundleName to DisplayName. Should eventually remove |
|
624 // BundleName from set of registry values. |
|
625 const TDesC& name = *(aPropertyValues[EBundleDisplayName]); |
|
626 *(aPropertyValues[EBundleName]) = name; |
|
627 |
|
628 // validate values are sane |
|
629 ValidateL( aPropertyValues ); |
|
630 |
|
631 xmlFreeDoc(doc); |
|
632 xmlCleanupParser(); |
|
633 #endif |
|
634 } |
|
635 |
|
636 // ============================================================================ |
|
637 // CWidgetUIConfigHandler::ValidateL |
|
638 // Check values. |
|
639 // |
|
640 // @since 3.1 |
|
641 // @param aPropertyValues output filled with parsed values from buf |
|
642 // ============================================================================ |
|
643 // |
|
644 void CWidgetUIConfigHandler::ValidateL( |
|
645 RPointerArray<CWidgetPropertyValue>& aPropertyValues ) |
|
646 { |
|
647 // leaves with KErrCorrupt if any values are rejected |
|
648 |
|
649 // The limits and their justification: |
|
650 // |
|
651 // Strings are limited to KMaxFileName and must not be empty. |
|
652 // |
|
653 // For values like "Identifier" that will be used in filenames the |
|
654 // fundamental limit in Symbian is KMaxFileName (from e32const.h |
|
655 // and included by essentially all higher level e32*.h). Since |
|
656 // these values will be concatenated with other directory |
|
657 // components, we might think to use a heuristic limit less than |
|
658 // KMaxFileName, but this introduces a needless arbitrary limit |
|
659 // and it will be cleaner to check length against KMaxFileName |
|
660 // after concatenation. Checking here just means detecting a |
|
661 // limit violation earlier and maybe giving a better error |
|
662 // message. Also, the KErrBadName error value from filesystem |
|
663 // operations will signal a pathname problem and MUST be checked. |
|
664 // |
|
665 // For strings like "DisplayName" that will be used in menus there |
|
666 // is no clear predefined value given that displays come in |
|
667 // various sizes and various fonts are used. I'm going to impose |
|
668 // the same limit as for values used in filenames on the belief |
|
669 // that this is useful and not harmfull. |
|
670 |
|
671 // Also, check that values are not empty. |
|
672 |
|
673 TInt i = 0; |
|
674 for (; i < EPropertyDescriptionIdCount; ++i ) |
|
675 { |
|
676 if ( EWidgetPropTypeString == aPropertyValues[i]->iType ) |
|
677 { |
|
678 const TDesC& s = *(aPropertyValues[i]); |
|
679 if ( !s.Length() || ( s.Length() > KMaxFileName ) ) |
|
680 { |
|
681 User::Leave( KErrCorrupt ); |
|
682 } |
|
683 } |
|
684 } |
|
685 } |
|
686 |
|
687 // ============================================================================ |
|
688 // CWidgetUIConfigHandler::ParseInfoLocL() |
|
689 // |
|
690 // @since 3.1 |
|
691 // ============================================================================ |
|
692 // |
|
693 void CWidgetUIConfigHandler::ParseInfoLocL( |
|
694 TPtrC8 aBuffer, |
|
695 RFs& aFileSession, |
|
696 CWidgetPropertyValue& aBundleDisplayName ) |
|
697 { |
|
698 // This logic is for localization of the display name. The |
|
699 // display name appears in a localization file in the form: |
|
700 // DisplayName = "something"; (for Nokia DTD) or |
|
701 // CFBundleDisplayName = "something"; (for Apple DTD). |
|
702 |
|
703 // The encoding of the localization file is not given so it must |
|
704 // be automatically recognized. The default is UTF-8 but if a |
|
705 // byte-order-mark is the first character then the BOM determines |
|
706 // the encoding. |
|
707 |
|
708 // get key name ID for display name depending on DTD |
|
709 TWidgetPropertyDescriptionId displayNameId = EPropertyDescriptionIdInvalid; |
|
710 if ( iDtdType == EDtdTypeNokia ) |
|
711 { |
|
712 displayNameId = EPropertyDescriptionNokiaDisplayName; |
|
713 } |
|
714 else if ( iDtdType == EDtdTypeApple ) |
|
715 { |
|
716 displayNameId = EPropertyDescriptionAppleBundleDisplayName; |
|
717 } |
|
718 if ( EPropertyDescriptionIdInvalid == displayNameId ) |
|
719 { |
|
720 User::Leave( KErrCorrupt ); |
|
721 } |
|
722 |
|
723 TPtrC8 inBuf; |
|
724 |
|
725 // default input encoding, no BOM |
|
726 TInt encoding = KCharacterSetIdentifierUtf8; |
|
727 TInt unicodeSizeMultiplier = 2; // a safe value which may waste some space |
|
728 inBuf.Set( aBuffer ); |
|
729 |
|
730 // check for BOM, we only recognize UTF-16(BE/LE) and UTF-8, |
|
731 // remove BOM if found |
|
732 if ( aBuffer[0] == 0xFE && aBuffer[1] == 0xFF ) |
|
733 { |
|
734 encoding = KCharacterSetIdentifierUnicodeBig; |
|
735 unicodeSizeMultiplier = 1; |
|
736 inBuf.Set( aBuffer.Right( aBuffer.Length() - 2 ) ); |
|
737 } |
|
738 else if ( aBuffer[0] == 0xFF && aBuffer[1] == 0xFE ) |
|
739 { |
|
740 encoding = KCharacterSetIdentifierUnicodeLittle; |
|
741 unicodeSizeMultiplier = 1; |
|
742 inBuf.Set( aBuffer.Right( aBuffer.Length() - 2 ) ); |
|
743 } |
|
744 else if ( aBuffer[0] == 0xEF && aBuffer[1] == 0xBB && aBuffer[2] == 0xBF ) |
|
745 { |
|
746 encoding = KCharacterSetIdentifierUtf8; |
|
747 unicodeSizeMultiplier = 2; // a safe value which may waste some space |
|
748 inBuf.Set( aBuffer.Right( aBuffer.Length() - 3 ) ); |
|
749 } |
|
750 |
|
751 // convert to unicode |
|
752 HBufC16* outBuf; |
|
753 ToUnicodeL( encoding, unicodeSizeMultiplier, |
|
754 inBuf, &outBuf, aFileSession ); |
|
755 CleanupStack::PushL( outBuf ); |
|
756 TPtr16 outPtr = outBuf->Des(); |
|
757 // convert the display name key name to unicode since it is just |
|
758 // _LIT() and so might be 8 bit and we want 16 bit "unicode" |
|
759 TPtrC keyName = iProperties[displayNameId].name; |
|
760 HBufC16* keyNameUnicode = HBufC16::NewLC( keyName.Length() ); |
|
761 TPtr16 keyNameUnicodePtr( keyNameUnicode->Des() ); |
|
762 keyNameUnicodePtr.Copy( keyName ); |
|
763 |
|
764 // parse the display name |
|
765 outPtr.TrimLeft(); // remove leading whitespace |
|
766 TInt pos = outPtr.Find( keyNameUnicodePtr ); |
|
767 if ( (KErrNotFound == pos) || (0 != pos) ) |
|
768 { |
|
769 User::Leave( KErrCorrupt ); |
|
770 } |
|
771 |
|
772 // rest contains buffer after the DisplayName, |
|
773 // i.e. = "some localized text" |
|
774 TPtr16 rest = |
|
775 outPtr.RightTPtr( |
|
776 outPtr.Length() |
|
777 - pos |
|
778 - keyNameUnicode->Length() ); |
|
779 const TUint16* data = rest.Ptr(); |
|
780 TBool hasEqual = EFalse; // already pass the = sign? |
|
781 |
|
782 // start pos and end pos of localized displayname |
|
783 TUint8 start = 0; |
|
784 TUint8 end = 0; |
|
785 for ( TInt i = 0; i < rest.Length(); i++ ) |
|
786 { |
|
787 if ( data[i] == ' ' || data[i] == '\t' ) |
|
788 { |
|
789 continue; |
|
790 } |
|
791 if ( data[i] == '=' ) |
|
792 { |
|
793 hasEqual = ETrue; |
|
794 continue; |
|
795 } |
|
796 if ( data[i] == '\"' ) |
|
797 { |
|
798 if ( !start ) |
|
799 { |
|
800 start = i + 1; |
|
801 continue; |
|
802 } |
|
803 // else already inquote, so this is close quote |
|
804 end = i; |
|
805 break; |
|
806 } |
|
807 if ( !hasEqual || !start ) |
|
808 { |
|
809 User::Leave( KErrCorrupt ); |
|
810 } |
|
811 } |
|
812 |
|
813 if ( end <= start ) |
|
814 { |
|
815 User::Leave( KErrCorrupt ); |
|
816 } |
|
817 TInt left = pos + keyNameUnicode->Length() + start; |
|
818 aBundleDisplayName = outPtr.MidTPtr( left, end - start); |
|
819 CleanupStack::PopAndDestroy( 2 ); // outBuf, keyNameUnicode |
|
820 } |
|
821 |
|
822 // End of File |