|
1 // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 #include <charconv.h> |
|
17 |
|
18 #include <xml/contenthandler.h> |
|
19 #include <xml/documentparameters.h> |
|
20 #include <xml/taginfo.h> |
|
21 #include <xml/xmlparsererrors.h> |
|
22 #include <xml/plugins/charsetconverter.h> |
|
23 |
|
24 #include "cexpat.h" |
|
25 |
|
26 using namespace Xml; |
|
27 |
|
28 const XML_Char KNamespaceSeparator = '!'; |
|
29 const TInt KExpatHeapSize = 64*1024-256; |
|
30 |
|
31 LOCAL_C void AttributeArrayDelete(TAny *aPtr); |
|
32 |
|
33 /* |
|
34 aDebugFailCount is for testing only, to configure the parser heap to fail during CExpat construction. |
|
35 |
|
36 After construction CExpat::GetInternalHeap() can be used in conjunction with __RHEAP_FAILNEXT |
|
37 for out-of-memory testing. |
|
38 */ |
|
39 CExpat* CExpat::NewL(MContentHandler& aContentHandler, RStringPool& aStringPool, CCharSetConverter& aCharSetConverter, |
|
40 RElementStack& aElementStack, TInt aDebugFailCount) |
|
41 { |
|
42 CExpat* self = new(ELeave) CExpat(aContentHandler, aStringPool, aCharSetConverter, aElementStack); |
|
43 |
|
44 CleanupStack::PushL(self); |
|
45 self->ConstructL(aDebugFailCount); |
|
46 CleanupStack::Pop(self); |
|
47 |
|
48 return self; |
|
49 } |
|
50 |
|
51 CExpat::CExpat(MContentHandler& aContentHandler, RStringPool& aStringPool, CCharSetConverter& aCharSetConverter, |
|
52 RElementStack& aElementStack) : |
|
53 iContentHandler(&aContentHandler), iStringPool(aStringPool), iCharSetConverter(aCharSetConverter), |
|
54 iElementStack(aElementStack), iInputBuffer(0,0,0), |
|
55 iPrevStatus(XML_STATUS_OK), |
|
56 iPrevError(KErrNone) |
|
57 { |
|
58 } |
|
59 |
|
60 void CExpat::ConstructL(TInt aDebugFailCount) |
|
61 { |
|
62 iAllocator.ConstructL(KExpatHeapSize, aDebugFailCount); |
|
63 ResetL(); |
|
64 } |
|
65 |
|
66 CExpat::~CExpat() |
|
67 { |
|
68 // iParser must be freed here. The destructor of iAllocator (~TExpat) is called automatically |
|
69 // when CExpat is destructed, as it is a member variable of CExpat. *But* ~TExpat() will only close its heap |
|
70 // which does not free any memory allocated on it. So - we have to free the memory here, before |
|
71 // deleting the allocator. This memory is guaranteed to be freed here, before the heap is closed |
|
72 // as the body of the destructor completes before the member destructors (~TExpat) are called. |
|
73 if ( iParser ) |
|
74 { |
|
75 XML_ParserFree( iParser ); |
|
76 } |
|
77 } |
|
78 |
|
79 /* |
|
80 ResetL resets an the parser or allocates one if none exists. This could be the case for one of two reasons: |
|
81 |
|
82 1. This is called as part of the construction of CExpat |
|
83 2. A MContentHandler function left. In this case the parser and all its memory will have been deleted. |
|
84 |
|
85 */ |
|
86 void CExpat::ResetL() |
|
87 { |
|
88 iParseMode = EReportNamespaces | EReportNamespacePrefixes; |
|
89 iBufferReady = EFalse; |
|
90 |
|
91 iPrevStatus = XML_STATUS_OK; |
|
92 iPrevError = KErrNone; |
|
93 |
|
94 if(iParser) |
|
95 XML_ParserReset(iParser, NULL); |
|
96 else |
|
97 { |
|
98 XML_Memory_Handling_Suite m; |
|
99 iAllocator.FillAllocStruct(m); |
|
100 |
|
101 // Expat element/attribute names are passed as a single string containing the prefix, uri and local part. |
|
102 // This character is used to separate those three parts. |
|
103 XML_Char sep[] = { KNamespaceSeparator, 0 }; |
|
104 |
|
105 iParser = XML_ParserCreate_MM(0, &m, sep); |
|
106 User::LeaveIfNull(iParser); |
|
107 } |
|
108 |
|
109 // UserData is the first argument passed to us by all Expat callbacks |
|
110 XML_SetUserData(iParser, this); |
|
111 |
|
112 XML_SetElementHandler(iParser, StartElementHandlerL, EndElementHandlerL); |
|
113 XML_SetCharacterDataHandler(iParser, CharacterDataHandlerL); |
|
114 XML_SetProcessingInstructionHandler(iParser, ProcessingInstructionHandlerL); |
|
115 XML_SetXmlDeclHandler(iParser, XmlDeclHandlerL); |
|
116 |
|
117 XML_SetNamespaceDeclHandler(iParser, StartNamespaceDeclHandlerL, EndNamespaceDeclHandlerL); |
|
118 |
|
119 // This tells Expat to pass all three parts of element/attribute names to us: prefix, uri and local part |
|
120 XML_SetReturnNSTriplet(iParser, 1); |
|
121 |
|
122 XML_SetSkippedEntityHandler(iParser, SkippedEntityHandlerL); |
|
123 XML_SetExternalEntityRefHandler(iParser, ExternalEntityRefHandlerL); |
|
124 } |
|
125 |
|
126 TDes8& CExpat::GetBufferL(TInt aLength) |
|
127 { |
|
128 TUint8* buf = (TUint8*) User::LeaveIfNull(XML_GetBuffer(iParser, aLength)); |
|
129 |
|
130 iInputBuffer.Set(buf, 0, aLength); |
|
131 |
|
132 iBufferReady = ETrue; |
|
133 |
|
134 return iInputBuffer; |
|
135 } |
|
136 |
|
137 void CExpat::ParseL(TBool done) |
|
138 { |
|
139 // GetBufferL must be called before each call to this function |
|
140 if(!iBufferReady) |
|
141 User::Leave(KErrNotReady); |
|
142 |
|
143 iBufferReady = EFalse; |
|
144 |
|
145 XML_Status status = XML_STATUS_OK; |
|
146 TInt error = KErrNone; |
|
147 |
|
148 // Two forms of error come out of here: error will be set if an MContentHandler function has left, |
|
149 // status notifies us of an internal from Expat |
|
150 TRAP(error, status=XML_ParseBuffer(iParser, iInputBuffer.Length(), done)); |
|
151 |
|
152 if(error!=KErrNone) |
|
153 { |
|
154 // If a MContentHandler function left it is possible that some allocated memory may be |
|
155 // leaked. We don't take that chance and de-allocate the parser and all its memory. |
|
156 iParser = 0; |
|
157 iAllocator.ResetL(); |
|
158 |
|
159 ClearElementStack(); |
|
160 |
|
161 // ResetL must be called to re-activate it. |
|
162 ResetL(); |
|
163 |
|
164 User::Leave(error); |
|
165 } |
|
166 |
|
167 if(status==XML_STATUS_ERROR) |
|
168 { |
|
169 error = (TInt)XML_GetErrorCode(iParser); |
|
170 |
|
171 if(error == (TInt)XML_ERROR_NO_MEMORY) |
|
172 error = KErrNoMemory; |
|
173 else |
|
174 error += (EXmlSyntax-XML_ERROR_SYNTAX); // Convert to our external error range |
|
175 |
|
176 ClearElementStack(); |
|
177 |
|
178 // We don't want to regenerate the same callback. So check |
|
179 // that the conditions are different. |
|
180 // I.e. if the last parse resulted in a fatal error then |
|
181 // subsequent parses will invoke the errorProcessor with the |
|
182 // same error and status returned. Nothing more will be parsed. |
|
183 if (iPrevStatus != XML_STATUS_ERROR || iPrevError != error) |
|
184 { |
|
185 iContentHandler->OnError(error); |
|
186 } |
|
187 } |
|
188 else if(done) |
|
189 { |
|
190 iContentHandler->OnEndDocumentL(KErrNone); |
|
191 } |
|
192 |
|
193 iPrevError = error; |
|
194 iPrevStatus = status; |
|
195 } |
|
196 |
|
197 const TInt KOptionalFeatures = EConvertTagsToLowerCase | EReportNamespaceMapping; |
|
198 const TInt KMandatoryFeatures = EReportNamespaces | EReportNamespacePrefixes; |
|
199 |
|
200 TInt CExpat::EnableFeature(TInt aParseMode) |
|
201 { |
|
202 if(aParseMode & ~(KOptionalFeatures | KMandatoryFeatures)) |
|
203 return KErrNotSupported; |
|
204 |
|
205 iParseMode |= aParseMode | KMandatoryFeatures; |
|
206 |
|
207 return KErrNone; |
|
208 } |
|
209 |
|
210 TInt CExpat::DisableFeature(TInt aParseMode) |
|
211 { |
|
212 if(aParseMode & KMandatoryFeatures) |
|
213 return KErrNotSupported; |
|
214 |
|
215 iParseMode &= ~aParseMode; |
|
216 |
|
217 return KErrNone; |
|
218 } |
|
219 |
|
220 TBool CExpat::IsFeatureEnabled(TInt aParseMode) const |
|
221 { |
|
222 return iParseMode & aParseMode; |
|
223 } |
|
224 |
|
225 |
|
226 void CExpat::SetContentSink(class MContentHandler &aContentSink) |
|
227 { |
|
228 iContentHandler = &aContentSink; |
|
229 } |
|
230 |
|
231 /* |
|
232 CreateRStringL converts the UTF-16 descriptor to UTF-8 and stores it in the stringpool. |
|
233 */ |
|
234 void CExpat::CreateRStringL(const TDesC& aInput, RString& aString, TBool aLowerCase) |
|
235 { |
|
236 TPtr8 conversionOutput(0,0); |
|
237 //Uses the more efficient TPtr overload of ConvertFromUnicode. |
|
238 TInt error = iCharSetConverter.ConvertFromUnicodeL(aInput, KCharacterSetIdentifierUtf8, conversionOutput); |
|
239 User::LeaveIfError(error>0 ? KErrCorrupt : error); |
|
240 |
|
241 if(aLowerCase) |
|
242 conversionOutput.LowerCase(); |
|
243 |
|
244 aString = iStringPool.OpenStringL(conversionOutput); |
|
245 } |
|
246 |
|
247 /* |
|
248 ScanNameL takes a null-terminated UTF-16 string of the form "uri!prefix!localpart" (although prefix, or uri and prefix, |
|
249 may not be there. The separated parts will be converted to UTF-8 and stored in the stringpool. |
|
250 |
|
251 The prefix and local part will be converted to lowercase if EConvertTagsToLowerCase is one of the |
|
252 current parse modes. |
|
253 */ |
|
254 void CExpat::ScanNameL(const XML_Char* aName16, RString& aUriString, RString& aLocalPartString, RString& aPrefixString) |
|
255 { |
|
256 const TUint16* uri = 0; |
|
257 const TUint16* prefix = 0; |
|
258 const TUint16* localPart; |
|
259 const TUint16* p; |
|
260 |
|
261 p = localPart = (TUint16*)aName16; |
|
262 |
|
263 while(*p) |
|
264 if(*p++ == KNamespaceSeparator) |
|
265 { |
|
266 uri = (TUint16*)aName16; |
|
267 localPart = p; |
|
268 break; |
|
269 } |
|
270 |
|
271 while(*p) |
|
272 if(*p++ == KNamespaceSeparator) |
|
273 { |
|
274 prefix = p; |
|
275 break; |
|
276 } |
|
277 |
|
278 while(*p) |
|
279 p++; |
|
280 |
|
281 TBool lowerCase = iParseMode & EConvertTagsToLowerCase; |
|
282 XML_Char nullString[] = ""; |
|
283 |
|
284 if(uri) |
|
285 CreateRStringL(TPtrC16(uri, localPart-uri-1), aUriString, EFalse); |
|
286 else |
|
287 aUriString = iStringPool.OpenStringL(TPtrC8((unsigned char*)nullString, 0)); |
|
288 CleanupClosePushL(aUriString); |
|
289 |
|
290 |
|
291 if(prefix) |
|
292 CreateRStringL(TPtrC16(prefix, p-prefix), aPrefixString , lowerCase); |
|
293 else |
|
294 aPrefixString = iStringPool.OpenStringL(TPtrC8((unsigned char*)nullString, 0)); |
|
295 CleanupClosePushL(aPrefixString); |
|
296 |
|
297 CreateRStringL(TPtrC16(localPart, (prefix ? prefix-1 : p)-localPart), aLocalPartString, lowerCase); |
|
298 |
|
299 CleanupStack::Pop(2); |
|
300 } |
|
301 |
|
302 void CExpat::StartElementHandlerL(void* aUserData, const XML_Char* aName, const XML_Char** aAtts) |
|
303 { |
|
304 ((CExpat*)aUserData)->HandleStartElementL(aName, aAtts); |
|
305 } |
|
306 |
|
307 void CExpat::HandleStartElementL(const XML_Char* aName, const XML_Char** aAtts) |
|
308 { |
|
309 RString uriString, nameString, prefixString; |
|
310 ScanNameL(aName, uriString, nameString, prefixString); |
|
311 |
|
312 RTagInfo tagInfo; |
|
313 tagInfo.Open(uriString, prefixString, nameString); |
|
314 CleanupClosePushL(tagInfo); |
|
315 |
|
316 // Only create a copy of nameString if the append succeeds |
|
317 User::LeaveIfError(iElementStack.Append(nameString)); |
|
318 nameString.Copy(); // i.e. iElementStack now has a copy so flag this to the stringpool |
|
319 |
|
320 // Count the number of attributes in aAtts |
|
321 // |
|
322 // The layout of aAtts is an array of name, value, name, value, name, ... |
|
323 // ... hence each attribute has two strings giving rise to the "att += 2;" |
|
324 const XML_Char** att = aAtts; |
|
325 while (*att) |
|
326 att += 2; |
|
327 TInt nAttributes = (att-aAtts)/2; |
|
328 |
|
329 RAttributeArray attributes; |
|
330 CleanupStack::PushL(TCleanupItem(AttributeArrayDelete, &attributes)); |
|
331 |
|
332 att = aAtts; |
|
333 for(TInt i=0; i<nAttributes; i++) |
|
334 { |
|
335 RString attUriString, attNameString, attPrefixString; |
|
336 ScanNameL(*att, attUriString, attNameString, attPrefixString); |
|
337 CleanupClosePushL(attUriString); |
|
338 CleanupClosePushL(attNameString); |
|
339 CleanupClosePushL(attPrefixString); |
|
340 att++; |
|
341 |
|
342 |
|
343 RString attValueString; |
|
344 CreateRStringL(TPtrC((TUint16*)*att, StringLen((TUint16*)*att)), attValueString, EFalse); |
|
345 att++; |
|
346 |
|
347 CleanupStack::Pop(3); // RAttribute will own the RStrings |
|
348 |
|
349 RAttribute attribute; |
|
350 attribute.Open(attUriString, attPrefixString, attNameString, attValueString); |
|
351 |
|
352 CleanupClosePushL(attribute); |
|
353 User::LeaveIfError(attributes.Append(attribute)); |
|
354 CleanupStack::Pop(); |
|
355 } |
|
356 |
|
357 iContentHandler->OnStartElementL(tagInfo, attributes, KErrNone); |
|
358 |
|
359 CleanupStack::PopAndDestroy(2); // Finished with RTagInfo and RAttributeArray |
|
360 } |
|
361 |
|
362 void CExpat::EndElementHandlerL(void* aUserData, const XML_Char* aName) |
|
363 { |
|
364 ((CExpat*)aUserData)->HandleEndElementL(aName); |
|
365 } |
|
366 |
|
367 void CExpat::HandleEndElementL(const XML_Char* aName) |
|
368 { |
|
369 RString uriString, nameString, prefixString; |
|
370 ScanNameL(aName, uriString, nameString, prefixString); |
|
371 |
|
372 RTagInfo tagInfo; |
|
373 tagInfo.Open(uriString, prefixString, nameString); |
|
374 CleanupClosePushL(tagInfo); |
|
375 |
|
376 TInt i = iElementStack.Count() - 1; |
|
377 |
|
378 // Expat will raise an error if the wrong element is closed. We only get an error here |
|
379 // if somehow our element stack is wrong. |
|
380 if(iElementStack[i]!=nameString) |
|
381 User::Leave(KErrCorrupt); |
|
382 |
|
383 iElementStack[i].Close(); |
|
384 iElementStack.Remove(i); |
|
385 |
|
386 iContentHandler->OnEndElementL(tagInfo, KErrNone); |
|
387 |
|
388 CleanupStack::PopAndDestroy(); // Finished with RTagInfo |
|
389 } |
|
390 |
|
391 void CExpat::CharacterDataHandlerL(void* aUserData, const XML_Char* aString, int aLen) |
|
392 { |
|
393 ((CExpat*)aUserData)->HandleCharacterDataL(aString, aLen); |
|
394 } |
|
395 |
|
396 void CExpat::HandleCharacterDataL(const XML_Char* aString, int aLen) |
|
397 { |
|
398 TPtr8 conversionOutput(0,0); |
|
399 //Uses the more efficient TPtr overload of ConvertFromUnicode |
|
400 TInt error = iCharSetConverter.ConvertFromUnicodeL(TPtrC16((TUint16*)aString, aLen), KCharacterSetIdentifierUtf8, conversionOutput); |
|
401 User::LeaveIfError(error>0 ? KErrCorrupt : error); |
|
402 iContentHandler->OnContentL(conversionOutput, KErrNone); |
|
403 } |
|
404 |
|
405 void CExpat::ProcessingInstructionHandlerL(void* aUserData, const XML_Char* aTarget, const XML_Char* aData) |
|
406 { |
|
407 ((CExpat*)aUserData)->HandleProcessingInstructionL(aTarget, aData); |
|
408 } |
|
409 |
|
410 void CExpat::HandleProcessingInstructionL(const XML_Char* aTarget, const XML_Char* aData) |
|
411 { |
|
412 TPtr8 utf8target(0,0); |
|
413 //Uses the more efficient TPtr overload of the ConvertFromUnicodeL function |
|
414 TInt error = iCharSetConverter.ConvertFromUnicodeL(TPtrC16((TUint16*)aTarget, StringLen((TUint16*)aTarget)), KCharacterSetIdentifierUtf8, utf8target); |
|
415 User::LeaveIfError(error>0 ? KErrCorrupt : error); |
|
416 |
|
417 HBufC8 *utf8data; |
|
418 //Uses the HBufC overload of ConvertFromUnicodeL as the data in the TPtr overload is still needed. |
|
419 error = iCharSetConverter.ConvertFromUnicodeL(TPtrC16((TUint16*)aData, StringLen((TUint16*)aData)), KCharacterSetIdentifierUtf8, utf8data); |
|
420 CleanupStack::PushL(utf8data); |
|
421 User::LeaveIfError(error>0 ? KErrCorrupt : error); |
|
422 |
|
423 iContentHandler->OnProcessingInstructionL(utf8target, utf8data->Des(), KErrNone); |
|
424 |
|
425 CleanupStack::PopAndDestroy(utf8data); |
|
426 } |
|
427 |
|
428 void CExpat::XmlDeclHandlerL(void* aUserData, const XML_Char* aVersion, const XML_Char* aEncoding, int aStandalone) |
|
429 { |
|
430 ((CExpat*)aUserData)->HandleXmlDeclL(aVersion, aEncoding, aStandalone); |
|
431 } |
|
432 |
|
433 void CExpat::HandleXmlDeclL(const XML_Char*, const XML_Char* aEncoding16, int) |
|
434 { |
|
435 // |
|
436 // Encoding |
|
437 // |
|
438 RString encodingString; |
|
439 |
|
440 if (aEncoding16) |
|
441 { |
|
442 TInt len = StringLen((TUint16*)aEncoding16); |
|
443 TPtr8 encoding8 = HBufC8::NewLC(len)->Des(); |
|
444 encoding8.Copy(TPtrC16((TUint16*)aEncoding16, len)); |
|
445 encodingString = iStringPool.OpenStringL(encoding8); |
|
446 CleanupStack::PopAndDestroy(); |
|
447 } |
|
448 else |
|
449 { |
|
450 encodingString = iStringPool.OpenStringL(KNullDesC8()); |
|
451 } |
|
452 |
|
453 CleanupClosePushL(encodingString); |
|
454 |
|
455 RDocumentParameters params; |
|
456 params.Open(encodingString); |
|
457 CleanupStack::Pop(); // encodingString |
|
458 CleanupClosePushL(params); |
|
459 |
|
460 iContentHandler->OnStartDocumentL(params, KErrNone); |
|
461 |
|
462 CleanupStack::PopAndDestroy(); // Finished with params |
|
463 } |
|
464 |
|
465 void CExpat::StartNamespaceDeclHandlerL(void* aUserData, const XML_Char* aPrefix, const XML_Char* aUri) |
|
466 { |
|
467 ((CExpat*)aUserData)->HandleStartNamespaceDeclL(aPrefix, aUri); |
|
468 } |
|
469 |
|
470 void CExpat::HandleStartNamespaceDeclL(const XML_Char* aPrefix, const XML_Char* aUri) |
|
471 { |
|
472 if(iParseMode & EReportNamespaceMapping) |
|
473 { |
|
474 RString prefixString; |
|
475 RString uriString; |
|
476 unsigned char nullString[] = ""; |
|
477 |
|
478 if(aPrefix) |
|
479 CreateRStringL(TPtrC((TUint16*)aPrefix, StringLen((TUint16*)aPrefix)), prefixString, EFalse); |
|
480 else |
|
481 { |
|
482 prefixString = iStringPool.OpenStringL(TPtrC8(nullString, 0)); |
|
483 } |
|
484 CleanupClosePushL(prefixString); |
|
485 |
|
486 |
|
487 if(aUri) |
|
488 CreateRStringL(TPtrC((TUint16*)aUri, StringLen((TUint16*)aUri)), uriString, EFalse); |
|
489 else |
|
490 { |
|
491 uriString = iStringPool.OpenStringL(TPtrC8(nullString, 0)); |
|
492 } |
|
493 CleanupClosePushL(uriString); |
|
494 |
|
495 iContentHandler->OnStartPrefixMappingL(prefixString, uriString, KErrNone); |
|
496 |
|
497 CleanupStack::PopAndDestroy(2); |
|
498 } |
|
499 } |
|
500 |
|
501 void CExpat::EndNamespaceDeclHandlerL(void* aUserData, const XML_Char* aPrefix) |
|
502 { |
|
503 ((CExpat*)aUserData)->HandleEndNamespaceDeclL(aPrefix); |
|
504 } |
|
505 |
|
506 void CExpat::HandleEndNamespaceDeclL(const XML_Char* aPrefix) |
|
507 { |
|
508 if(iParseMode & EReportNamespaceMapping) |
|
509 { |
|
510 RString prefixString; |
|
511 |
|
512 if(aPrefix) |
|
513 CreateRStringL(TPtrC((TUint16*)aPrefix, StringLen((TUint16*)aPrefix)), prefixString, EFalse); |
|
514 else |
|
515 { |
|
516 unsigned char nullString[] = ""; |
|
517 prefixString = iStringPool.OpenStringL(TPtrC8(nullString, 0)); |
|
518 } |
|
519 |
|
520 CleanupClosePushL(prefixString); |
|
521 iContentHandler->OnEndPrefixMappingL(prefixString, KErrNone); |
|
522 CleanupStack::PopAndDestroy(); |
|
523 } |
|
524 } |
|
525 |
|
526 void CExpat::SkippedEntityHandlerL(void* aUserData, const XML_Char* aName, int aIsParamEntity) |
|
527 { |
|
528 ((CExpat*)aUserData)->HandleSkippedEntityL(aName, aIsParamEntity); |
|
529 } |
|
530 |
|
531 void CExpat::HandleSkippedEntityL(const XML_Char* aName, int) |
|
532 { |
|
533 RString nameString; |
|
534 CreateRStringL(TPtrC((TUint16*)aName, StringLen((TUint16*)aName)), nameString, EFalse); |
|
535 |
|
536 CleanupClosePushL(nameString); |
|
537 iContentHandler->OnSkippedEntityL(nameString, KErrNone); |
|
538 CleanupStack::PopAndDestroy(); |
|
539 } |
|
540 |
|
541 int CExpat::ExternalEntityRefHandlerL(void* aUserData, const XML_Char* aName) |
|
542 { |
|
543 ((CExpat*)aUserData)->HandleSkippedEntityL(aName, 0); |
|
544 return 1; |
|
545 } |
|
546 |
|
547 void CExpat::ClearElementStack() |
|
548 { |
|
549 for(TInt i=iElementStack.Count()-1; i>=0; i--) |
|
550 iElementStack[i].Close(); |
|
551 |
|
552 iElementStack.Reset(); |
|
553 } |
|
554 |
|
555 LOCAL_C void AttributeArrayDelete(TAny *aPtr) |
|
556 { |
|
557 RAttributeArray& attributes = *(RAttributeArray*)aPtr; |
|
558 |
|
559 TInt nAttributes = attributes.Count(); |
|
560 |
|
561 for(TInt i=0; i<nAttributes; i++) |
|
562 attributes[i].Close(); |
|
563 |
|
564 attributes.Close(); |
|
565 } |
|
566 |
|
567 RHeap* CExpat::GetInternalHeap() const |
|
568 { |
|
569 return iAllocator.GetHeap(); |
|
570 } |
|
571 |
|
572 |
|
573 // |
|
574 // CExpat::TExpatAlloc |
|
575 // |
|
576 #ifndef _DEBUG |
|
577 void CExpat::TExpatAlloc::ConstructL(TInt aHeapSize, TInt) |
|
578 { |
|
579 #else |
|
580 void CExpat::TExpatAlloc::ConstructL(TInt aHeapSize, TInt aDebugFailCount) |
|
581 { |
|
582 // The first failure is a simulated chunk/heap creation failure |
|
583 if(aDebugFailCount==1) |
|
584 User::Leave(KErrNoMemory); |
|
585 #endif |
|
586 |
|
587 iHeapSize = aHeapSize; |
|
588 iHeap = (RHeap*)User::LeaveIfNull(UserHeap::ChunkHeap(0, aHeapSize, aHeapSize)); |
|
589 |
|
590 #ifdef _DEBUG |
|
591 if(aDebugFailCount) |
|
592 iHeap->__DbgSetAllocFail(RHeap::EFailNext, aDebugFailCount-1); |
|
593 #endif |
|
594 } |
|
595 |
|
596 CExpat::TExpatAlloc::~TExpatAlloc() |
|
597 { |
|
598 if(iHeap) |
|
599 { |
|
600 iHeap->Close(); |
|
601 iHeap = 0; |
|
602 } |
|
603 } |
|
604 |
|
605 void CExpat::TExpatAlloc::ResetL() |
|
606 { |
|
607 __ASSERT_DEBUG(iHeap, User::Invariant()); |
|
608 |
|
609 if(iHeap) |
|
610 iHeap->Close(); |
|
611 iHeap = UserHeap::ChunkHeap(0, iHeapSize, iHeapSize); |
|
612 User::LeaveIfNull(iHeap); |
|
613 } |
|
614 |
|
615 void CExpat::TExpatAlloc::FillAllocStruct(XML_Memory_Handling_Suite& aMem) const |
|
616 { |
|
617 aMem.malloc_fcn = CExpat::TExpatAlloc::Alloc; |
|
618 aMem.realloc_fcn = CExpat::TExpatAlloc::ReAlloc; |
|
619 aMem.free_fcn = CExpat::TExpatAlloc::Free; |
|
620 aMem.allocData = (void*)this; |
|
621 } |
|
622 |
|
623 void* CExpat::TExpatAlloc::Alloc(void* aUserData, size_t aSize) |
|
624 { |
|
625 RHeap* heap = ((TExpatAlloc*)aUserData)->iHeap; |
|
626 return heap ? heap->Alloc(aSize) : 0; |
|
627 } |
|
628 |
|
629 void* CExpat::TExpatAlloc::ReAlloc(void* aUserData, void* aPtr, size_t aSize) |
|
630 { |
|
631 RHeap* heap = ((TExpatAlloc*)aUserData)->iHeap; |
|
632 |
|
633 // Used during development to ensure good heap. Left in for future reference |
|
634 __ASSERT_DEBUG(heap, User::Invariant()); |
|
635 |
|
636 return heap ? heap->ReAlloc(aPtr, aSize) : 0; |
|
637 } |
|
638 |
|
639 void CExpat::TExpatAlloc::Free(void* aUserData, void *aPtr) |
|
640 { |
|
641 RHeap* heap = ((TExpatAlloc*)aUserData)->iHeap; |
|
642 |
|
643 // Used during development to ensure good heap. Left in for future reference |
|
644 __ASSERT_DEBUG(heap, User::Invariant()); |
|
645 |
|
646 if(heap) |
|
647 heap->Free(aPtr); |
|
648 } |
|
649 |
|
650 RHeap* CExpat::TExpatAlloc::GetHeap() const |
|
651 { |
|
652 return iHeap; |
|
653 } |