b311480e |
1 | // Created on: 2001-06-28 |
2 | // Created by: Alexander GRIGORIEV |
973c2be1 |
3 | // Copyright (c) 2001-2014 OPEN CASCADE SAS |
b311480e |
4 | // |
973c2be1 |
5 | // This file is part of Open CASCADE Technology software library. |
b311480e |
6 | // |
d5f74e42 |
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 |
973c2be1 |
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. |
b311480e |
12 | // |
973c2be1 |
13 | // Alternatively, this file may be used under the terms of Open CASCADE |
14 | // commercial license or contractual agreement. |
7fd59977 |
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 LXMLCh gEndElement[] = { chOpenAngle, chForwardSlash, chNull }; |
97 | static const LXMLCh gEndElement1[]= { chForwardSlash, chNull }; |
f24125b9 |
98 | //static const LXMLCh gEndPI[] = { chQuestion, chCloseAngle, chNull }; |
99 | //static const LXMLCh gStartPI[] = { chOpenAngle, chQuestion, chNull }; |
7fd59977 |
100 | static const LXMLCh gXMLDecl1[] = |
101 | { chOpenAngle, chQuestion, chLatin_x, chLatin_m, chLatin_l |
102 | , chSpace, chLatin_v, chLatin_e, chLatin_r, chLatin_s, chLatin_i |
103 | , chLatin_o, chLatin_n, chEqual, chDoubleQuote, chNull |
104 | }; |
105 | static const LXMLCh gXMLDecl2[] = |
106 | { chDoubleQuote, chSpace, chLatin_e, chLatin_n, chLatin_c |
107 | , chLatin_o, chLatin_d, chLatin_i, chLatin_n, chLatin_g, chEqual |
108 | , chDoubleQuote, chNull |
109 | }; |
f24125b9 |
110 | /* |
7fd59977 |
111 | static const LXMLCh gXMLDecl3[] = |
112 | { chDoubleQuote, chSpace, chLatin_s, chLatin_t, chLatin_a |
113 | , chLatin_n, chLatin_d, chLatin_a, chLatin_l, chLatin_o |
114 | , chLatin_n, chLatin_e, chEqual, chDoubleQuote, chNull |
115 | }; |
f24125b9 |
116 | */ |
7fd59977 |
117 | static const LXMLCh gXMLDecl4[] = |
118 | { chDoubleQuote, chQuestion, chCloseAngle |
119 | , chLF, chNull |
120 | }; |
121 | static const LXMLCh gStartCDATA[] = |
122 | { chOpenAngle, chBang, chOpenSquare, chLatin_C, chLatin_D, |
123 | chLatin_A, chLatin_T, chLatin_A, chOpenSquare, chNull |
124 | }; |
125 | static const LXMLCh gEndCDATA[] = |
126 | { chCloseSquare, chCloseSquare, chCloseAngle, chNull }; |
127 | static const LXMLCh gStartComment[] = |
128 | { chOpenAngle, chBang, chDash, chDash, chNull }; |
129 | static const LXMLCh gEndComment[] = |
130 | { chDash, chDash, chCloseAngle, chNull }; |
f24125b9 |
131 | /* |
7fd59977 |
132 | static const LXMLCh gStartDoctype[] = |
133 | { chOpenAngle, chBang, chLatin_D, chLatin_O, chLatin_C, chLatin_T, |
134 | chLatin_Y, chLatin_P, chLatin_E, chSpace, chNull |
135 | }; |
136 | static const LXMLCh gPublic[] = |
137 | { chLatin_P, chLatin_U, chLatin_B, chLatin_L, chLatin_I, |
138 | chLatin_C, chSpace, chDoubleQuote, chNull |
139 | }; |
140 | static const LXMLCh gSystem[] = |
141 | { chLatin_S, chLatin_Y, chLatin_S, chLatin_T, chLatin_E, |
142 | chLatin_M, chSpace, chDoubleQuote, chNull |
143 | }; |
144 | static const LXMLCh gStartEntity[] = |
145 | { chOpenAngle, chBang, chLatin_E, chLatin_N, chLatin_T, chLatin_I, |
146 | chLatin_T, chLatin_Y, chSpace, chNull |
147 | }; |
148 | static const LXMLCh gNotation[] = |
149 | { chLatin_N, chLatin_D, chLatin_A, chLatin_T, chLatin_A, |
150 | chSpace, chDoubleQuote, chNull |
151 | }; |
f24125b9 |
152 | */ |
7fd59977 |
153 | |
154 | static LXMLCh * getEncodingName (const LXMLCh * theEncodingName) |
155 | { |
156 | const LXMLCh * anEncoding = theEncodingName; |
157 | if (theEncodingName == NULL) |
158 | { |
159 | // anEncoding = // US-ASCII |
160 | // { chLatin_U, chLatin_S, chDash, chLatin_A, chLatin_S, chLatin_C, chLatin_I, |
161 | // chLatin_I, chNull }; |
162 | static const LXMLCh anUTFEncoding [] = // UTF-8 |
163 | { chLatin_U, chLatin_T, chLatin_F, chDash, chEight, chNull }; |
164 | anEncoding = anUTFEncoding; |
165 | } |
166 | Standard_Integer aLen = 0; |
167 | while (anEncoding[aLen++] != chNull); |
168 | LXMLCh * aResult = new LXMLCh [aLen]; |
169 | memcpy (aResult, anEncoding, aLen * sizeof (LXMLCh)); |
170 | return aResult; |
171 | } |
172 | |
173 | //======================================================================= |
174 | //function : LH3D_LXMLWriter() |
175 | //purpose : Constructor |
176 | //======================================================================= |
177 | LDOM_XmlWriter::LDOM_XmlWriter (FILE * aFile, |
178 | const LXMLCh * theEncoding) |
179 | : myFile (aFile), |
180 | myEncodingName (::getEncodingName (theEncoding)), |
181 | myIndent (0), |
182 | myCurIndent (0), |
183 | myABuffer (NULL), |
184 | myABufferLen (0) |
185 | {} |
186 | |
187 | //======================================================================= |
188 | //function : ~LDOM_XmlWriter |
189 | //purpose : Destructor |
190 | //======================================================================= |
191 | |
192 | LDOM_XmlWriter::~LDOM_XmlWriter () |
193 | { |
194 | delete [] myEncodingName; |
195 | if (myABuffer != NULL) delete [] myABuffer; |
196 | } |
197 | |
198 | //======================================================================= |
199 | //function : operator << |
200 | //purpose : |
201 | //======================================================================= |
202 | |
203 | LDOM_XmlWriter& LDOM_XmlWriter::operator << (const LDOM_Document& aDoc) |
204 | { |
205 | const char * anXMLversion = "1.0"; |
206 | * this << gXMLDecl1 << anXMLversion |
207 | << gXMLDecl2 << myEncodingName << gXMLDecl4; |
208 | |
209 | return (* this << aDoc.getDocumentElement()); |
210 | } |
211 | |
212 | //======================================================================= |
213 | //function : operator << |
214 | //purpose : Stream out an LDOMString |
215 | //======================================================================= |
216 | |
217 | inline LDOM_XmlWriter& LDOM_XmlWriter::operator << |
218 | (const LDOMBasicString& aString) |
219 | { |
220 | switch (aString.Type()) { |
221 | case LDOMBasicString::LDOM_Integer: |
222 | { |
223 | Standard_Integer aValue; |
224 | aString.GetInteger (aValue); |
225 | fprintf (myFile, "%d", aValue); |
226 | break; |
227 | } |
228 | case LDOMBasicString::LDOM_AsciiHashed: // attr names and element tags |
229 | case LDOMBasicString::LDOM_AsciiDocClear: |
230 | { |
231 | const char * str = aString.GetString(); |
232 | if (str) { |
60be1f9b |
233 | const Standard_Size aLen = strlen (str); |
7fd59977 |
234 | if (aLen > 0) fwrite (str, aLen, 1, myFile); |
235 | } |
236 | } |
237 | break; |
238 | case LDOMBasicString::LDOM_AsciiFree: |
239 | case LDOMBasicString::LDOM_AsciiDoc: |
240 | { |
241 | const char * str = aString.GetString(); |
242 | if (str) { |
243 | Standard_Integer aLen; |
244 | char * encStr = LDOM_CharReference::Encode(str, aLen, Standard_False); |
245 | if (aLen > 0) fwrite (encStr, aLen, 1, myFile); |
246 | if (encStr != str) delete [] encStr; |
247 | } |
248 | } |
249 | default: ; |
250 | } |
251 | return * this; |
252 | } |
253 | |
254 | //======================================================================= |
255 | //function : operator<<() |
256 | //purpose : Stream out a char *. |
257 | //======================================================================= |
258 | inline LDOM_XmlWriter& LDOM_XmlWriter::operator << (const LXMLCh * aString) |
259 | { |
60be1f9b |
260 | Standard_Size aLength = strlen (aString); |
7fd59977 |
261 | if (aLength > 0) fwrite ((void *) aString, aLength, 1, myFile); |
262 | return * this; |
263 | } |
264 | |
265 | //======================================================================= |
266 | //function : operator<<() |
267 | //purpose : Stream out a character. |
268 | //======================================================================= |
269 | inline LDOM_XmlWriter& LDOM_XmlWriter::operator << (const LXMLCh aChar) |
270 | { |
271 | fputc (aChar, myFile); |
272 | return * this; |
273 | } |
274 | |
275 | //======================================================================= |
276 | //function : WriteAttribute() |
277 | //purpose : Stream out an XML attribute. |
278 | //======================================================================= |
279 | void LDOM_XmlWriter::WriteAttribute (const LDOM_Node& theAtt) |
280 | { |
281 | int aLength; |
282 | const char * aName = theAtt.getNodeName().GetString(); |
283 | const LDOMString aValueStr = theAtt.getNodeValue(); |
284 | |
285 | // Integer attribute value |
286 | if (aValueStr.Type() == LDOMBasicString::LDOM_Integer) { |
287 | Standard_Integer anIntValue; |
288 | aValueStr.GetInteger (anIntValue); |
60be1f9b |
289 | aLength = (Standard_Integer) (20 + strlen (aName)); |
7fd59977 |
290 | if (aLength > myABufferLen) { |
291 | if (myABuffer != NULL) delete [] myABuffer; |
292 | myABuffer = new char [aLength+1]; |
293 | myABufferLen = aLength; |
294 | } |
295 | sprintf (myABuffer, "%c%s%c%c%d%c", chSpace, aName, |
296 | chEqual, chDoubleQuote, anIntValue, chDoubleQuote); |
60be1f9b |
297 | aLength = (Standard_Integer) strlen (myABuffer); |
7fd59977 |
298 | |
299 | // String attribute value |
300 | } else { |
301 | const char * aValue = aValueStr.GetString(); |
302 | char * encStr; |
303 | if (aValueStr.Type() == LDOMBasicString::LDOM_AsciiDocClear) { |
304 | encStr = (char *) aValue; |
60be1f9b |
305 | aLength = (Standard_Integer) (4 + strlen (aValue) + strlen (aName)); |
7fd59977 |
306 | } else { |
307 | encStr = LDOM_CharReference::Encode (aValue, aLength, Standard_True); |
60be1f9b |
308 | aLength += (Standard_Integer) (4 + strlen (aName)); |
7fd59977 |
309 | } |
310 | if (aLength > myABufferLen) { |
311 | if (myABuffer != NULL) delete [] myABuffer; |
312 | myABuffer = new char [aLength+1]; |
313 | myABufferLen = aLength; |
314 | } |
315 | sprintf (myABuffer, "%c%s%c%c%s%c", chSpace, aName, |
316 | chEqual, chDoubleQuote, encStr, chDoubleQuote); |
317 | if (encStr != aValue) delete [] encStr; |
318 | } |
319 | fwrite ((void *) myABuffer, aLength, 1, myFile); |
320 | } |
321 | |
322 | //======================================================================= |
323 | //function : operator<<() |
324 | //purpose : Stream out a DOM node, and, recursively, all of its children. |
325 | // This function is the heart of writing a DOM tree out as XML source. |
326 | // Give it a document node and it will do the whole thing. |
327 | //======================================================================= |
328 | LDOM_XmlWriter& LDOM_XmlWriter::operator<< (const LDOM_Node& theNodeToWrite) |
329 | { |
330 | // Get the name and value out for convenience |
331 | LDOMString aNodeName = theNodeToWrite.getNodeName(); |
332 | LDOMString aNodeValue = theNodeToWrite.getNodeValue(); |
333 | // unsigned long dwLent = aNodeValue.length(); |
334 | |
335 | switch (theNodeToWrite.getNodeType()) |
336 | { |
337 | case LDOM_Node::TEXT_NODE : |
338 | * this << aNodeValue; |
339 | break; |
340 | case LDOM_Node::ELEMENT_NODE : |
341 | { |
342 | const int aMaxNSpaces = 40; |
343 | static LXMLCh aSpaces [] = { |
344 | chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, |
345 | chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, |
346 | chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, |
347 | chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, |
348 | chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, |
349 | chOpenAngle, chNull }; |
350 | const LXMLCh * anIndentString = &aSpaces [aMaxNSpaces - myCurIndent]; |
351 | if (anIndentString < &aSpaces[0]) anIndentString = &aSpaces[0]; |
352 | |
353 | // Output the element start tag. |
354 | * this << anIndentString << aNodeName.GetString(); |
355 | |
356 | // Output any attributes of this element |
357 | const LDOM_Element& anElemToWrite = (const LDOM_Element&) theNodeToWrite; |
358 | LDOM_NodeList aListAtt = anElemToWrite.GetAttributesList (); |
359 | Standard_Integer aListInd = aListAtt.getLength(); |
360 | while (aListInd--) { |
361 | LDOM_Node aChild = aListAtt.item (aListInd); |
362 | WriteAttribute (aChild); |
363 | } |
364 | |
365 | // Test for the presence of children |
366 | LDOM_Node aChild = theNodeToWrite.getFirstChild(); |
367 | if (aChild != 0) |
368 | { |
369 | // There are children. Close start-tag, and output children. |
370 | * this << chCloseAngle; |
371 | if (aChild.getNodeType() == LDOM_Node::ELEMENT_NODE && myIndent > 0) |
372 | * this << chLF; |
373 | Standard_Boolean isChildElem = Standard_False; |
374 | while( aChild != 0) |
375 | { |
376 | isChildElem = (aChild.getNodeType() == LDOM_Node::ELEMENT_NODE); |
377 | if (isChildElem) myCurIndent += myIndent; |
378 | *this << aChild; |
379 | if (isChildElem) myCurIndent -= myIndent; |
380 | do aChild = aChild.getNextSibling(); |
381 | while (aChild.getNodeType() == LDOM_Node::ATTRIBUTE_NODE); |
382 | } |
383 | // Done with children. Output the end tag. |
384 | // |
385 | if (isChildElem) |
386 | * this << anIndentString |
387 | << gEndElement1 << aNodeName.GetString() << chCloseAngle; |
388 | else |
389 | * this << gEndElement << aNodeName.GetString() << chCloseAngle; |
390 | } |
391 | else |
392 | { |
393 | // There were no children. Output the short form close of |
394 | // the element start tag, making it an empty-element tag. |
395 | * this << chForwardSlash << chCloseAngle; |
396 | } |
397 | if (myIndent > 0) |
398 | * this << chLF; |
399 | break; |
400 | } |
401 | case LDOM_Node::CDATA_SECTION_NODE: |
402 | { |
403 | * this << gStartCDATA << aNodeValue << gEndCDATA; |
404 | break; |
405 | } |
406 | case LDOM_Node::COMMENT_NODE: |
407 | { |
408 | * this << gStartComment << aNodeValue << gEndComment; |
409 | break; |
410 | } |
411 | default: |
57c28b61 |
412 | #ifndef _MSC_VER |
7fd59977 |
413 | cerr << "Unrecognized node type = " |
414 | << (long)theNodeToWrite.getNodeType() << endl |
415 | #endif |
416 | ; } |
417 | return *this; |
418 | } |