0024023: Revamp the OCCT Handle - gcc and clang
[occt.git] / src / LDOM / LDOMParser.cxx
1 // Created on: 2001-07-20
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 //AGV 060302: Input from istream
17 //            AGV 130302: Return error if there are data after the root element
18
19 //#define LDOM_PARSER_TRACE
20
21 #include <LDOMParser.hxx>
22 #include <LDOM_MemManager.hxx>
23 #include <LDOM_XmlReader.hxx>
24 #include <LDOM_BasicText.hxx>
25 #include <LDOM_CharReference.hxx>
26 #include <TCollection_ExtendedString.hxx>
27
28 #include <fcntl.h>
29 #ifdef WNT
30 #include <io.h>
31 #else
32 #include <unistd.h>
33 #endif
34
35 //=======================================================================
36 //function : ~LDOMParser
37 //purpose  : 
38 //=======================================================================
39
40 LDOMParser::~LDOMParser()
41 {
42   if (myReader) delete myReader;
43 }
44
45 //=======================================================================
46 //function : ReadRecord
47 //purpose  : Take the next lexical element from XML stream
48 //=======================================================================
49
50 #ifdef LDOM_PARSER_TRACE
51 static
52 #else
53 inline
54 #endif
55         LDOM_XmlReader::RecordType ReadRecord (LDOM_XmlReader&  aReader,
56                                                LDOM_OSStream&   aData)
57 {
58 #ifdef LDOM_PARSER_TRACE
59   static aCounter = 0;
60   ++ aCounter;
61 #endif
62   const LDOM_XmlReader::RecordType aType = aReader.ReadRecord (aData);
63 #ifdef LDOM_PARSER_TRACE
64   static FILE * ff = NULL;
65   TCollection_AsciiString aTraceFileName;
66 #ifdef WNT
67   aTraceFileName = TCollection_AsciiString (getenv("TEMP")) + "\\ldom.trace";
68 #else
69   aTraceFileName = "/tmp/ldom.trace";
70 #endif
71   ff = fopen (aTraceFileName.ToCString(),ff ? "at": "wt");
72   const char * aDataType;
73   switch (aType) {
74   case LDOM_XmlReader::XML_UNKNOWN:       aDataType= "XML_UNKNOWN      "; break;
75   case LDOM_XmlReader::XML_HEADER:        aDataType= "XML_HEADER       "; break;
76   case LDOM_XmlReader::XML_DOCTYPE:       aDataType= "XML_DOCTYPE      "; break;
77   case LDOM_XmlReader::XML_COMMENT:       aDataType= "XML_COMMENT      "; break;
78   case LDOM_XmlReader::XML_START_ELEMENT: aDataType= "XML_START_ELEMENT"; break;
79   case LDOM_XmlReader::XML_END_ELEMENT:   aDataType= "XML_END_ELEMENT  "; break;
80   case LDOM_XmlReader::XML_FULL_ELEMENT:  aDataType= "XML_FULL_ELEMENT "; break;
81   case LDOM_XmlReader::XML_TEXT:          aDataType= "XML_TEXT         "; break;
82   case LDOM_XmlReader::XML_CDATA:         aDataType= "XML_CDATA        "; break;
83   case LDOM_XmlReader::XML_EOF:           aDataType= "XML_EOF          ";
84   }
85   char * aStr = aData.str();
86   fprintf (ff, "%5d %s: %s\n", aCounter, aDataType, aStr);
87   delete [] aStr;
88   fclose (ff);
89 #endif
90   return aType;
91 }
92
93 //=======================================================================
94 //function : GetError
95 //purpose  : Return text describing a parsing error
96 //=======================================================================
97
98 const TCollection_AsciiString& LDOMParser::GetError
99                                 (TCollection_AsciiString& aData) const
100 {
101   char * aStr =(char *)myCurrentData.str();
102   aData = aStr;
103   delete [] aStr;
104   return myError;
105 }
106
107 //=======================================================================
108 //function : parse
109 //purpose  :
110 //=======================================================================
111
112 Standard_Boolean LDOMParser::parse (istream& anInput)
113 {
114   // Open the DOM Document
115   myDocument = new LDOM_MemManager (20000);
116   myError.Clear();
117
118   // Create the Reader instance
119   if (myReader) delete myReader;
120   myReader = new LDOM_XmlReader (anInput, myDocument, myError);
121
122   // Parse
123   return ParseDocument();
124 }
125
126 //=======================================================================
127 //function : parse
128 //purpose  :
129 //=======================================================================
130
131 Standard_Boolean LDOMParser::parse (const char * const aFileName)
132 {
133   // Open the DOM Document
134   myDocument = new LDOM_MemManager (20000);
135   myError.Clear ();
136
137   // Open the file
138 #ifdef _WIN32
139   TCollection_ExtendedString aFileNameW(aFileName, Standard_True);
140   int aFile = _wopen ((const wchar_t*) aFileNameW.ToExtString(), O_RDONLY);
141 #else
142   int aFile = open (aFileName, O_RDONLY);
143 #endif
144   if (aFile < 0) {
145     myError = "Fatal XML error: Cannot open XML file";
146     return Standard_True;
147   }
148
149   // Create the Reader instance
150   if (myReader) delete myReader;
151   myReader = new LDOM_XmlReader (aFile, myDocument, myError);
152
153   // Parse
154   Standard_Boolean isError = ParseDocument();
155   close (aFile);
156   return isError;
157 }
158
159 //=======================================================================
160 //function : ParseDocument
161 //purpose  : parse the whole document (abstracted from the XML source)
162 //=======================================================================
163
164 Standard_Boolean LDOMParser::ParseDocument ()
165 {
166   Standard_Boolean      isError   = Standard_False;
167   Standard_Boolean      isElement = Standard_False;
168   Standard_Boolean      isDoctype = Standard_False;
169
170   for(;;) {
171     LDOM_XmlReader::RecordType aType = ReadRecord (*myReader, myCurrentData);
172     switch (aType) {
173     case LDOM_XmlReader::XML_HEADER:
174       if (isDoctype || isElement) {
175         myError = "Unexpected XML declaration";
176         isError = Standard_True;
177         break;
178       }
179       continue;
180     case LDOM_XmlReader::XML_DOCTYPE:
181       if (isElement) {
182         myError = "Unexpected DOCTYPE declaration";
183         isError = Standard_True;
184         break;
185       }
186       isDoctype = Standard_True;
187     case LDOM_XmlReader::XML_COMMENT:
188       continue;
189     case LDOM_XmlReader::XML_FULL_ELEMENT:
190       if (isElement == Standard_False) {
191         isElement = Standard_True;
192         myDocument -> myRootElement = &myReader -> GetElement ();
193         if (startElement()) {
194           isError = Standard_True;
195           myError = "User abort at startElement()";
196           break;
197         }
198         if (endElement()) {
199           isError = Standard_True;
200           myError = "User abort at endElement()";
201           break;
202         }
203         continue;
204       }
205     case LDOM_XmlReader::XML_START_ELEMENT:
206       if (isElement == Standard_False) {
207         isElement = Standard_True;
208         myDocument -> myRootElement = &myReader -> GetElement ();
209         if (startElement()) {
210           isError = Standard_True;
211           myError = "User abort at startElement()";
212           break;
213         }
214         isError = ParseElement ();
215         if (isError) break;
216         continue;
217       }
218       isError = Standard_True;
219       myError = "Expected comment or end-of-file";
220     case LDOM_XmlReader::XML_END_ELEMENT:
221       if (endElement()) {
222         isError = Standard_True;
223         myError = "User abort at endElement()";
224       }
225     case LDOM_XmlReader::XML_EOF:
226       break;
227     case LDOM_XmlReader::XML_UNKNOWN:
228       if (isElement) {
229     default:
230         myError = "Unexpected data beyond the Document Element";
231       }
232       isError = Standard_True;
233     }
234     break;
235   }
236   return isError;
237 }
238
239 //=======================================================================
240 //function : ParseElement
241 //purpose  : parse one element, given the type of its XML presentation
242 //=======================================================================
243
244 Standard_Boolean LDOMParser::ParseElement ()
245 {
246   Standard_Boolean  isError = Standard_False;
247   const LDOM_BasicElement * aParent = &myReader->GetElement();
248   const LDOM_BasicNode    * aLastChild = NULL;
249   for(;;) {
250     LDOM_Node::NodeType aLocType;
251     LDOMBasicString     aTextValue;
252     char *aTextStr;
253     LDOM_XmlReader::RecordType aType = ReadRecord (* myReader, myCurrentData);
254     switch (aType) {
255     case LDOM_XmlReader::XML_UNKNOWN:
256       isError = Standard_True;
257       break;
258     case LDOM_XmlReader::XML_FULL_ELEMENT:
259       aParent -> AppendChild (&myReader -> GetElement(), aLastChild);
260       if (startElement()) {
261         isError = Standard_True;
262         myError = "User abort at startElement()";
263         break;
264       }
265       if (endElement()) {
266         isError = Standard_True;
267         myError = "User abort at endElement()";
268         break;
269       }
270       break;
271     case LDOM_XmlReader::XML_START_ELEMENT:
272       aParent -> AppendChild (&myReader -> GetElement(), aLastChild);
273       if (startElement()) {
274         isError = Standard_True;
275         myError = "User abort at startElement()";
276         break;
277       }
278       isError = ParseElement ();
279       break;
280     case LDOM_XmlReader::XML_END_ELEMENT:
281       {
282         Standard_CString aParentName = Standard_CString(aParent->GetTagName());
283         aTextStr = (char *)myCurrentData.str();
284         if (strcmp(aTextStr, aParentName) != 0) {
285           myError = "Expected end tag \'";
286           myError += aParentName;
287           myError += "\'";
288           isError = Standard_True;
289         }
290         else if (endElement()) {
291           isError = Standard_True;
292           myError = "User abort at endElement()";
293         }
294         delete [] aTextStr;
295       }
296       return isError;
297     case LDOM_XmlReader::XML_TEXT:
298       aLocType = LDOM_Node::TEXT_NODE;
299       {
300         Standard_Integer aTextLen;
301         aTextStr = LDOM_CharReference::Decode ((char *)myCurrentData.str(), aTextLen);
302         // try to convert to integer
303         if (IsDigit(aTextStr[0])) {
304           if (LDOM_XmlReader::getInteger (aTextValue, aTextStr,
305                                           aTextStr + aTextLen))
306             aTextValue = LDOMBasicString (aTextStr, aTextLen, myDocument);
307         } else
308           aTextValue = LDOMBasicString (aTextStr, aTextLen, myDocument);
309       }
310       goto create_text_node;
311     case LDOM_XmlReader::XML_COMMENT:
312       aLocType = LDOM_Node::COMMENT_NODE;
313       {
314         Standard_Integer aTextLen;
315         aTextStr = LDOM_CharReference::Decode ((char *)myCurrentData.str(), aTextLen);
316         aTextValue = LDOMBasicString (aTextStr, aTextLen, myDocument);
317       }
318       goto create_text_node;
319     case LDOM_XmlReader::XML_CDATA:
320       aLocType = LDOM_Node::CDATA_SECTION_NODE;
321       aTextStr = (char *)myCurrentData.str();
322       aTextValue = LDOMBasicString(aTextStr,myCurrentData.Length(),myDocument);
323     create_text_node:
324       {
325         LDOM_BasicNode& aTextNode =
326           LDOM_BasicText::Create (aLocType, aTextValue, myDocument);
327         aParent -> AppendChild (&aTextNode, aLastChild);
328       }
329       delete [] aTextStr;
330       break;
331     case LDOM_XmlReader::XML_EOF:
332       myError = "Inexpected end of file";
333       isError = Standard_True;
334       break;
335     default: ;
336     }
337     if (isError) break;
338   }
339   return isError;
340 }
341
342 //=======================================================================
343 //function : startElement
344 //purpose  : virtual hook on 'StartElement' event for descendant classes
345 //=======================================================================
346
347 Standard_Boolean LDOMParser::startElement ()
348 {
349   return Standard_False;
350 }
351
352 //=======================================================================
353 //function : endElement
354 //purpose  : virtual hook on 'EndElement' event for descendant classes
355 //=======================================================================
356
357 Standard_Boolean LDOMParser::endElement ()
358 {
359   return Standard_False;
360 }
361
362 //=======================================================================
363 //function : getCurrentElement
364 //purpose  : 
365 //=======================================================================
366
367 LDOM_Element LDOMParser::getCurrentElement () const
368 {
369   return LDOM_Element (myReader -> GetElement(), myDocument);
370 }
371
372 //=======================================================================
373 //function : getDocument
374 //purpose  : 
375 //=======================================================================
376
377 LDOM_Document LDOMParser::getDocument ()
378 {
379   return myDocument -> Self();
380 }
381