0031642: Visualization - crash in Graphic3d_Structure::SetVisual() on redisplaying...
[occt.git] / src / LDOM / LDOM_XmlWriter.cxx
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
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 //=======================================================================
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 //=======================================================================
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 //=======================================================================
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 //=======================================================================
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 //=======================================================================
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 //=======================================================================
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 //=======================================================================
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 //=======================================================================
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 }