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