|
1 /* |
|
2 * Copyright (c) 2002-2005 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: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 #include <utf.h> |
|
26 |
|
27 #include "SenXmlConstants.h" |
|
28 #include "SenXmlUtils.h" |
|
29 #include "SenElement.h" |
|
30 #include "SenBaseAttribute.h" |
|
31 |
|
32 #ifdef SYMBIAN_SECURE_ECOM |
|
33 // for 2.8, 3.0 or newer: |
|
34 #include <xml/attribute.h> // needed for RAttributeArray |
|
35 #else // for 2.6 or olde |
|
36 #include "Attribute.h" |
|
37 #endif |
|
38 |
|
39 using namespace Xml; |
|
40 |
|
41 EXPORT_C HBufC8* SenXmlUtils::ToUtf8LC(const TDesC16& aUnicodeString) |
|
42 { |
|
43 // 6 times multiplier is the worst case... |
|
44 HBufC8* pBuf8 = HBufC8::NewLC(6 * aUnicodeString.Length()); |
|
45 TPtr8 des8 = pBuf8->Des(); |
|
46 TInt ret = CnvUtfConverter::ConvertFromUnicodeToUtf8(des8, aUnicodeString); |
|
47 User::LeaveIfError(ret); |
|
48 |
|
49 // Shrink allocated memory if possible |
|
50 HBufC8* pReallocBuf8 = pBuf8->ReAlloc(pBuf8->Length()); |
|
51 if (pReallocBuf8 != NULL) |
|
52 { |
|
53 // It could reallocate |
|
54 CleanupStack::Pop(); // pop pBuf8; |
|
55 CleanupStack::PushL(pReallocBuf8); |
|
56 pBuf8 = pReallocBuf8; |
|
57 } |
|
58 return pBuf8; |
|
59 } |
|
60 |
|
61 EXPORT_C HBufC16* SenXmlUtils::ToUnicodeLC(const TDesC8& aUtf8String) |
|
62 { |
|
63 HBufC16* pBuf = HBufC16::NewLC(2 * aUtf8String.Length()); |
|
64 TPtr16 des = pBuf->Des(); |
|
65 TInt ret = CnvUtfConverter::ConvertToUnicodeFromUtf8(des, aUtf8String); |
|
66 User::LeaveIfError(ret); |
|
67 return pBuf; |
|
68 } |
|
69 |
|
70 |
|
71 EXPORT_C TBool SenXmlUtils::StartsWith(const TDesC8& aDes, |
|
72 const TDesC8& aPrefix) |
|
73 { |
|
74 if (aDes.Length() < aPrefix.Length()) |
|
75 { |
|
76 return EFalse; |
|
77 } |
|
78 else |
|
79 { |
|
80 return (aDes.Left(aPrefix.Length()) == aPrefix); |
|
81 } |
|
82 } |
|
83 |
|
84 EXPORT_C TBool SenXmlUtils::EndsWith(const TDesC8& aDes, |
|
85 const TDesC8& aPostfix) |
|
86 { |
|
87 if (aDes.Length() < aPostfix.Length()) |
|
88 { |
|
89 return EFalse; |
|
90 } |
|
91 else |
|
92 { |
|
93 return (aDes.Right(aPostfix.Length()) == aPostfix); |
|
94 } |
|
95 } |
|
96 |
|
97 EXPORT_C TPtrC8 SenXmlUtils::NsPrefix(const TDesC8& aQName) |
|
98 { |
|
99 TInt colonPos = aQName.Find(KSenColon); |
|
100 if (colonPos < 0) |
|
101 { |
|
102 return KNullDesC8(); |
|
103 } |
|
104 else |
|
105 { |
|
106 return aQName.Left(colonPos); |
|
107 } |
|
108 } |
|
109 |
|
110 EXPORT_C TPtrC8 SenXmlUtils::LocalName(const TDesC8& aQName) |
|
111 { |
|
112 TInt colonPos = aQName.Find(KSenColon); |
|
113 if (colonPos < 0) |
|
114 { |
|
115 return aQName; |
|
116 } |
|
117 else |
|
118 { |
|
119 return aQName.Mid(colonPos + 1); |
|
120 } |
|
121 } |
|
122 |
|
123 EXPORT_C TPtrC8 SenXmlUtils::AttrValue( const RAttributeArray& aAttributes, |
|
124 const TDesC8& aAttrName) |
|
125 { |
|
126 TInt count(aAttributes.Count()); |
|
127 for (TInt i=0; i<count;i++) |
|
128 { |
|
129 if (aAttributes[i].Attribute().LocalName().DesC() == aAttrName) |
|
130 { |
|
131 return aAttributes[i].Value().DesC(); |
|
132 } |
|
133 } |
|
134 return KNullDesC8(); |
|
135 } |
|
136 |
|
137 //EXPORT_C TPtrC8 SenXmlUtils::AttrType(const RAttributeArray& aAttributes, |
|
138 // const TDesC8& aAttrName) |
|
139 // { |
|
140 // TInt count(aAttributes.Count()); |
|
141 // for (TInt i=0; i<count;i++) |
|
142 // { |
|
143 // if (aAttributes[i].Attribute().LocalName().DesC() == aAttrName) |
|
144 // { |
|
145 // return aAttributes[i].Type().DesC(); |
|
146 // } |
|
147 // } |
|
148 // return KNullDesC8(); |
|
149 // } |
|
150 |
|
151 EXPORT_C void SenXmlUtils::BuildQNameL( const TDesC8& aPrefix, |
|
152 const TDesC8& aLocalName, |
|
153 HBufC8*& aQName) |
|
154 { |
|
155 aQName = HBufC8::NewLC( aPrefix.Length()+KSenColon().Length() |
|
156 +aLocalName.Length() ); |
|
157 if (aPrefix != KNullDesC8) |
|
158 { |
|
159 aQName->Des().Append(aPrefix); |
|
160 aQName->Des().Append(KSenColon); |
|
161 } |
|
162 aQName->Des().Append(aLocalName); |
|
163 CleanupStack::Pop(); |
|
164 |
|
165 } |
|
166 |
|
167 EXPORT_C TBool SenXmlUtils::EncodeHttpCharactersL(const TDesC8& aOriginal, |
|
168 HBufC8*& aEncoded) |
|
169 { |
|
170 TBool retVal = EFalse; |
|
171 delete aEncoded; |
|
172 aEncoded = NULL; |
|
173 |
|
174 if (aOriginal == KNullDesC8) |
|
175 { |
|
176 return retVal; |
|
177 } |
|
178 TPtrC8 tokens[] = |
|
179 { |
|
180 KSenEscapedAmp(), |
|
181 KSenEscapedApos(), |
|
182 KSenEscapedDblQuot(), |
|
183 KSenEscapedGt(), |
|
184 KSenEscapedLt() |
|
185 }; |
|
186 TText16 tokenChars[] = |
|
187 { |
|
188 '&', |
|
189 '\'', |
|
190 '\"', |
|
191 '>', |
|
192 '<' |
|
193 }; |
|
194 |
|
195 // Replace escaped characters, if any |
|
196 for (TInt i = 0; i < aOriginal.Length(); i++) |
|
197 { |
|
198 TBool foundChar = EFalse; |
|
199 for (TUint j = 0; j < (sizeof(tokenChars) / sizeof(TText16)); j++) |
|
200 { |
|
201 if (aOriginal[i] == tokenChars[j]) |
|
202 { |
|
203 if (!aEncoded) |
|
204 { |
|
205 aEncoded = |
|
206 HBufC8::NewL(aOriginal.Length() * KSenMaxXmlEscapedLength); |
|
207 aEncoded->Des().Append(aOriginal.Left(i)); |
|
208 } |
|
209 foundChar = ETrue; |
|
210 aEncoded->Des().Append(tokens[j]); |
|
211 retVal = ETrue; // indicate, that encoding was done |
|
212 break; |
|
213 } |
|
214 } |
|
215 if (!foundChar) |
|
216 { |
|
217 if (aEncoded) |
|
218 { |
|
219 |
|
220 aEncoded->Des().Append(aOriginal[i]); |
|
221 } |
|
222 } |
|
223 } |
|
224 |
|
225 return retVal; |
|
226 } |
|
227 |
|
228 EXPORT_C HBufC8* SenXmlUtils::EncodeHttpCharactersLC( const TDesC8& aOriginal ) |
|
229 { |
|
230 HBufC8* pDecoded = NULL; |
|
231 if (!EncodeHttpCharactersL(aOriginal, pDecoded)) |
|
232 { |
|
233 // if anything was allocated (never in current implementation) |
|
234 delete pDecoded; |
|
235 pDecoded = NULL; |
|
236 |
|
237 // make a copy of original, so that caller always knows that |
|
238 // there is something from which to take ownership. |
|
239 pDecoded = aOriginal.AllocL(); |
|
240 } |
|
241 CleanupStack::PushL(pDecoded); |
|
242 return pDecoded; |
|
243 } |
|
244 |
|
245 TBool SenXmlUtils::ReplaceAll(TPtr8 aDestination, |
|
246 const TDesC8& aFrom, |
|
247 const TDesC8& aTo) |
|
248 { |
|
249 TInt retVal(EFalse); |
|
250 |
|
251 TInt pos = aDestination.Find(aFrom); |
|
252 if (pos != KErrNotFound) retVal = ETrue; |
|
253 |
|
254 while (pos != KErrNotFound) |
|
255 { |
|
256 aDestination.Replace(pos,aFrom.Length(),aTo); |
|
257 pos = aDestination.Find(aFrom); |
|
258 } |
|
259 |
|
260 return retVal; |
|
261 } |
|
262 /** |
|
263 * DecodeHttpCharactersL() returns ETrue, if any XML escaping |
|
264 * (some Basic Entity) character-sequence was decoded. |
|
265 * |
|
266 * Note that aDecoded points to a copy of the original string |
|
267 * even if there were no basic entities to decode. Otherwise, |
|
268 * it points to a newly allocated descriptor, where some |
|
269 * basic entity or entities has been decoded (replaced) from |
|
270 * aOriginal descriptor. |
|
271 * |
|
272 */ |
|
273 EXPORT_C TBool SenXmlUtils::DecodeHttpCharactersL( const TDesC8& aOriginal, |
|
274 HBufC8*& aDecoded ) |
|
275 { |
|
276 delete aDecoded; |
|
277 aDecoded = NULL; |
|
278 |
|
279 // make a copy of the original |
|
280 aDecoded = aOriginal.AllocL(); |
|
281 |
|
282 TBool retVal(EFalse); |
|
283 |
|
284 |
|
285 // replace all five basic entities with XML escaping counterpart, |
|
286 // if found. |
|
287 if (ReplaceAll(aDecoded->Des(), KSenEscapedAmp(), KSenAmpersandDesC8())) |
|
288 { |
|
289 retVal = ETrue; |
|
290 } |
|
291 if (ReplaceAll(aDecoded->Des(), KSenEscapedApos(), KSenAposDesC8())) |
|
292 { |
|
293 retVal = ETrue; |
|
294 } |
|
295 if (ReplaceAll(aDecoded->Des(), KSenEscapedDblQuot(), KSenDblQuotDesC8())) |
|
296 { |
|
297 retVal = ETrue; |
|
298 } |
|
299 if (ReplaceAll(aDecoded->Des(), KSenEscapedGt(), KSenGtDesC8())) |
|
300 { |
|
301 retVal = ETrue; |
|
302 } |
|
303 if (ReplaceAll(aDecoded->Des(), KSenEscapedLt(), KSenLtDesC8())) |
|
304 { |
|
305 retVal = ETrue; |
|
306 } |
|
307 |
|
308 return retVal; |
|
309 } |
|
310 |
|
311 /** |
|
312 * In Symbian OS v9.1, see |
|
313 * Location: EscapeUtils.h |
|
314 * Link against: inetprotutil.lib |
|
315 * |
|
316 */ |
|
317 EXPORT_C HBufC8* SenXmlUtils::DecodeHttpCharactersLC(const TDesC8& aOriginal) |
|
318 { |
|
319 HBufC8* pDecoded = NULL; |
|
320 |
|
321 // Attempt to decode. Note, that even if no Basic Entities were |
|
322 // decoded into XML escaping characters (&,',",< or >), this |
|
323 // function will return a pointer to a copy of the original |
|
324 // descriptor. |
|
325 DecodeHttpCharactersL(aOriginal, pDecoded); |
|
326 |
|
327 // Push to cleanup stack |
|
328 CleanupStack::PushL(pDecoded); |
|
329 return pDecoded; |
|
330 } |
|
331 |
|
332 EXPORT_C HBufC8* SenXmlUtils::AllocAttrValueL( const RAttributeArray& apAttrs, |
|
333 const TDesC8& aAttrName ) |
|
334 { |
|
335 TPtrC8 p = AttrValue(apAttrs, aAttrName); |
|
336 if (p == KNullDesC8) |
|
337 { |
|
338 return NULL; |
|
339 } |
|
340 else |
|
341 { |
|
342 return p.AllocL(); |
|
343 } |
|
344 } |
|
345 |
|
346 // the non-optimized version: |
|
347 /* |
|
348 EXPORT_C void SenXmlUtils::LeaveOnXmlEscapesL(const TDesC8& aCandidate) |
|
349 { |
|
350 HBufC8* pValidator = NULL; |
|
351 |
|
352 // check if there are any XML escaping character by calling |
|
353 // basic entity encoding function. |
|
354 TBool containsEscapes = SenXmlUtils::EncodeHttpCharactersL(aCandidate, pValidator); |
|
355 |
|
356 delete pValidator; |
|
357 |
|
358 if(containsEscapes) |
|
359 { |
|
360 // some XML-escaping character was found. |
|
361 // Indicate with Leave, that the given |
|
362 // aChars descriptor is illegal, because |
|
363 // it contained invalid characters |
|
364 User::Leave(KErrSenInvalidCharacters); |
|
365 } |
|
366 } |
|
367 */ |
|
368 |
|
369 // Optimized, but not throughoutly tested version. |
|
370 // Based on UPnP project optimizations (2005-10-13). |
|
371 |
|
372 EXPORT_C void SenXmlUtils::LeaveOnXmlEscapesL(const TDesC8& aCandidate) |
|
373 { |
|
374 // these are the escapes which are searched after |
|
375 TText16 tokenChars[] = |
|
376 { |
|
377 '&', |
|
378 '\'', |
|
379 '\"', |
|
380 '>', |
|
381 '<' |
|
382 }; |
|
383 |
|
384 // Search for XML escaping characters |
|
385 for (TInt i=0; i<aCandidate.Length(); i++) |
|
386 { |
|
387 for (TUint j = 0; j < (sizeof(tokenChars) / sizeof(TText16)); j++) |
|
388 { |
|
389 if (aCandidate[i] == tokenChars[j]) |
|
390 { |
|
391 // some XML-escaping character was found. |
|
392 // Indicate with Leave, that the given |
|
393 // aChars descriptor is illegal, because |
|
394 // it contained invalid characters |
|
395 User::Leave(KErrSenInvalidCharacters); |
|
396 } |
|
397 } |
|
398 } |
|
399 } |
|
400 |
|
401 void SenXmlUtils::LeaveOnInvalidElementNameL(const TDesC8& aCandidate) |
|
402 { |
|
403 if (aCandidate == KNullDesC8) |
|
404 { |
|
405 User::Leave(KErrSenZeroLengthDescriptor); |
|
406 } |
|
407 SenXmlUtils::LeaveOnXmlEscapesL(aCandidate); |
|
408 } |
|
409 |
|
410 EXPORT_C CSenBaseAttribute* SenXmlUtils::RemoveAttributeL(CSenElement& aElement, |
|
411 const TDesC8& aAttrName) |
|
412 { |
|
413 CSenBaseAttribute* pAttribute = SenXmlUtils::FindAttrL( aElement, aAttrName ); |
|
414 if ( pAttribute ) |
|
415 { |
|
416 RPointerArray<CSenBaseAttribute>& attributes = aElement.AttributesL(); |
|
417 |
|
418 TInt index(attributes.Find(pAttribute)); |
|
419 if ( index != KErrNotFound ) |
|
420 { |
|
421 attributes.Remove(index); // release ownership |
|
422 } |
|
423 else |
|
424 { |
|
425 // should never occur: |
|
426 pAttribute = NULL; // ownership could not be transferred.. |
|
427 } |
|
428 } |
|
429 |
|
430 return pAttribute; |
|
431 } |
|
432 |
|
433 EXPORT_C CSenBaseAttribute* SenXmlUtils::RemoveAttributeL(CSenElement& aElement, |
|
434 CSenBaseAttribute* apAttribute) |
|
435 { |
|
436 return SenXmlUtils::RemoveAttributeL(aElement, apAttribute->Name()); |
|
437 } |
|
438 |
|
439 CSenBaseAttribute* SenXmlUtils::FindAttrL( CSenElement& aElement, |
|
440 const TDesC8& aName ) |
|
441 { |
|
442 RPointerArray<CSenBaseAttribute>& attributes = aElement.AttributesL(); |
|
443 |
|
444 TInt count(attributes.Count()); |
|
445 for (TInt i = 0; i < count; i++) |
|
446 { |
|
447 CSenBaseAttribute* pAttribute = attributes[i]; |
|
448 if ( pAttribute->Name() == aName ) |
|
449 { |
|
450 return pAttribute; |
|
451 } |
|
452 } |
|
453 |
|
454 return NULL; |
|
455 } |
|
456 |
|
457 EXPORT_C const TDesC8& SenXmlUtils::AddAttributeL(CSenElement& aElement, |
|
458 const TDesC8& aQName, |
|
459 const TDesC8& aLocalName, |
|
460 const TDesC8& aValue) |
|
461 { |
|
462 // first we check for possible namespace declarations... |
|
463 if ( aQName == KSenXmlns || aLocalName == KSenXmlns) |
|
464 { |
|
465 // this is a default name space declaration |
|
466 aElement.SetNamespaceL(aValue); |
|
467 } |
|
468 else if (aLocalName == aElement.NsPrefix()) |
|
469 { |
|
470 //we have a new declaration for the namespace of this element |
|
471 aElement.SetNamespaceL(aLocalName, aValue); |
|
472 } |
|
473 else if(aQName.Find(KSenXmlNsAttNamePlusColon) == 0) |
|
474 { |
|
475 // we have an additional namespace declaration |
|
476 aElement.AddNamespaceL(aLocalName, aValue); |
|
477 } |
|
478 else |
|
479 { |
|
480 // we have a real attribute! |
|
481 CSenBaseAttribute* pAttribute = CSenBaseAttribute::NewL(aQName, |
|
482 aLocalName, |
|
483 aValue); |
|
484 AddAttributeL(aElement, pAttribute); |
|
485 } |
|
486 return aValue; |
|
487 } |
|
488 |
|
489 EXPORT_C const TDesC8& SenXmlUtils::AddAttributeL(CSenElement& aElement, |
|
490 const TDesC8& aAttrName, |
|
491 const TDesC8& aValue) |
|
492 { |
|
493 // note, the aAttrName may be a qualified name or simply localname |
|
494 // strip off the possible prefix from possible qualified name: |
|
495 TPtrC8 localName = SenXmlUtils::LocalName(aAttrName); |
|
496 return AddAttributeL(aElement, aAttrName, localName, aValue); |
|
497 } |
|
498 |
|
499 EXPORT_C const TDesC8& SenXmlUtils::AddAttributeL(CSenElement& aElement, |
|
500 CSenBaseAttribute* apAttribute) |
|
501 { |
|
502 CSenBaseAttribute* pOldAtt = FindAttrL( aElement, apAttribute->Name() ); |
|
503 |
|
504 if(!pOldAtt) |
|
505 { |
|
506 // transfrer the ownership to this class: |
|
507 RPointerArray<CSenBaseAttribute>& attributes = aElement.AttributesL(); |
|
508 #ifdef EKA2 |
|
509 attributes.AppendL(apAttribute); |
|
510 #else |
|
511 User::LeaveIfError(attributes.Append(apAttribute)); |
|
512 #endif // EKA2 |
|
513 return apAttribute->Value(); |
|
514 } |
|
515 else |
|
516 { |
|
517 pOldAtt->SetValueL(apAttribute->Value()); |
|
518 delete apAttribute; |
|
519 apAttribute = NULL; |
|
520 return pOldAtt->Value(); |
|
521 } |
|
522 } |
|
523 |
|
524 // END OF FILE |
|
525 |