|
1 // Copyright (c) 2004-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 // GMXMLCOMPOSE.CPP |
|
15 // @file |
|
16 // This file contains the declaration of the generic CMDXMLComposer class |
|
17 // which is responsible for creating an XML file |
|
18 // from a given DOM structure. |
|
19 // |
|
20 // |
|
21 |
|
22 #include <f32file.h> |
|
23 #include <utf.h> |
|
24 |
|
25 #include <gmxmlconstants.h> |
|
26 #include <gmxmlnode.h> |
|
27 #include <gmxmldocument.h> |
|
28 #include <gmxmlelement.h> |
|
29 #include <gmxmlcomposer.h> |
|
30 #include <gmxmlentityconverter.h> |
|
31 #include <gmxmltext.h> |
|
32 #include <gmxmlprocessinginstruction.h> |
|
33 #include <gmxmlcomment.h> |
|
34 #include <gmxmlcdatasection.h> |
|
35 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS |
|
36 #include "gmxmldummydtd.h" |
|
37 #endif |
|
38 |
|
39 _LIT(KXmlQuotation, """); |
|
40 |
|
41 // |
|
42 // CMDXMLComposer // |
|
43 // |
|
44 |
|
45 CMDXMLComposer::CMDXMLComposer(MMDXMLComposerObserver* aComposerObserver) : CActive(EPriorityNormal) |
|
46 // |
|
47 // Constructor |
|
48 // |
|
49 { |
|
50 iComposerObserver = aComposerObserver; |
|
51 iOutputProlog = ETrue; |
|
52 CActiveScheduler::Add(this); |
|
53 } |
|
54 |
|
55 CMDXMLComposer::CMDXMLComposer(MMDXMLComposerObserver* aComposerObserver, TBool aOutputProlog) : CActive(EPriorityNormal), |
|
56 iOutputProlog(aOutputProlog) |
|
57 // |
|
58 // Constructor |
|
59 // |
|
60 { |
|
61 iComposerObserver = aComposerObserver; |
|
62 CActiveScheduler::Add(this); |
|
63 } |
|
64 //================================================================================== |
|
65 |
|
66 EXPORT_C CMDXMLComposer::~CMDXMLComposer() |
|
67 { |
|
68 Cancel(); |
|
69 delete iEntityConverter; |
|
70 delete iCharconv; |
|
71 |
|
72 iXMLFile.Close(); |
|
73 } |
|
74 |
|
75 //================================================================================== |
|
76 |
|
77 void CMDXMLComposer::BaseConstructL() |
|
78 { |
|
79 iCharconv = CCnvCharacterSetConverter::NewL(); |
|
80 iCharconv->SetDowngradeForExoticLineTerminatingCharacters( |
|
81 CCnvCharacterSetConverter::EDowngradeExoticLineTerminatingCharactersToJustLineFeed); |
|
82 } |
|
83 |
|
84 //================================================================================== |
|
85 |
|
86 EXPORT_C CMDXMLComposer* CMDXMLComposer::NewL(MMDXMLComposerObserver* aComposerObserver) |
|
87 // |
|
88 // Two phase static factory function constructor |
|
89 // @param aEntityStrings the string table which lists the entity references and conversion |
|
90 // @return Created CMDXMLComposer |
|
91 // @leave can Leave due to OOM |
|
92 // |
|
93 { |
|
94 CMDXMLComposer* self = NewLC(aComposerObserver); |
|
95 CleanupStack::Pop(self); |
|
96 return self; |
|
97 } |
|
98 |
|
99 //================================================================================== |
|
100 |
|
101 EXPORT_C CMDXMLComposer* CMDXMLComposer::NewL(MMDXMLComposerObserver* aComposerObserver, TBool aOutputProlog) |
|
102 // |
|
103 // Two phase static factory function constructor |
|
104 // @param aEntityStrings the string table which lists the entity references and conversion |
|
105 // @param aOutputProlog Whether the Doctype and Version tags should be output. This is |
|
106 // provided for MMS conformance. |
|
107 // @return Created CMDXMLComposer |
|
108 // @leave can Leave due to OOM |
|
109 // |
|
110 { |
|
111 CMDXMLComposer* self = NewLC(aComposerObserver, aOutputProlog); |
|
112 CleanupStack::Pop(self); |
|
113 return self; |
|
114 } |
|
115 |
|
116 //================================================================================== |
|
117 |
|
118 EXPORT_C CMDXMLComposer* CMDXMLComposer::NewLC(MMDXMLComposerObserver* aComposerObserver) |
|
119 // |
|
120 // Two phase static factory function constructor |
|
121 // @param aEntityStrings the string table which lists the entity references and conversion |
|
122 // @return Created CMDXMLComposer |
|
123 // @leave can Leave due to OOM |
|
124 // |
|
125 { |
|
126 CMDXMLComposer* self = new (ELeave) CMDXMLComposer(aComposerObserver); |
|
127 CleanupStack::PushL(self); |
|
128 self->ConstructL(); |
|
129 return self; |
|
130 } |
|
131 |
|
132 //================================================================================== |
|
133 |
|
134 EXPORT_C CMDXMLComposer* CMDXMLComposer::NewLC(MMDXMLComposerObserver* aComposerObserver, TBool aOutputProlog) |
|
135 // |
|
136 // Two phase static factory function constructor |
|
137 // @param aEntityStrings the string table which lists the entity references and conversion |
|
138 // @param aOutputProlog Whether the Doctype and Version tags should be output. This is |
|
139 // provided for MMS conformance. |
|
140 // @return Created CMDXMLComposer |
|
141 // @leave can Leave due to OOM |
|
142 // |
|
143 { |
|
144 CMDXMLComposer* self = new (ELeave) CMDXMLComposer(aComposerObserver, aOutputProlog); |
|
145 CleanupStack::PushL(self); |
|
146 self->ConstructL(); |
|
147 return self; |
|
148 } |
|
149 |
|
150 //================================================================================== |
|
151 |
|
152 void CMDXMLComposer::ConstructL() |
|
153 // |
|
154 // Second stage constructor |
|
155 // @param aEntityStrings the string table which lists the entity references and conversion |
|
156 // |
|
157 { |
|
158 BaseConstructL(); |
|
159 CMDXMLEntityConverter* entityConverter = new(ELeave) CMDXMLEntityConverter(); |
|
160 SetEntityConverter(entityConverter); |
|
161 } |
|
162 |
|
163 |
|
164 //================================================================================== |
|
165 |
|
166 void CMDXMLComposer::InitialiseCompose(CMDXMLDocument* aDocument, TXMLFileType aFileType) |
|
167 { |
|
168 Cancel(); |
|
169 |
|
170 iError = KErrNone; |
|
171 iSeverity = EXMLNone; |
|
172 iOutputBuffer.Zero(); |
|
173 |
|
174 iXMLDoc = aDocument; |
|
175 iFileType = aFileType; |
|
176 |
|
177 iOnlyCalculatingSize = EFalse; |
|
178 iSizeTally = 0; |
|
179 } |
|
180 |
|
181 EXPORT_C TInt CMDXMLComposer::ComposeFile(RFs aRFs, const TDesC& aFileToCompose, CMDXMLDocument* aDocument, TXMLFileType aFileType) |
|
182 /** Starts file composition. |
|
183 |
|
184 This function can not be called if there is an outstanding size calculation or compose |
|
185 operation in progress. If it is necessary to run two asynchronous operations in parallel |
|
186 then two instances of the CMDXMLComposer are needed. |
|
187 |
|
188 @param aRFS File system to use |
|
189 @param aFileToCompose Name of file to create |
|
190 @param aDocument The document object to compose to the file |
|
191 @return KERRNone if successful |
|
192 **/ |
|
193 { |
|
194 InitialiseCompose(aDocument, aFileType); |
|
195 iRFs = aRFs; |
|
196 TInt error = KErrNone; |
|
197 |
|
198 if(iXMLDoc == NULL) |
|
199 { |
|
200 error = KErrNotSupported; |
|
201 } |
|
202 else |
|
203 { |
|
204 switch(iFileType) |
|
205 { |
|
206 case EAscii: |
|
207 { |
|
208 error = iXMLFile.Replace(aRFs, aFileToCompose, EFileWrite | EFileStream); |
|
209 break; |
|
210 } |
|
211 case EUnicode: |
|
212 error = iXMLFile.Replace(aRFs, aFileToCompose, EFileWrite | EFileStream); |
|
213 if(error == KErrNone) |
|
214 { |
|
215 // append Unicode File identifier to start of output text |
|
216 iOutputBuffer.Append(CEditableText::EByteOrderMark); |
|
217 } |
|
218 break; |
|
219 case EUtf8: |
|
220 { |
|
221 error = iXMLFile.Replace(aRFs, aFileToCompose, EFileWrite | EFileStream); |
|
222 break; |
|
223 } |
|
224 default: |
|
225 error = KErrNotSupported; |
|
226 break; |
|
227 } |
|
228 } |
|
229 |
|
230 if(error == KErrNone) |
|
231 { |
|
232 SetActive(); |
|
233 TRequestStatus* s=&iStatus; |
|
234 User::RequestComplete(s, KErrNone); |
|
235 } |
|
236 else |
|
237 { |
|
238 SetError(error, EXMLFatal); |
|
239 } |
|
240 |
|
241 return error; |
|
242 } |
|
243 |
|
244 /** Starts file composition to an open file handle. |
|
245 |
|
246 This function must not be called when file sizing is in progress. If it is necessary to calulate |
|
247 the size and generate the XML simultaneously then two instances of the composer should be used, |
|
248 one for sizing and one for composition. |
|
249 |
|
250 @param aFileHandleToCompose An open file handle to write to. Ownership of the file handle is passed even if an error occurs. |
|
251 @param aDocument The document object to compose to the file. |
|
252 @param aFileType Type of the output file. |
|
253 @return KErrNone if successful. |
|
254 */ |
|
255 EXPORT_C TInt CMDXMLComposer::ComposeFile(RFile& aFileHandleToCompose, CMDXMLDocument* aDocument, TXMLFileType aFileType) |
|
256 { |
|
257 InitialiseCompose(aDocument, aFileType); |
|
258 iXMLFile = aFileHandleToCompose; |
|
259 TInt error = KErrNone; |
|
260 |
|
261 if(iXMLDoc == NULL) |
|
262 { |
|
263 error = KErrNotSupported; |
|
264 } |
|
265 else |
|
266 { |
|
267 switch(iFileType) |
|
268 { |
|
269 case EUnicode: |
|
270 { |
|
271 // append Unicode File identifier to start of output text |
|
272 iOutputBuffer.Append(CEditableText::EByteOrderMark); |
|
273 } |
|
274 case EAscii: |
|
275 case EUtf8: |
|
276 break; |
|
277 |
|
278 default: |
|
279 error = KErrNotSupported; |
|
280 break; |
|
281 } |
|
282 } |
|
283 |
|
284 if(error == KErrNone) |
|
285 { |
|
286 iStatus = KRequestPending; |
|
287 SetActive(); |
|
288 TRequestStatus* s=&iStatus; |
|
289 User::RequestComplete(s, KErrNone); |
|
290 } |
|
291 else |
|
292 { |
|
293 iXMLFile.Close(); |
|
294 SetError(error, EXMLFatal); |
|
295 } |
|
296 |
|
297 return error; |
|
298 } |
|
299 |
|
300 //================================================================================== |
|
301 |
|
302 /** Starts calculating the size of the XML output without actually writing it to the file. |
|
303 |
|
304 This process is asyncronous, the size value is only updated when ComposeFileComplete |
|
305 is called on the MMDXMLComposerObserver passed in in the NewL. |
|
306 |
|
307 This function can not be called if there is an outstanding size calculation or compose |
|
308 operation in progress. If it is necessary to run two asynchronous operations in parallel |
|
309 then two instances of CMDXMLComposer are needed. |
|
310 |
|
311 @param aSize Will be set to the size of the XML document when composition has completed. |
|
312 @param aDocument The document object to size |
|
313 @param aFileType Type of the output file, required because it will affect the size of the XML |
|
314 @return KErrNone if successful */ |
|
315 |
|
316 EXPORT_C TInt CMDXMLComposer::CalculateFileSize(TInt& aSize, CMDXMLDocument* aDocument, TXMLFileType aFileType) |
|
317 { |
|
318 Cancel(); |
|
319 |
|
320 iError = KErrNone; |
|
321 iSeverity = EXMLNone; |
|
322 iOutputBuffer.Zero(); |
|
323 |
|
324 iXMLDoc = aDocument; |
|
325 iFileType = aFileType; |
|
326 TInt error = KErrNone; |
|
327 |
|
328 if (iFileType == EUnicode) |
|
329 { |
|
330 // The size tally must be incremented by two characters because the unicode byte marker |
|
331 // gets added in the ComposeFile function that does not get called when we are calculating |
|
332 // the size. |
|
333 iSizeTally = 2; |
|
334 } |
|
335 else |
|
336 { |
|
337 iSizeTally = 0; |
|
338 } |
|
339 |
|
340 iSize = &aSize; |
|
341 iOnlyCalculatingSize = ETrue; |
|
342 |
|
343 if(iXMLDoc == NULL) |
|
344 { |
|
345 error = KErrNotSupported; |
|
346 } |
|
347 |
|
348 if(error == KErrNone) |
|
349 { |
|
350 SetActive(); |
|
351 TRequestStatus* s=&iStatus; |
|
352 User::RequestComplete(s, KErrNone); |
|
353 } |
|
354 else |
|
355 { |
|
356 SetError(error, EXMLFatal); |
|
357 } |
|
358 |
|
359 return error; |
|
360 } |
|
361 |
|
362 //================================================================================== |
|
363 |
|
364 EXPORT_C TInt CMDXMLComposer::Error() const |
|
365 { |
|
366 return iError; |
|
367 } |
|
368 |
|
369 //================================================================================== |
|
370 |
|
371 EXPORT_C TXMLErrorCodeSeverity CMDXMLComposer::ErrorSeverity() const |
|
372 { |
|
373 return iSeverity; |
|
374 } |
|
375 |
|
376 //================================================================================== |
|
377 |
|
378 EXPORT_C CMDXMLEntityConverter* CMDXMLComposer::EntityConverter() const |
|
379 { |
|
380 return iEntityConverter; |
|
381 } |
|
382 |
|
383 //================================================================================== |
|
384 |
|
385 TInt CMDXMLComposer::OutputCommentL(const TDesC& aComment) |
|
386 // |
|
387 // Output a comment |
|
388 // @param aComment the comment text to output |
|
389 // @return KERRNone if successful, otherwise a file writing error. |
|
390 // |
|
391 { |
|
392 TInt error = KErrNone; |
|
393 |
|
394 if(iSeverity != EXMLFatal) |
|
395 { |
|
396 error = WriteFileL(KNewLine); |
|
397 } |
|
398 |
|
399 #ifdef _DEBUG |
|
400 for(TInt loopIndex = 0; loopIndex < iIndentationLevel; loopIndex++) |
|
401 { |
|
402 if(iSeverity != EXMLFatal) |
|
403 { |
|
404 error = WriteFileL(KTab); |
|
405 } |
|
406 } |
|
407 #endif |
|
408 |
|
409 if(iSeverity != EXMLFatal) |
|
410 { |
|
411 error = WriteFileL(KXMLStartComment); |
|
412 } |
|
413 |
|
414 if(iSeverity != EXMLFatal) |
|
415 { |
|
416 error = WriteFileL(aComment); |
|
417 } |
|
418 |
|
419 if(iSeverity != EXMLFatal) |
|
420 { |
|
421 error = WriteFileL(KXMLEndComment); |
|
422 } |
|
423 |
|
424 return error; |
|
425 } |
|
426 |
|
427 //================================================================================== |
|
428 |
|
429 TInt CMDXMLComposer::OutputProcessingInstructionL(const TDesC& aInstruction) |
|
430 // |
|
431 // Output a Processing Instruction |
|
432 // @param aInstruction the Processing Instruction text to output |
|
433 // @return KERRNone if successful, otherwise a file writing error. |
|
434 // |
|
435 { |
|
436 TInt error = KErrNone; |
|
437 |
|
438 if(iSeverity != EXMLFatal) |
|
439 { |
|
440 error = WriteFileL(KNewLine); |
|
441 } |
|
442 |
|
443 #ifdef _DEBUG |
|
444 for(TInt loopIndex = 0; loopIndex < iIndentationLevel; loopIndex++) |
|
445 { |
|
446 if(iSeverity != EXMLFatal) |
|
447 { |
|
448 error = WriteFileL(KTab); |
|
449 } |
|
450 } |
|
451 #endif |
|
452 |
|
453 if(iSeverity != EXMLFatal) |
|
454 { |
|
455 error = WriteFileL(KXMLStartProcessingInstruction); |
|
456 } |
|
457 |
|
458 if(iSeverity != EXMLFatal) |
|
459 { |
|
460 error = WriteFileL(aInstruction); |
|
461 } |
|
462 |
|
463 if(iSeverity != EXMLFatal) |
|
464 { |
|
465 error = WriteFileL(KXMLEndProcessingInstruction); |
|
466 } |
|
467 |
|
468 return error; |
|
469 } |
|
470 |
|
471 |
|
472 //================================================================================== |
|
473 |
|
474 TInt CMDXMLComposer::OutputCDataSectionL(const TDesC& aCDataSection) |
|
475 // |
|
476 // Output a CDataSection |
|
477 // @param aCDataSection the data section text to output |
|
478 // @return KERRNone if successful, otherwise a file writing error. |
|
479 // |
|
480 { |
|
481 TInt error = KErrNone; |
|
482 |
|
483 #ifdef _DEBUG |
|
484 for(TInt loopIndex = 0; loopIndex < iIndentationLevel; loopIndex++) |
|
485 { |
|
486 if(iSeverity != EXMLFatal) |
|
487 { |
|
488 error = WriteFileL(KTab); |
|
489 } |
|
490 } |
|
491 #endif |
|
492 |
|
493 if(iSeverity != EXMLFatal) |
|
494 { |
|
495 error = WriteFileL(KXMLStartCDataSection); |
|
496 } |
|
497 |
|
498 if(iSeverity != EXMLFatal) |
|
499 { |
|
500 error = WriteFileL(aCDataSection); |
|
501 } |
|
502 |
|
503 if(iSeverity != EXMLFatal) |
|
504 { |
|
505 error = WriteFileL(KXMLEndCDataSection); |
|
506 } |
|
507 |
|
508 return error; |
|
509 } |
|
510 |
|
511 //================================================================================== |
|
512 //Defect fix for INC036136- Enable the use of custom entity converters in GMXML |
|
513 |
|
514 EXPORT_C TInt CMDXMLComposer::OutputDataL(const TDesC& aData) |
|
515 // |
|
516 // Output raw data |
|
517 // it's only intended to be used from within a custom entity converter as |
|
518 // it relies on a Composer sesssion already being in progress |
|
519 // @param the data to be output |
|
520 // @return KERRNone if successful, otherwise a file writing error. |
|
521 // |
|
522 { |
|
523 TInt error = KErrNone; |
|
524 |
|
525 if(iSeverity != EXMLFatal) |
|
526 { |
|
527 if(aData.Find(KQuotation) != KErrNotFound) |
|
528 { |
|
529 error = ReplaceXmlCharactersL(aData, KQuotation); |
|
530 } |
|
531 else |
|
532 { |
|
533 error = WriteFileL(aData); |
|
534 } |
|
535 } |
|
536 |
|
537 return error; |
|
538 } |
|
539 |
|
540 //================================================================================== |
|
541 /* Before writing to xml file, search for special character like quotation ("). |
|
542 if it exist then replace it with " and then write it to xml file. |
|
543 Refer section 5 of below URL for more information. |
|
544 http://www.xmlnews.org/docs/xml-basics.html |
|
545 @param aXmlData the data to be output |
|
546 @param aString the special character to search in aXmlData |
|
547 @return KERRNone if successful, otherwise a file writing error. */ |
|
548 |
|
549 TInt CMDXMLComposer::ReplaceXmlCharactersL(const TDesC16& aXmlData, const TDesC& aString) |
|
550 { |
|
551 TInt xmlDataIndex; |
|
552 const TDesC& quot = KXmlQuotation; |
|
553 HBufC16* xmlData = aXmlData.AllocL(); |
|
554 |
|
555 while((xmlDataIndex = (xmlData->Des()).Find(aString)) != KErrNotFound) |
|
556 { |
|
557 HBufC16* temp = HBufC::NewLC(((xmlData->Des()).Length() - 1) + quot.Length()); |
|
558 TPtr16 tempPtr = temp->Des(); |
|
559 tempPtr.Append((xmlData->Des()).Left(xmlDataIndex)); |
|
560 tempPtr.Append(quot); |
|
561 tempPtr.Append((xmlData->Des()).Right((xmlData->Des()).Length() - (xmlDataIndex + 1))); |
|
562 delete xmlData; |
|
563 xmlData = NULL; |
|
564 xmlData = tempPtr.AllocL(); |
|
565 CleanupStack::PopAndDestroy(); // temp |
|
566 } |
|
567 TInt error = WriteFileL((xmlData->Des())); |
|
568 delete xmlData; |
|
569 xmlData = NULL; |
|
570 return error; |
|
571 } |
|
572 |
|
573 //================================================================================== |
|
574 |
|
575 EXPORT_C void CMDXMLComposer::SetEntityConverter(CMDXMLEntityConverter* aEntityConverter) |
|
576 /* |
|
577 * Sets the entity converter to be used |
|
578 * and take ownership of the passed entity converter |
|
579 * @param aEntityConverter The entity converter to be used |
|
580 */ |
|
581 { |
|
582 delete iEntityConverter; |
|
583 iEntityConverter = aEntityConverter; |
|
584 } |
|
585 |
|
586 //End Defect fix for INC036136 |
|
587 //================================================================================== |
|
588 |
|
589 EXPORT_C TInt CMDXMLComposer::OutputStartOfElementTagL(const TDesC& aElementName) |
|
590 // |
|
591 // Output a start of element tag |
|
592 // @param aElementName the name of the tag to output |
|
593 // @return KERRNone if successful, otherwise a file writing error. |
|
594 // |
|
595 { |
|
596 TInt error = KErrNone; |
|
597 |
|
598 #ifdef _DEBUG |
|
599 for(TInt loopIndex = 0; loopIndex < iIndentationLevel; loopIndex++) |
|
600 { |
|
601 if(iSeverity != EXMLFatal) |
|
602 { |
|
603 error = WriteFileL(KTab); |
|
604 } |
|
605 } |
|
606 iIndentationLevel++; |
|
607 #endif |
|
608 |
|
609 if(iSeverity != EXMLFatal) |
|
610 { |
|
611 error = WriteFileL(KXMLStartTag); |
|
612 } |
|
613 |
|
614 if(iSeverity != EXMLFatal) |
|
615 { |
|
616 error = WriteFileL(aElementName); |
|
617 } |
|
618 |
|
619 return error; |
|
620 } |
|
621 |
|
622 //================================================================================== |
|
623 |
|
624 EXPORT_C TInt CMDXMLComposer::OutputEndOfElementTagL(const TBool aHasChildren) |
|
625 // |
|
626 // Output an end of element start tag |
|
627 // @param aHasChildren true if the element has children |
|
628 // @return KERRNone if successful, otherwise a file writing error. |
|
629 // |
|
630 { |
|
631 TInt error = KErrNone; |
|
632 |
|
633 if(iSeverity != EXMLFatal) |
|
634 { |
|
635 if(aHasChildren) |
|
636 { |
|
637 error = WriteFileL(KXMLEndTag); |
|
638 } |
|
639 else |
|
640 { |
|
641 error = WriteFileL(KXMLEndStartTag); |
|
642 |
|
643 #ifdef _DEBUG |
|
644 iIndentationLevel--; |
|
645 #endif |
|
646 } |
|
647 } |
|
648 |
|
649 return error; |
|
650 } |
|
651 |
|
652 //================================================================================== |
|
653 |
|
654 TInt CMDXMLComposer::OutputEndTagL(const TDesC& aElementName) |
|
655 // |
|
656 // Output an end of element tag |
|
657 // @param aElementName the name of the tag to output |
|
658 // @return KERRNone if successful, otherwise a file writing error. |
|
659 // |
|
660 { |
|
661 TInt error = KErrNone; |
|
662 |
|
663 #ifdef _DEBUG |
|
664 iIndentationLevel--; |
|
665 for(TInt loopIndex = 0; loopIndex < iIndentationLevel; loopIndex++) |
|
666 { |
|
667 if(iSeverity != EXMLFatal) |
|
668 { |
|
669 error = WriteFileL(KTab); |
|
670 } |
|
671 } |
|
672 #endif |
|
673 |
|
674 if(iSeverity != EXMLFatal) |
|
675 { |
|
676 error = WriteFileL(KXMLStartEndTag); |
|
677 } |
|
678 |
|
679 if(iSeverity != EXMLFatal) |
|
680 { |
|
681 error = WriteFileL(aElementName); |
|
682 } |
|
683 |
|
684 if(iSeverity != EXMLFatal) |
|
685 { |
|
686 error = WriteFileL(KXMLEndTag); |
|
687 } |
|
688 |
|
689 return error; |
|
690 } |
|
691 |
|
692 |
|
693 |
|
694 |
|
695 |
|
696 //================================================================================== |
|
697 |
|
698 EXPORT_C TInt CMDXMLComposer::OutputAttributeL(const TDesC& aAttributeName, const TDesC& aAttributeValue) |
|
699 // |
|
700 // Output an attribute - name and value. |
|
701 // @param aAttributeName the name of the attribute to output |
|
702 // @param aAttributeValue the text of the attribute value to output |
|
703 // @return KERRNone if successful, otherwise a file writing error. |
|
704 // |
|
705 { |
|
706 TInt error = KErrNone; |
|
707 |
|
708 if(iSeverity != EXMLFatal) |
|
709 { |
|
710 error = WriteFileL(KSingleSpace); |
|
711 } |
|
712 |
|
713 if(iSeverity != EXMLFatal) |
|
714 { |
|
715 error = WriteFileL(aAttributeName); |
|
716 } |
|
717 |
|
718 if(iSeverity != EXMLFatal) |
|
719 { |
|
720 error = WriteFileL(KEqualSign); |
|
721 } |
|
722 |
|
723 if(iSeverity != EXMLFatal) |
|
724 { |
|
725 error = WriteFileL(KQuotation); |
|
726 } |
|
727 |
|
728 if(iSeverity != EXMLFatal) |
|
729 { |
|
730 // Work along the attribute value in sections. We have two markers in the attribute, |
|
731 // one at the beginning of the section we're working on and one at the end. Initially |
|
732 // beginSection is the start of the string, 0, the end of the section is the first |
|
733 // CDataSection we find. |
|
734 // beginSection is an offset within the string, endSection is an offset from that |
|
735 TInt beginSection = 0; |
|
736 TInt endSection = aAttributeValue.Find(KXMLStartCDataSection); |
|
737 |
|
738 // We've found at least one CDataSection |
|
739 while(endSection != KErrNotFound) |
|
740 { |
|
741 // Entity convert this plain text section |
|
742 TPtrC plainText = aAttributeValue.Mid(beginSection, endSection); |
|
743 error = iEntityConverter->OutputComposedTextL(this, plainText); |
|
744 |
|
745 // Move on our markers. We start the new section at the end of the old one. |
|
746 beginSection += endSection; |
|
747 // The end of this section is the end of the CDataSection |
|
748 endSection = TPtrC(aAttributeValue.Mid(beginSection)).Find(KXMLEndCDataSection); |
|
749 if(endSection != KErrNotFound) |
|
750 { |
|
751 // The CDataSection ends at the beginning of the end tag, so we need to add |
|
752 // on the length of the end tag before outputting it without conversion |
|
753 endSection += TPtrC(KXMLEndCDataSection).Length(); |
|
754 OutputDataL(aAttributeValue.Mid(beginSection, endSection)); |
|
755 |
|
756 // Now move on our markers again. Start at the end of the CDataSection, and |
|
757 // continue to the beginning of the next one. |
|
758 beginSection += endSection; |
|
759 endSection = TPtrC(aAttributeValue.Mid(beginSection)).Find(KXMLStartCDataSection); |
|
760 } |
|
761 else |
|
762 { |
|
763 // There's an unterminated CDataSection in our attribute |
|
764 error = KErrXMLBadAttributeValue; |
|
765 } |
|
766 } |
|
767 |
|
768 // There are no more CDataSections, entity convert the rest of the string |
|
769 if(!error) |
|
770 { |
|
771 error = iEntityConverter->OutputComposedTextL(this, aAttributeValue.Mid(beginSection)); |
|
772 } |
|
773 } |
|
774 |
|
775 if(iSeverity != EXMLFatal) |
|
776 { |
|
777 error = WriteFileL(KQuotation); |
|
778 } |
|
779 |
|
780 return error; |
|
781 } |
|
782 |
|
783 //================================================================================== |
|
784 |
|
785 EXPORT_C TInt CMDXMLComposer::RunError(TInt aError) |
|
786 // |
|
787 // RunError function inherited from CActive base class - intercepts any Leave from |
|
788 // the RunL() function, sets an appropriate errorcode and calls ComposeFileCompleteL |
|
789 // |
|
790 { |
|
791 iSeverity = EXMLFatal; |
|
792 iError = aError; |
|
793 iXMLFile.Close(); |
|
794 TRAPD(err, iComposerObserver->ComposeFileCompleteL()); |
|
795 return err; |
|
796 } |
|
797 |
|
798 //================================================================================== |
|
799 |
|
800 EXPORT_C void CMDXMLComposer::DoCancel() |
|
801 // |
|
802 // DoCancel function inherited from CActive base class |
|
803 // |
|
804 { |
|
805 iXMLFile.Close(); |
|
806 } |
|
807 |
|
808 //================================================================================== |
|
809 |
|
810 void CMDXMLComposer::RunL() |
|
811 // |
|
812 // RunL function inherited from CActive base class - does the actual composition |
|
813 // @leave can Leave due to OOM |
|
814 // |
|
815 { |
|
816 // If this is an ASCII file then check that we can load the character set converter |
|
817 if(iSeverity != EXMLFatal) |
|
818 { |
|
819 if(iFileType == EAscii) |
|
820 { |
|
821 if (iCharconv->PrepareToConvertToOrFromL(KCharacterSetIdentifierAscii, iRFs)!= |
|
822 CCnvCharacterSetConverter::EAvailable) |
|
823 { |
|
824 SetError( KErrNotSupported, EXMLFatal); |
|
825 } |
|
826 } |
|
827 } |
|
828 |
|
829 if(iSeverity != EXMLFatal) |
|
830 { |
|
831 #ifdef _DEBUG |
|
832 iIndentationLevel = 0; |
|
833 #endif |
|
834 |
|
835 CMDXMLElement* parentElement = iXMLDoc->DocumentElement(); |
|
836 |
|
837 TInt error = KErrNone; |
|
838 |
|
839 if(!parentElement->CheckChildren()) |
|
840 { |
|
841 error = KErrNotSupported; |
|
842 SetError(KErrXMLInvalidChild, EXMLWorkable); |
|
843 } |
|
844 |
|
845 if(iOutputProlog) |
|
846 { |
|
847 // Output document level information if required. MMS conformance requires no Version |
|
848 // or DocType tag, so we may not want to output them. |
|
849 if(iSeverity != EXMLFatal) |
|
850 { |
|
851 WriteFileL(iXMLDoc->VersionTag()); |
|
852 } |
|
853 if(iSeverity != EXMLFatal) |
|
854 { |
|
855 WriteFileL(KNewLine); |
|
856 } |
|
857 if(iSeverity != EXMLFatal) |
|
858 { |
|
859 WriteFileL(iXMLDoc->DocTypeTag()); |
|
860 } |
|
861 if(iSeverity != EXMLFatal) |
|
862 { |
|
863 WriteFileL(KNewLine); |
|
864 } |
|
865 } |
|
866 |
|
867 // Output the contents of the DOM tree |
|
868 if(iSeverity != EXMLFatal) |
|
869 { |
|
870 error = ComposeL(); |
|
871 if(iSeverity != EXMLFatal) |
|
872 { |
|
873 if(error != KErrNone) |
|
874 { |
|
875 SetError(error, EXMLIndeterminate); |
|
876 } |
|
877 |
|
878 WriteFileL(KNewLine); |
|
879 } |
|
880 } |
|
881 |
|
882 if(iSeverity != EXMLFatal) |
|
883 { |
|
884 error = FlushOutputBufferL(); |
|
885 |
|
886 if(error != KErrNone) |
|
887 { |
|
888 SetError(error, EXMLIndeterminate); |
|
889 } |
|
890 } |
|
891 } |
|
892 |
|
893 iXMLFile.Close(); |
|
894 |
|
895 if (iOnlyCalculatingSize) |
|
896 { |
|
897 *iSize = iSizeTally; |
|
898 } |
|
899 |
|
900 iComposerObserver->ComposeFileCompleteL(); |
|
901 } |
|
902 |
|
903 |
|
904 TInt CMDXMLComposer::ComposeL() |
|
905 // |
|
906 // Function to output the contents of the node as XML to some output stream. |
|
907 // @param aComposer The composer to use - provides access to output and entity conversion |
|
908 // @return Returns KerrNone if successful or a file write error |
|
909 // @leave Can Leave due to OOM. |
|
910 // |
|
911 { |
|
912 CMDXMLNode* nextPtr; |
|
913 TInt error = KErrNone; |
|
914 nextPtr = iXMLDoc->DocumentElement()->FirstChild(); |
|
915 |
|
916 |
|
917 while(error == KErrNone && nextPtr != NULL) |
|
918 { |
|
919 // compose the start tag of the current element |
|
920 error = ComposeStartTagL(*nextPtr); |
|
921 |
|
922 if(error == KErrNone) |
|
923 { |
|
924 // move to the first child is there is one |
|
925 if(nextPtr->FirstChild() != NULL) |
|
926 { |
|
927 nextPtr = nextPtr->FirstChild(); |
|
928 } |
|
929 else |
|
930 { |
|
931 // EndTag is only output if HasChildNodes() == TRUE |
|
932 error = ComposeEndTagL(*nextPtr); |
|
933 |
|
934 // move to the next sibling if exists |
|
935 if(nextPtr->NextSibling() != NULL) |
|
936 { |
|
937 nextPtr = nextPtr->NextSibling(); |
|
938 } |
|
939 |
|
940 // no siblings, move back to parent and close parent tag |
|
941 else |
|
942 { |
|
943 // might need to go up several layers so WHILE rather than IF |
|
944 while(nextPtr != NULL && nextPtr->NextSibling() == NULL && error == KErrNone) |
|
945 { |
|
946 nextPtr = nextPtr->ParentNode(); |
|
947 if(nextPtr != NULL) |
|
948 { |
|
949 error = ComposeEndTagL(*nextPtr); |
|
950 } |
|
951 } |
|
952 |
|
953 // if we've stopped at an element with further siblings |
|
954 if(nextPtr != NULL && nextPtr->NextSibling() != NULL) |
|
955 { |
|
956 nextPtr = nextPtr->NextSibling(); |
|
957 } |
|
958 } |
|
959 } |
|
960 } |
|
961 } |
|
962 |
|
963 return error; |
|
964 } |
|
965 |
|
966 |
|
967 EXPORT_C TInt CMDXMLComposer::ComposeStartTagL(CMDXMLNode& aNode) |
|
968 // |
|
969 // Outputs a start tag for the node which includes the |
|
970 // tag name and all attribute name value pairs currently |
|
971 // specified. If the node is an empty node then it |
|
972 // makes the tag an empty node tag, otherwise it creates |
|
973 // a start tag. |
|
974 // @param aNode The Node for which the start tag is being written |
|
975 // @return Returns KerrNone if successful or a file write error |
|
976 // |
|
977 { |
|
978 TInt error = KErrNone; |
|
979 |
|
980 switch (aNode.NodeType()) |
|
981 { |
|
982 case CMDXMLNode::ETextNode: |
|
983 error = iEntityConverter->OutputComposedTextL(this, ((CMDXMLText&)aNode).Data()); |
|
984 break; |
|
985 case CMDXMLNode::ECDATASectionNode: |
|
986 error = OutputCDataSectionL(((CMDXMLCDATASection&)aNode).Data()); |
|
987 // does nothing |
|
988 break; |
|
989 case CMDXMLNode::EProcessingInstructionNode: |
|
990 error = OutputProcessingInstructionL(((CMDXMLProcessingInstruction&)aNode).Data()); |
|
991 break; |
|
992 case CMDXMLNode::ECommentNode: |
|
993 error = OutputCommentL(((CMDXMLComment&)aNode).Data()); |
|
994 break; |
|
995 case CMDXMLNode::EDocumentNode: |
|
996 // does nothing |
|
997 break; |
|
998 case CMDXMLNode::EElementNode: |
|
999 error = OutputStartOfElementTagL(aNode.NodeName()); |
|
1000 TInt attIndex; |
|
1001 // Output all attributes in a loop |
|
1002 for(attIndex = 0 ; (error == KErrNone && attIndex < ((CMDXMLElement&)aNode).NumAttributes()); attIndex ++ ) |
|
1003 { |
|
1004 TPtrC attributeValue; |
|
1005 TPtrC attributeName; |
|
1006 error = ((CMDXMLElement&)aNode).AttributeDetails(attIndex, attributeName, attributeValue); |
|
1007 if(error == KErrNone) |
|
1008 error = OutputAttributeL(attributeName, attributeValue); |
|
1009 } |
|
1010 |
|
1011 |
|
1012 if( error == KErrNone ) |
|
1013 { |
|
1014 error = OutputEndOfElementTagL(aNode.HasChildNodes()); |
|
1015 } |
|
1016 break; |
|
1017 default: |
|
1018 // does nothing |
|
1019 break; |
|
1020 |
|
1021 |
|
1022 } |
|
1023 |
|
1024 return error; |
|
1025 } |
|
1026 |
|
1027 EXPORT_C TInt CMDXMLComposer::ComposeEndTagL(CMDXMLNode& aNode) |
|
1028 // |
|
1029 // Outputs an end tag for the node. |
|
1030 // @param aNode the node for which the tag is being written. |
|
1031 // @return Returns KerrNone if successful or a file write error |
|
1032 // |
|
1033 { |
|
1034 TInt error = KErrNone; |
|
1035 |
|
1036 if (aNode.NodeType() == CMDXMLNode::EElementNode && aNode.NodeName() != KXMLDocumentElementNodeName) |
|
1037 { |
|
1038 if(aNode.HasChildNodes()) |
|
1039 { |
|
1040 error = OutputEndTagL(aNode.NodeName()); |
|
1041 } |
|
1042 } |
|
1043 |
|
1044 |
|
1045 return error; |
|
1046 } |
|
1047 |
|
1048 //================================================================================== |
|
1049 |
|
1050 TInt CMDXMLComposer::WriteFileL(const TDesC& aStringToWrite) |
|
1051 // |
|
1052 // Function to write string to required file format - handles format conversion |
|
1053 // @param aStringToWrite the string to output |
|
1054 // @return returns KERRNone if successful or a file write error. |
|
1055 // |
|
1056 { |
|
1057 TInt error = KErrNone; |
|
1058 TInt outputBufferLength = iOutputBuffer.Length(); |
|
1059 TInt additionalLength = aStringToWrite.Length(); |
|
1060 |
|
1061 if(outputBufferLength + additionalLength <= KWriteBufferLen) |
|
1062 { |
|
1063 iOutputBuffer.Append(aStringToWrite); |
|
1064 } |
|
1065 else |
|
1066 { |
|
1067 iOutputBuffer.Append(aStringToWrite.Left(KWriteBufferLen - outputBufferLength)); |
|
1068 error = FlushOutputBufferL(); |
|
1069 iOutputBuffer.Zero(); |
|
1070 WriteFileL(aStringToWrite.Right(additionalLength - (KWriteBufferLen - outputBufferLength))); |
|
1071 } |
|
1072 |
|
1073 return error; |
|
1074 } |
|
1075 |
|
1076 //================================================================================== |
|
1077 #define DES_AS_8_BIT(str) (TPtrC8((TText8*)((str).Ptr()), (str).Size())) |
|
1078 |
|
1079 TInt CMDXMLComposer::FlushOutputBufferL() |
|
1080 // |
|
1081 // Function to write string to required file format - handles format conversion |
|
1082 // @param aStringToWrite the string to output |
|
1083 // @return returns KERRNone if successful or a file write or conversion error. |
|
1084 // |
|
1085 { |
|
1086 TInt error = KErrNone; |
|
1087 |
|
1088 if (!iOnlyCalculatingSize) |
|
1089 { |
|
1090 if(iXMLFile.SubSessionHandle() == KNullHandle) |
|
1091 { |
|
1092 return KErrBadHandle; |
|
1093 } |
|
1094 } |
|
1095 |
|
1096 // All text is processed internally as unicode. If we've been asked to output |
|
1097 // another format (Ascii or Utf-8) we need to translate it to that format using |
|
1098 // charconv before writing the file. |
|
1099 switch(iFileType) |
|
1100 { |
|
1101 case EAscii: |
|
1102 case EUtf8: |
|
1103 { |
|
1104 // We need to convert in a loop as charconv only allows 25 untranslatable |
|
1105 // characters per block of text. convResult tells us how many characters |
|
1106 // were left untranslated at the end of iOutputBuffer so we only look at |
|
1107 // that many characters on the right hand of iOutputBuffer. Initially we |
|
1108 // don't have any characters translated so convResult is the length of |
|
1109 // iOutputBuffer. Each time through the loop write out the chunk we've |
|
1110 // converted. If there's an error writing the file or doing the character |
|
1111 // conversion we give up. |
|
1112 TInt convResult = iOutputBuffer.Length(); |
|
1113 while((convResult > 0) && (error == KErrNone)) |
|
1114 { |
|
1115 HBufC8* narrow = HBufC8::NewLC(convResult); |
|
1116 TPtr8 narrowPtr = narrow->Des(); |
|
1117 if(iFileType == EAscii) |
|
1118 { |
|
1119 convResult = iCharconv->ConvertFromUnicode(narrowPtr, iOutputBuffer.Right(convResult)); |
|
1120 } |
|
1121 else // iFileType == EUtf8 |
|
1122 { |
|
1123 convResult = CnvUtfConverter::ConvertFromUnicodeToUtf8(narrowPtr, iOutputBuffer.Right(convResult)); |
|
1124 } |
|
1125 |
|
1126 if(convResult >= 0) |
|
1127 { |
|
1128 iSizeTally += narrow->Size(); |
|
1129 |
|
1130 if (!iOnlyCalculatingSize) |
|
1131 { |
|
1132 error = iXMLFile.Write(narrow->Des()); |
|
1133 } |
|
1134 } |
|
1135 else |
|
1136 { |
|
1137 error = convResult; |
|
1138 } |
|
1139 CleanupStack::PopAndDestroy(narrow); |
|
1140 } |
|
1141 break; |
|
1142 } |
|
1143 |
|
1144 case EUnicode: |
|
1145 { |
|
1146 TPtrC output16 = iOutputBuffer; |
|
1147 TPtrC8 output = DES_AS_8_BIT(output16); |
|
1148 |
|
1149 iSizeTally += output.Size(); |
|
1150 |
|
1151 if (!iOnlyCalculatingSize) |
|
1152 { |
|
1153 error = iXMLFile.Write(output); |
|
1154 } |
|
1155 |
|
1156 break; |
|
1157 } |
|
1158 |
|
1159 default: |
|
1160 error = KErrNotSupported; |
|
1161 break; |
|
1162 } |
|
1163 |
|
1164 if(error != KErrNone) |
|
1165 { |
|
1166 SetError(error, EXMLFatal); |
|
1167 } |
|
1168 |
|
1169 return error; |
|
1170 } |
|
1171 |
|
1172 //================================================================================== |
|
1173 |
|
1174 EXPORT_C void CMDXMLComposer::SetError(const TInt aErrorCode, const TXMLErrorCodeSeverity aSeverity) |
|
1175 // |
|
1176 // Sets iError to new errorcode if more serious than any error so far encountered |
|
1177 // |
|
1178 { |
|
1179 if(iSeverity > aSeverity) |
|
1180 { |
|
1181 iSeverity = aSeverity; |
|
1182 iError = aErrorCode; |
|
1183 } |
|
1184 } |
|
1185 |
|
1186 EXPORT_C void CMDXMLComposer::PlaceholderForRemovedExport1(MMDXMLComposerObserver* /*aComposerObserver*/) |
|
1187 { |
|
1188 User::Panic(KLDRIMPORT, KLdrImportedOrdinalDoesNotExist); |
|
1189 } |
|
1190 |
|
1191 EXPORT_C void CMDXMLComposer::PlaceholderForRemovedExport2() |
|
1192 { |
|
1193 User::Panic(KLDRIMPORT, KLdrImportedOrdinalDoesNotExist); |
|
1194 } |
|
1195 |
|
1196 EXPORT_C void CMDXMLComposer::PlaceholderForRemovedExport3() |
|
1197 { |
|
1198 User::Panic(KLDRIMPORT, KLdrImportedOrdinalDoesNotExist); |
|
1199 } |
|
1200 |
|
1201 // End of File |