1 // Created on: 2001-06-28
2 // Created by: Alexander GRIGORIEV
3 // Copyright (c) 2001-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <LDOM_XmlWriter.hxx>
17 #include <LDOM_Document.hxx>
18 #include <LDOM_CharReference.hxx>
19
20 #define chOpenAngle '<'
21 #define chCloseAngle '>'
22 #define chOpenSquare '['
23 #define chCloseSquare ']'
24 #define chQuestion '?'
25 #define chForwardSlash '/'
26 #define chLF '\n'
27 #define chNull '\0'
28 #define chEqual '='
29 #define chDash '-'
30 #define chBang '!'
31 #define chSpace ' '
32 #define chDoubleQuote '\"'
33 #define chZero '0'
34 #define chOne '1'
35 #define chTwo '2'
36 #define chThree '3'
37 #define chFour '4'
38 #define chFive '5'
39 #define chSix '6'
40 #define chSeven '7'
41 #define chEight '8'
42 #define chNine '9'
43 #define chLatin_a 'a'
44 #define chLatin_b 'b'
45 #define chLatin_c 'c'
46 #define chLatin_d 'd'
47 #define chLatin_e 'e'
48 #define chLatin_f 'f'
49 #define chLatin_g 'g'
50 #define chLatin_h 'h'
51 #define chLatin_i 'i'
52 #define chLatin_j 'j'
53 #define chLatin_k 'k'
54 #define chLatin_l 'l'
55 #define chLatin_m 'm'
56 #define chLatin_n 'n'
57 #define chLatin_o 'o'
58 #define chLatin_p 'p'
59 #define chLatin_q 'q'
60 #define chLatin_r 'r'
61 #define chLatin_s 's'
62 #define chLatin_t 't'
63 #define chLatin_u 'u'
64 #define chLatin_v 'v'
65 #define chLatin_w 'w'
66 #define chLatin_x 'x'
67 #define chLatin_y 'y'
68 #define chLatin_z 'z'
69 #define chLatin_A 'A'
70 #define chLatin_B 'B'
71 #define chLatin_C 'C'
72 #define chLatin_D 'D'
73 #define chLatin_E 'E'
74 #define chLatin_F 'F'
75 #define chLatin_G 'G'
76 #define chLatin_H 'H'
77 #define chLatin_I 'I'
78 #define chLatin_J 'J'
79 #define chLatin_K 'K'
80 #define chLatin_L 'L'
81 #define chLatin_M 'M'
82 #define chLatin_N 'N'
83 #define chLatin_O 'O'
84 #define chLatin_P 'P'
85 #define chLatin_Q 'Q'
86 #define chLatin_R 'R'
87 #define chLatin_S 'S'
88 #define chLatin_T 'T'
89 #define chLatin_U 'U'
90 #define chLatin_V 'V'
91 #define chLatin_W 'W'
92 #define chLatin_X 'X'
93 #define chLatin_Y 'Y'
94 #define chLatin_Z 'Z'
95
96 static const char gEndElement[] = { chOpenAngle, chForwardSlash, chNull };
97 static const char gEndElement1[]= { chForwardSlash, chNull };
98
99 static const char gXMLDecl1[] =
100 { chOpenAngle, chQuestion, chLatin_x, chLatin_m, chLatin_l
101 , chSpace, chLatin_v, chLatin_e, chLatin_r, chLatin_s, chLatin_i
102 , chLatin_o, chLatin_n, chEqual, chDoubleQuote, chNull
103 };
104 static const char gXMLDecl2[] =
105 { chDoubleQuote, chSpace, chLatin_e, chLatin_n, chLatin_c
106 , chLatin_o, chLatin_d, chLatin_i, chLatin_n, chLatin_g, chEqual
107 , chDoubleQuote, chNull
108 };
109
110 static const char gXMLDecl4[] =
111 { chDoubleQuote, chQuestion, chCloseAngle
112 , chLF, chNull
113 };
114 static const char gStartCDATA[] =
115 { chOpenAngle, chBang, chOpenSquare, chLatin_C, chLatin_D,
116 chLatin_A, chLatin_T, chLatin_A, chOpenSquare, chNull
117 };
118 static const char gEndCDATA[] =
119 { chCloseSquare, chCloseSquare, chCloseAngle, chNull };
120 static const char gStartComment[] =
121 { chOpenAngle, chBang, chDash, chDash, chNull };
122 static const char gEndComment[] =
123 { chDash, chDash, chCloseAngle, chNull };
124
getEncodingName(const char * theEncodingName)125 static char* getEncodingName (const char* theEncodingName)
126 {
127 const char* anEncoding = theEncodingName;
128 if (theEncodingName == NULL)
129 {
130 static const char anUTFEncoding [] = {chLatin_U, chLatin_T, chLatin_F, chDash, chEight, chNull};
131 anEncoding = anUTFEncoding;
132 }
133
134 Standard_Integer aLen = 0;
135 while (anEncoding[aLen++] != chNull);
136
137 char * aResult = new char [aLen];
138 memcpy (aResult, anEncoding, aLen * sizeof (char));
139
140 return aResult;
141 }
142
143 //=======================================================================
144 //function : LDOM_XmlWriter
145 //purpose :
146 //=======================================================================
LDOM_XmlWriter(const char * theEncoding)147 LDOM_XmlWriter::LDOM_XmlWriter (const char * theEncoding)
148 : myEncodingName (::getEncodingName (theEncoding)),
149 myIndent (0),
150 myCurIndent (0),
151 myABuffer (NULL),
152 myABufferLen (0)
153 {
154 ;
155 }
156
157 //=======================================================================
158 //function : ~LDOM_XmlWriter
159 //purpose : Destructor
160 //=======================================================================
~LDOM_XmlWriter()161 LDOM_XmlWriter::~LDOM_XmlWriter ()
162 {
163 delete [] myEncodingName;
164
165 if (myABuffer != NULL)
166 {
167 delete [] myABuffer;
168 }
169 }
170
171 //=======================================================================
172 //function : Write
173 //purpose :
174 //=======================================================================
Write(Standard_OStream & theOStream,const LDOM_Document & aDoc)175 void LDOM_XmlWriter::Write (Standard_OStream& theOStream, const LDOM_Document& aDoc)
176 {
177 Write (theOStream, gXMLDecl1);
178
179 const char * anXMLversion = "1.0";
180 Write (theOStream, anXMLversion);
181
182 Write (theOStream, gXMLDecl2);
183 Write (theOStream, myEncodingName);
184 Write (theOStream, gXMLDecl4);
185
186 Write (theOStream, aDoc.getDocumentElement());
187 }
188
189 //=======================================================================
190 //function : Write
191 //purpose :
192 //=======================================================================
Write(Standard_OStream & theOStream,const LDOM_Node & theNode)193 void LDOM_XmlWriter::Write (Standard_OStream& theOStream, const LDOM_Node& theNode)
194 {
195 // Get the name and value out for convenience
196 LDOMString aNodeName = theNode.getNodeName();
197 LDOMString aNodeValue = theNode.getNodeValue();
198
199 switch (theNode.getNodeType())
200 {
201 case LDOM_Node::TEXT_NODE :
202 Write (theOStream, aNodeValue);
203 break;
204 case LDOM_Node::ELEMENT_NODE :
205 {
206 const int aMaxNSpaces = 40;
207 static char aSpaces [] = {
208 chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace,
209 chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace,
210 chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace,
211 chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace,
212 chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace,
213 chOpenAngle, chNull };
214 const char * anIndentString = &aSpaces [aMaxNSpaces - myCurIndent];
215
216 if (anIndentString < &aSpaces[0])
217 {
218 anIndentString = &aSpaces[0];
219 }
220
221 // Output the element start tag.
222 Write (theOStream, anIndentString);
223 Write (theOStream, aNodeName.GetString());
224
225 // Output any attributes of this element
226 const LDOM_Element& anElemToWrite = (const LDOM_Element&)theNode;
227 LDOM_NodeList aListAtt = anElemToWrite.GetAttributesList();
228 Standard_Integer aListInd = aListAtt.getLength();
229
230 while (aListInd--)
231 {
232 LDOM_Node aChild = aListAtt.item (aListInd);
233 WriteAttribute (theOStream, aChild);
234 }
235
236 // Test for the presence of children
237 LDOM_Node aChild = theNode.getFirstChild();
238 if (aChild != 0)
239 {
240 // There are children. Close start-tag, and output children.
241 Write (theOStream, chCloseAngle);
242 if (aChild.getNodeType() == LDOM_Node::ELEMENT_NODE && myIndent > 0)
243 {
244 Write(theOStream, chLF);
245 }
246
247 Standard_Boolean isChildElem = Standard_False;
248 while( aChild != 0)
249 {
250 isChildElem = (aChild.getNodeType() == LDOM_Node::ELEMENT_NODE);
251 if (isChildElem)
252 {
253 myCurIndent += myIndent;
254 }
255
256 Write(theOStream, aChild);
257
258 if (isChildElem)
259 {
260 myCurIndent -= myIndent;
261 }
262
263 do
264 {
265 aChild = aChild.getNextSibling();
266 } while (aChild.getNodeType() == LDOM_Node::ATTRIBUTE_NODE);
267 }
268
269 // Done with children. Output the end tag.
270 if (isChildElem)
271 {
272 Write (theOStream, anIndentString);
273 Write (theOStream, gEndElement1);
274 Write (theOStream, aNodeName.GetString());
275 Write (theOStream, chCloseAngle);
276 }
277 else
278 {
279 Write (theOStream, gEndElement);
280 Write (theOStream, aNodeName.GetString());
281 Write (theOStream, chCloseAngle);
282 }
283 }
284 else
285 {
286 // There were no children. Output the short form close of
287 // the element start tag, making it an empty-element tag.
288 Write (theOStream, chForwardSlash);
289 Write (theOStream, chCloseAngle);
290 }
291
292 if (myIndent > 0)
293 {
294 Write (theOStream, chLF);
295 }
296 break;
297 }
298 case LDOM_Node::CDATA_SECTION_NODE:
299 {
300 Write (theOStream, gStartCDATA);
301 Write (theOStream, aNodeValue);
302 Write (theOStream, gEndCDATA);
303 break;
304 }
305 case LDOM_Node::COMMENT_NODE:
306 {
307 Write (theOStream, gStartComment);
308 Write (theOStream, aNodeValue);
309 Write (theOStream, gEndComment);
310 break;
311 }
312 default:
313 #ifndef _MSC_VER
314 std::cerr << "Unrecognized node type = "
315 << (long)theNode.getNodeType() << std::endl
316 #endif
317 ; }
318 }
319
320 //=======================================================================
321 //function :
322 //purpose : Stream out an LDOMString
323 //=======================================================================
Write(Standard_OStream & theOStream,const LDOMBasicString & theString)324 void LDOM_XmlWriter::Write (Standard_OStream& theOStream, const LDOMBasicString& theString)
325 {
326 switch (theString.Type())
327 {
328 case LDOMBasicString::LDOM_Integer:
329 {
330 Standard_Integer aValue;
331 theString.GetInteger (aValue);
332
333 TCollection_AsciiString aStrValue (aValue);
334 theOStream.write(aStrValue.ToCString(), strlen (aStrValue.ToCString()));
335
336 break;
337 }
338 case LDOMBasicString::LDOM_AsciiHashed: // attr names and element tags
339 case LDOMBasicString::LDOM_AsciiDocClear:
340 {
341 const char* aStr = theString.GetString();
342 if (aStr)
343 {
344 const Standard_Size aLen = strlen (aStr);
345 if (aLen > 0)
346 {
347 theOStream.write(aStr, aLen);
348 }
349 }
350 }
351 break;
352 case LDOMBasicString::LDOM_AsciiFree:
353 case LDOMBasicString::LDOM_AsciiDoc:
354 {
355 const char* aStr = theString.GetString();
356 if (aStr)
357 {
358 Standard_Integer aLen;
359 char* encStr = LDOM_CharReference::Encode (aStr, aLen, Standard_False);
360 if (aLen > 0)
361 {
362 theOStream.write(encStr, aLen);
363 }
364
365 if (encStr != aStr)
366 {
367 delete [] encStr;
368 }
369 }
370 }
371 default: ;
372 }
373 }
374
375 //=======================================================================
376 //function : Write
377 //purpose : Stream out a char
378 //=======================================================================
Write(Standard_OStream & theOStream,const char theChar)379 void LDOM_XmlWriter::Write (Standard_OStream& theOStream, const char theChar)
380 {
381 theOStream.write (&theChar, sizeof(char));
382 }
383
384 //=======================================================================
385 //function : Write
386 //purpose : Stream out a char *
387 //=======================================================================
Write(Standard_OStream & theOStream,const char * theString)388 void LDOM_XmlWriter::Write (Standard_OStream& theOStream, const char * theString)
389 {
390 Standard_Size aLength = strlen (theString);
391 if (aLength > 0)
392 {
393 theOStream.write (theString, aLength);
394 }
395 }
396
397 //=======================================================================
398 //function : WriteAttribute()
399 //purpose : Stream out an XML attribute.
400 //=======================================================================
WriteAttribute(Standard_OStream & theOStream,const LDOM_Node & theAtt)401 void LDOM_XmlWriter::WriteAttribute (Standard_OStream& theOStream, const LDOM_Node& theAtt)
402 {
403 const char* aName = theAtt.getNodeName().GetString();
404 const LDOMString aValueStr = theAtt.getNodeValue();
405
406 int aLength = 0;
407
408 // Integer attribute value
409 if (aValueStr.Type() == LDOMBasicString::LDOM_Integer)
410 {
411 Standard_Integer anIntValue;
412 aValueStr.GetInteger (anIntValue);
413
414 aLength = (Standard_Integer)(20 + strlen (aName));
415 if (aLength > myABufferLen)
416 {
417 if (myABuffer != NULL)
418 {
419 delete [] myABuffer;
420 }
421
422 myABuffer = new char [aLength+1];
423 myABufferLen = aLength;
424 }
425 sprintf (myABuffer, "%c%s%c%c%d%c", chSpace, aName, chEqual, chDoubleQuote, anIntValue, chDoubleQuote);
426 aLength = (Standard_Integer)strlen (myABuffer);
427
428
429 }
430 else // String attribute value
431 {
432 char* encStr;
433 const char* aValue = aValueStr.GetString();
434 if (aValueStr.Type() == LDOMBasicString::LDOM_AsciiDocClear)
435 {
436 encStr = (char *) aValue;
437 aLength = (Standard_Integer) (4 + strlen (aValue) + strlen (aName));
438 }
439 else
440 {
441 encStr = LDOM_CharReference::Encode (aValue, aLength, Standard_True);
442 aLength += (Standard_Integer) (4 + strlen (aName));
443 }
444
445 if (aLength > myABufferLen)
446 {
447 if (myABuffer != NULL)
448 {
449 delete [] myABuffer;
450 }
451
452 myABuffer = new char [aLength+1];
453 myABufferLen = aLength;
454 }
455
456 sprintf (myABuffer, "%c%s%c%c%s%c", chSpace, aName, chEqual, chDoubleQuote, encStr, chDoubleQuote);
457
458 if (encStr != aValue)
459 {
460 delete [] encStr;
461 }
462 }
463
464 theOStream.write (myABuffer, aLength);
465 }
466