0024002: Overall code and build procedure refactoring -- automatic
[occt.git] / src / LDOM / LDOM_XmlWriter.cxx
CommitLineData
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
96static const LXMLCh gEndElement[] = { chOpenAngle, chForwardSlash, chNull };
97static const LXMLCh gEndElement1[]= { chForwardSlash, chNull };
f24125b9 98//static const LXMLCh gEndPI[] = { chQuestion, chCloseAngle, chNull };
99//static const LXMLCh gStartPI[] = { chOpenAngle, chQuestion, chNull };
7fd59977 100static 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};
105static 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 111static 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 117static const LXMLCh gXMLDecl4[] =
118{ chDoubleQuote, chQuestion, chCloseAngle
119 , chLF, chNull
120};
121static const LXMLCh gStartCDATA[] =
122{ chOpenAngle, chBang, chOpenSquare, chLatin_C, chLatin_D,
123 chLatin_A, chLatin_T, chLatin_A, chOpenSquare, chNull
124};
125static const LXMLCh gEndCDATA[] =
126{ chCloseSquare, chCloseSquare, chCloseAngle, chNull };
127static const LXMLCh gStartComment[] =
128{ chOpenAngle, chBang, chDash, chDash, chNull };
129static const LXMLCh gEndComment[] =
130{ chDash, chDash, chCloseAngle, chNull };
f24125b9 131/*
7fd59977 132static const LXMLCh gStartDoctype[] =
133{ chOpenAngle, chBang, chLatin_D, chLatin_O, chLatin_C, chLatin_T,
134 chLatin_Y, chLatin_P, chLatin_E, chSpace, chNull
135};
136static const LXMLCh gPublic[] =
137{ chLatin_P, chLatin_U, chLatin_B, chLatin_L, chLatin_I,
138 chLatin_C, chSpace, chDoubleQuote, chNull
139};
140static const LXMLCh gSystem[] =
141{ chLatin_S, chLatin_Y, chLatin_S, chLatin_T, chLatin_E,
142 chLatin_M, chSpace, chDoubleQuote, chNull
143};
144static const LXMLCh gStartEntity[] =
145{ chOpenAngle, chBang, chLatin_E, chLatin_N, chLatin_T, chLatin_I,
146 chLatin_T, chLatin_Y, chSpace, chNull
147};
148static const LXMLCh gNotation[] =
149{ chLatin_N, chLatin_D, chLatin_A, chLatin_T, chLatin_A,
150 chSpace, chDoubleQuote, chNull
151};
f24125b9 152*/
7fd59977 153
154static 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//=======================================================================
177LDOM_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
192LDOM_XmlWriter::~LDOM_XmlWriter ()
193{
194 delete [] myEncodingName;
195 if (myABuffer != NULL) delete [] myABuffer;
196}
197
198//=======================================================================
199//function : operator <<
200//purpose :
201//=======================================================================
202
203LDOM_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
217inline 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//=======================================================================
258inline 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//=======================================================================
269inline 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//=======================================================================
279void 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//=======================================================================
328LDOM_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:
412#ifndef WNT
413 cerr << "Unrecognized node type = "
414 << (long)theNodeToWrite.getNodeType() << endl
415#endif
416 ; }
417 return *this;
418}