b311480e |
1 | // Created on: 2001-06-28 |
2 | // Created by: Alexander GRIGORIEV |
3 | // Copyright (c) 2001-2012 OPEN CASCADE SAS |
4 | // |
5 | // The content of this file is subject to the Open CASCADE Technology Public |
6 | // License Version 6.5 (the "License"). You may not use the content of this file |
7 | // except in compliance with the License. Please obtain a copy of the License |
8 | // at http://www.opencascade.org and read it completely before using this file. |
9 | // |
10 | // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its |
11 | // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France. |
12 | // |
13 | // The Original Code and all software distributed under the License is |
14 | // distributed on an "AS IS" basis, without warranty of any kind, and the |
15 | // Initial Developer hereby disclaims all such warranties, including without |
16 | // limitation, any warranties of merchantability, fitness for a particular |
17 | // purpose or non-infringement. Please see the License for the specific terms |
18 | // and conditions governing the rights and limitations under the License. |
19 | |
7fd59977 |
20 | |
21 | |
22 | #include <LDOM_XmlWriter.hxx> |
23 | #include <LDOM_Document.hxx> |
24 | #include <LDOM_CharReference.hxx> |
25 | |
26 | #define chOpenAngle '<' |
27 | #define chCloseAngle '>' |
28 | #define chOpenSquare '[' |
29 | #define chCloseSquare ']' |
30 | #define chQuestion '?' |
31 | #define chForwardSlash '/' |
32 | #define chLF '\n' |
33 | #define chNull '\0' |
34 | #define chEqual '=' |
35 | #define chDash '-' |
36 | #define chBang '!' |
37 | #define chSpace ' ' |
38 | #define chDoubleQuote '\"' |
39 | #define chZero '0' |
40 | #define chOne '1' |
41 | #define chTwo '2' |
42 | #define chThree '3' |
43 | #define chFour '4' |
44 | #define chFive '5' |
45 | #define chSix '6' |
46 | #define chSeven '7' |
47 | #define chEight '8' |
48 | #define chNine '9' |
49 | #define chLatin_a 'a' |
50 | #define chLatin_b 'b' |
51 | #define chLatin_c 'c' |
52 | #define chLatin_d 'd' |
53 | #define chLatin_e 'e' |
54 | #define chLatin_f 'f' |
55 | #define chLatin_g 'g' |
56 | #define chLatin_h 'h' |
57 | #define chLatin_i 'i' |
58 | #define chLatin_j 'j' |
59 | #define chLatin_k 'k' |
60 | #define chLatin_l 'l' |
61 | #define chLatin_m 'm' |
62 | #define chLatin_n 'n' |
63 | #define chLatin_o 'o' |
64 | #define chLatin_p 'p' |
65 | #define chLatin_q 'q' |
66 | #define chLatin_r 'r' |
67 | #define chLatin_s 's' |
68 | #define chLatin_t 't' |
69 | #define chLatin_u 'u' |
70 | #define chLatin_v 'v' |
71 | #define chLatin_w 'w' |
72 | #define chLatin_x 'x' |
73 | #define chLatin_y 'y' |
74 | #define chLatin_z 'z' |
75 | #define chLatin_A 'A' |
76 | #define chLatin_B 'B' |
77 | #define chLatin_C 'C' |
78 | #define chLatin_D 'D' |
79 | #define chLatin_E 'E' |
80 | #define chLatin_F 'F' |
81 | #define chLatin_G 'G' |
82 | #define chLatin_H 'H' |
83 | #define chLatin_I 'I' |
84 | #define chLatin_J 'J' |
85 | #define chLatin_K 'K' |
86 | #define chLatin_L 'L' |
87 | #define chLatin_M 'M' |
88 | #define chLatin_N 'N' |
89 | #define chLatin_O 'O' |
90 | #define chLatin_P 'P' |
91 | #define chLatin_Q 'Q' |
92 | #define chLatin_R 'R' |
93 | #define chLatin_S 'S' |
94 | #define chLatin_T 'T' |
95 | #define chLatin_U 'U' |
96 | #define chLatin_V 'V' |
97 | #define chLatin_W 'W' |
98 | #define chLatin_X 'X' |
99 | #define chLatin_Y 'Y' |
100 | #define chLatin_Z 'Z' |
101 | |
102 | static const LXMLCh gEndElement[] = { chOpenAngle, chForwardSlash, chNull }; |
103 | static const LXMLCh gEndElement1[]= { chForwardSlash, chNull }; |
104 | static const LXMLCh gEndPI[] = { chQuestion, chCloseAngle, chNull }; |
105 | static const LXMLCh gStartPI[] = { chOpenAngle, chQuestion, chNull }; |
106 | static const LXMLCh gXMLDecl1[] = |
107 | { chOpenAngle, chQuestion, chLatin_x, chLatin_m, chLatin_l |
108 | , chSpace, chLatin_v, chLatin_e, chLatin_r, chLatin_s, chLatin_i |
109 | , chLatin_o, chLatin_n, chEqual, chDoubleQuote, chNull |
110 | }; |
111 | static const LXMLCh gXMLDecl2[] = |
112 | { chDoubleQuote, chSpace, chLatin_e, chLatin_n, chLatin_c |
113 | , chLatin_o, chLatin_d, chLatin_i, chLatin_n, chLatin_g, chEqual |
114 | , chDoubleQuote, chNull |
115 | }; |
116 | static const LXMLCh gXMLDecl3[] = |
117 | { chDoubleQuote, chSpace, chLatin_s, chLatin_t, chLatin_a |
118 | , chLatin_n, chLatin_d, chLatin_a, chLatin_l, chLatin_o |
119 | , chLatin_n, chLatin_e, chEqual, chDoubleQuote, chNull |
120 | }; |
121 | static const LXMLCh gXMLDecl4[] = |
122 | { chDoubleQuote, chQuestion, chCloseAngle |
123 | , chLF, chNull |
124 | }; |
125 | static const LXMLCh gStartCDATA[] = |
126 | { chOpenAngle, chBang, chOpenSquare, chLatin_C, chLatin_D, |
127 | chLatin_A, chLatin_T, chLatin_A, chOpenSquare, chNull |
128 | }; |
129 | static const LXMLCh gEndCDATA[] = |
130 | { chCloseSquare, chCloseSquare, chCloseAngle, chNull }; |
131 | static const LXMLCh gStartComment[] = |
132 | { chOpenAngle, chBang, chDash, chDash, chNull }; |
133 | static const LXMLCh gEndComment[] = |
134 | { chDash, chDash, chCloseAngle, chNull }; |
135 | static const LXMLCh gStartDoctype[] = |
136 | { chOpenAngle, chBang, chLatin_D, chLatin_O, chLatin_C, chLatin_T, |
137 | chLatin_Y, chLatin_P, chLatin_E, chSpace, chNull |
138 | }; |
139 | static const LXMLCh gPublic[] = |
140 | { chLatin_P, chLatin_U, chLatin_B, chLatin_L, chLatin_I, |
141 | chLatin_C, chSpace, chDoubleQuote, chNull |
142 | }; |
143 | static const LXMLCh gSystem[] = |
144 | { chLatin_S, chLatin_Y, chLatin_S, chLatin_T, chLatin_E, |
145 | chLatin_M, chSpace, chDoubleQuote, chNull |
146 | }; |
147 | static const LXMLCh gStartEntity[] = |
148 | { chOpenAngle, chBang, chLatin_E, chLatin_N, chLatin_T, chLatin_I, |
149 | chLatin_T, chLatin_Y, chSpace, chNull |
150 | }; |
151 | static const LXMLCh gNotation[] = |
152 | { chLatin_N, chLatin_D, chLatin_A, chLatin_T, chLatin_A, |
153 | chSpace, chDoubleQuote, chNull |
154 | }; |
155 | |
156 | static LXMLCh * getEncodingName (const LXMLCh * theEncodingName) |
157 | { |
158 | const LXMLCh * anEncoding = theEncodingName; |
159 | if (theEncodingName == NULL) |
160 | { |
161 | // anEncoding = // US-ASCII |
162 | // { chLatin_U, chLatin_S, chDash, chLatin_A, chLatin_S, chLatin_C, chLatin_I, |
163 | // chLatin_I, chNull }; |
164 | static const LXMLCh anUTFEncoding [] = // UTF-8 |
165 | { chLatin_U, chLatin_T, chLatin_F, chDash, chEight, chNull }; |
166 | anEncoding = anUTFEncoding; |
167 | } |
168 | Standard_Integer aLen = 0; |
169 | while (anEncoding[aLen++] != chNull); |
170 | LXMLCh * aResult = new LXMLCh [aLen]; |
171 | memcpy (aResult, anEncoding, aLen * sizeof (LXMLCh)); |
172 | return aResult; |
173 | } |
174 | |
175 | //======================================================================= |
176 | //function : LH3D_LXMLWriter() |
177 | //purpose : Constructor |
178 | //======================================================================= |
179 | LDOM_XmlWriter::LDOM_XmlWriter (FILE * aFile, |
180 | const LXMLCh * theEncoding) |
181 | : myFile (aFile), |
182 | myEncodingName (::getEncodingName (theEncoding)), |
183 | myIndent (0), |
184 | myCurIndent (0), |
185 | myABuffer (NULL), |
186 | myABufferLen (0) |
187 | {} |
188 | |
189 | //======================================================================= |
190 | //function : ~LDOM_XmlWriter |
191 | //purpose : Destructor |
192 | //======================================================================= |
193 | |
194 | LDOM_XmlWriter::~LDOM_XmlWriter () |
195 | { |
196 | delete [] myEncodingName; |
197 | if (myABuffer != NULL) delete [] myABuffer; |
198 | } |
199 | |
200 | //======================================================================= |
201 | //function : operator << |
202 | //purpose : |
203 | //======================================================================= |
204 | |
205 | LDOM_XmlWriter& LDOM_XmlWriter::operator << (const LDOM_Document& aDoc) |
206 | { |
207 | const char * anXMLversion = "1.0"; |
208 | * this << gXMLDecl1 << anXMLversion |
209 | << gXMLDecl2 << myEncodingName << gXMLDecl4; |
210 | |
211 | return (* this << aDoc.getDocumentElement()); |
212 | } |
213 | |
214 | //======================================================================= |
215 | //function : operator << |
216 | //purpose : Stream out an LDOMString |
217 | //======================================================================= |
218 | |
219 | inline LDOM_XmlWriter& LDOM_XmlWriter::operator << |
220 | (const LDOMBasicString& aString) |
221 | { |
222 | switch (aString.Type()) { |
223 | case LDOMBasicString::LDOM_Integer: |
224 | { |
225 | Standard_Integer aValue; |
226 | aString.GetInteger (aValue); |
227 | fprintf (myFile, "%d", aValue); |
228 | break; |
229 | } |
230 | case LDOMBasicString::LDOM_AsciiHashed: // attr names and element tags |
231 | case LDOMBasicString::LDOM_AsciiDocClear: |
232 | { |
233 | const char * str = aString.GetString(); |
234 | if (str) { |
60be1f9b |
235 | const Standard_Size aLen = strlen (str); |
7fd59977 |
236 | if (aLen > 0) fwrite (str, aLen, 1, myFile); |
237 | } |
238 | } |
239 | break; |
240 | case LDOMBasicString::LDOM_AsciiFree: |
241 | case LDOMBasicString::LDOM_AsciiDoc: |
242 | { |
243 | const char * str = aString.GetString(); |
244 | if (str) { |
245 | Standard_Integer aLen; |
246 | char * encStr = LDOM_CharReference::Encode(str, aLen, Standard_False); |
247 | if (aLen > 0) fwrite (encStr, aLen, 1, myFile); |
248 | if (encStr != str) delete [] encStr; |
249 | } |
250 | } |
251 | default: ; |
252 | } |
253 | return * this; |
254 | } |
255 | |
256 | //======================================================================= |
257 | //function : operator<<() |
258 | //purpose : Stream out a char *. |
259 | //======================================================================= |
260 | inline LDOM_XmlWriter& LDOM_XmlWriter::operator << (const LXMLCh * aString) |
261 | { |
60be1f9b |
262 | Standard_Size aLength = strlen (aString); |
7fd59977 |
263 | if (aLength > 0) fwrite ((void *) aString, aLength, 1, myFile); |
264 | return * this; |
265 | } |
266 | |
267 | //======================================================================= |
268 | //function : operator<<() |
269 | //purpose : Stream out a character. |
270 | //======================================================================= |
271 | inline LDOM_XmlWriter& LDOM_XmlWriter::operator << (const LXMLCh aChar) |
272 | { |
273 | fputc (aChar, myFile); |
274 | return * this; |
275 | } |
276 | |
277 | //======================================================================= |
278 | //function : WriteAttribute() |
279 | //purpose : Stream out an XML attribute. |
280 | //======================================================================= |
281 | void LDOM_XmlWriter::WriteAttribute (const LDOM_Node& theAtt) |
282 | { |
283 | int aLength; |
284 | const char * aName = theAtt.getNodeName().GetString(); |
285 | const LDOMString aValueStr = theAtt.getNodeValue(); |
286 | |
287 | // Integer attribute value |
288 | if (aValueStr.Type() == LDOMBasicString::LDOM_Integer) { |
289 | Standard_Integer anIntValue; |
290 | aValueStr.GetInteger (anIntValue); |
60be1f9b |
291 | aLength = (Standard_Integer) (20 + strlen (aName)); |
7fd59977 |
292 | if (aLength > myABufferLen) { |
293 | if (myABuffer != NULL) delete [] myABuffer; |
294 | myABuffer = new char [aLength+1]; |
295 | myABufferLen = aLength; |
296 | } |
297 | sprintf (myABuffer, "%c%s%c%c%d%c", chSpace, aName, |
298 | chEqual, chDoubleQuote, anIntValue, chDoubleQuote); |
60be1f9b |
299 | aLength = (Standard_Integer) strlen (myABuffer); |
7fd59977 |
300 | |
301 | // String attribute value |
302 | } else { |
303 | const char * aValue = aValueStr.GetString(); |
304 | char * encStr; |
305 | if (aValueStr.Type() == LDOMBasicString::LDOM_AsciiDocClear) { |
306 | encStr = (char *) aValue; |
60be1f9b |
307 | aLength = (Standard_Integer) (4 + strlen (aValue) + strlen (aName)); |
7fd59977 |
308 | } else { |
309 | encStr = LDOM_CharReference::Encode (aValue, aLength, Standard_True); |
60be1f9b |
310 | aLength += (Standard_Integer) (4 + strlen (aName)); |
7fd59977 |
311 | } |
312 | if (aLength > myABufferLen) { |
313 | if (myABuffer != NULL) delete [] myABuffer; |
314 | myABuffer = new char [aLength+1]; |
315 | myABufferLen = aLength; |
316 | } |
317 | sprintf (myABuffer, "%c%s%c%c%s%c", chSpace, aName, |
318 | chEqual, chDoubleQuote, encStr, chDoubleQuote); |
319 | if (encStr != aValue) delete [] encStr; |
320 | } |
321 | fwrite ((void *) myABuffer, aLength, 1, myFile); |
322 | } |
323 | |
324 | //======================================================================= |
325 | //function : operator<<() |
326 | //purpose : Stream out a DOM node, and, recursively, all of its children. |
327 | // This function is the heart of writing a DOM tree out as XML source. |
328 | // Give it a document node and it will do the whole thing. |
329 | //======================================================================= |
330 | LDOM_XmlWriter& LDOM_XmlWriter::operator<< (const LDOM_Node& theNodeToWrite) |
331 | { |
332 | // Get the name and value out for convenience |
333 | LDOMString aNodeName = theNodeToWrite.getNodeName(); |
334 | LDOMString aNodeValue = theNodeToWrite.getNodeValue(); |
335 | // unsigned long dwLent = aNodeValue.length(); |
336 | |
337 | switch (theNodeToWrite.getNodeType()) |
338 | { |
339 | case LDOM_Node::TEXT_NODE : |
340 | * this << aNodeValue; |
341 | break; |
342 | case LDOM_Node::ELEMENT_NODE : |
343 | { |
344 | const int aMaxNSpaces = 40; |
345 | static LXMLCh aSpaces [] = { |
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 | chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, |
350 | chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, chSpace, |
351 | chOpenAngle, chNull }; |
352 | const LXMLCh * anIndentString = &aSpaces [aMaxNSpaces - myCurIndent]; |
353 | if (anIndentString < &aSpaces[0]) anIndentString = &aSpaces[0]; |
354 | |
355 | // Output the element start tag. |
356 | * this << anIndentString << aNodeName.GetString(); |
357 | |
358 | // Output any attributes of this element |
359 | const LDOM_Element& anElemToWrite = (const LDOM_Element&) theNodeToWrite; |
360 | LDOM_NodeList aListAtt = anElemToWrite.GetAttributesList (); |
361 | Standard_Integer aListInd = aListAtt.getLength(); |
362 | while (aListInd--) { |
363 | LDOM_Node aChild = aListAtt.item (aListInd); |
364 | WriteAttribute (aChild); |
365 | } |
366 | |
367 | // Test for the presence of children |
368 | LDOM_Node aChild = theNodeToWrite.getFirstChild(); |
369 | if (aChild != 0) |
370 | { |
371 | // There are children. Close start-tag, and output children. |
372 | * this << chCloseAngle; |
373 | if (aChild.getNodeType() == LDOM_Node::ELEMENT_NODE && myIndent > 0) |
374 | * this << chLF; |
375 | Standard_Boolean isChildElem = Standard_False; |
376 | while( aChild != 0) |
377 | { |
378 | isChildElem = (aChild.getNodeType() == LDOM_Node::ELEMENT_NODE); |
379 | if (isChildElem) myCurIndent += myIndent; |
380 | *this << aChild; |
381 | if (isChildElem) myCurIndent -= myIndent; |
382 | do aChild = aChild.getNextSibling(); |
383 | while (aChild.getNodeType() == LDOM_Node::ATTRIBUTE_NODE); |
384 | } |
385 | // Done with children. Output the end tag. |
386 | // |
387 | if (isChildElem) |
388 | * this << anIndentString |
389 | << gEndElement1 << aNodeName.GetString() << chCloseAngle; |
390 | else |
391 | * this << gEndElement << aNodeName.GetString() << chCloseAngle; |
392 | } |
393 | else |
394 | { |
395 | // There were no children. Output the short form close of |
396 | // the element start tag, making it an empty-element tag. |
397 | * this << chForwardSlash << chCloseAngle; |
398 | } |
399 | if (myIndent > 0) |
400 | * this << chLF; |
401 | break; |
402 | } |
403 | case LDOM_Node::CDATA_SECTION_NODE: |
404 | { |
405 | * this << gStartCDATA << aNodeValue << gEndCDATA; |
406 | break; |
407 | } |
408 | case LDOM_Node::COMMENT_NODE: |
409 | { |
410 | * this << gStartComment << aNodeValue << gEndComment; |
411 | break; |
412 | } |
413 | default: |
414 | #ifndef WNT |
415 | cerr << "Unrecognized node type = " |
416 | << (long)theNodeToWrite.getNodeType() << endl |
417 | #endif |
418 | ; } |
419 | return *this; |
420 | } |