0023326: The 'aSibling' pointer was utilized before it was verified against nullptr...
[occt.git] / src / LDOM / LDOMParser.cxx
CommitLineData
b311480e 1// Created on: 2001-07-20
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
20//AGV 060302: Input from istream
7fd59977 21// AGV 130302: Return error if there are data after the root element
22
23//#define LDOM_PARSER_TRACE
24
25#include <LDOMParser.hxx>
26#include <LDOM_MemManager.hxx>
27#include <LDOM_XmlReader.hxx>
28#include <LDOM_BasicText.hxx>
29#include <LDOM_CharReference.hxx>
30
31#include <fcntl.h>
32#ifdef WNT
33#include <io.h>
34#else
35#include <unistd.h>
36#endif
37
38//=======================================================================
39//function : ~LDOMParser
40//purpose :
41//=======================================================================
42
43LDOMParser::~LDOMParser()
44{
45 if (myReader) delete myReader;
46}
47
48//=======================================================================
49//function : ReadRecord
50//purpose : Take the next lexical element from XML stream
51//=======================================================================
52
53#ifdef LDOM_PARSER_TRACE
54static
55#else
56inline
57#endif
58 LDOM_XmlReader::RecordType ReadRecord (LDOM_XmlReader& aReader,
59 LDOM_OSStream& aData)
60{
61#ifdef LDOM_PARSER_TRACE
62 static aCounter = 0;
63 ++ aCounter;
64#endif
65 const LDOM_XmlReader::RecordType aType = aReader.ReadRecord (aData);
66#ifdef LDOM_PARSER_TRACE
67 static FILE * ff = NULL;
68 TCollection_AsciiString aTraceFileName;
69#ifdef WNT
70 aTraceFileName = TCollection_AsciiString (getenv("TEMP")) + "\\ldom.trace";
71#else
72 aTraceFileName = "/tmp/ldom.trace";
73#endif
74 ff = fopen (aTraceFileName.ToCString(),ff ? "at": "wt");
75 const char * aDataType;
76 switch (aType) {
77 case LDOM_XmlReader::XML_UNKNOWN: aDataType= "XML_UNKNOWN "; break;
78 case LDOM_XmlReader::XML_HEADER: aDataType= "XML_HEADER "; break;
79 case LDOM_XmlReader::XML_DOCTYPE: aDataType= "XML_DOCTYPE "; break;
80 case LDOM_XmlReader::XML_COMMENT: aDataType= "XML_COMMENT "; break;
81 case LDOM_XmlReader::XML_START_ELEMENT: aDataType= "XML_START_ELEMENT"; break;
82 case LDOM_XmlReader::XML_END_ELEMENT: aDataType= "XML_END_ELEMENT "; break;
83 case LDOM_XmlReader::XML_FULL_ELEMENT: aDataType= "XML_FULL_ELEMENT "; break;
84 case LDOM_XmlReader::XML_TEXT: aDataType= "XML_TEXT "; break;
85 case LDOM_XmlReader::XML_CDATA: aDataType= "XML_CDATA "; break;
86 case LDOM_XmlReader::XML_EOF: aDataType= "XML_EOF ";
87 }
88 char * aStr = aData.str();
89 fprintf (ff, "%5d %s: %s\n", aCounter, aDataType, aStr);
90 delete [] aStr;
91 fclose (ff);
92#endif
93 return aType;
94}
95
96//=======================================================================
97//function : GetError
98//purpose : Return text describing a parsing error
99//=======================================================================
100
101const TCollection_AsciiString& LDOMParser::GetError
102 (TCollection_AsciiString& aData) const
103{
104 char * aStr =(char *)myCurrentData.str();
105 aData = aStr;
106 delete [] aStr;
107 return myError;
108}
109
110//=======================================================================
111//function : parse
112//purpose :
113//=======================================================================
114
115Standard_Boolean LDOMParser::parse (istream& anInput)
116{
117 // Open the DOM Document
118 myDocument = new LDOM_MemManager (20000);
119 myError.Clear();
120
121 // Create the Reader instance
122 if (myReader) delete myReader;
123 myReader = new LDOM_XmlReader (anInput, myDocument, myError);
124
125 // Parse
126 return ParseDocument();
127}
128
129//=======================================================================
130//function : parse
131//purpose :
132//=======================================================================
133
134Standard_Boolean LDOMParser::parse (const char * const aFileName)
135{
136 // Open the DOM Document
137 myDocument = new LDOM_MemManager (20000);
138 myError.Clear ();
139
140 // Open the file
141 int aFile = open (aFileName, O_RDONLY);
142 if (aFile < 0) {
143 myError = "Fatal XML error: Cannot open XML file";
144 return Standard_True;
145 }
146
147 // Create the Reader instance
148 if (myReader) delete myReader;
149 myReader = new LDOM_XmlReader (aFile, myDocument, myError);
150
151 // Parse
152 Standard_Boolean isError = ParseDocument();
153 close (aFile);
154 return isError;
155}
156
157//=======================================================================
158//function : ParseDocument
159//purpose : parse the whole document (abstracted from the XML source)
160//=======================================================================
161
162Standard_Boolean LDOMParser::ParseDocument ()
163{
164 Standard_Boolean isError = Standard_False;
165 Standard_Boolean isElement = Standard_False;
166 Standard_Boolean isHeader = Standard_False;
167 Standard_Boolean isDoctype = Standard_False;
168
169 while (1) {
170 LDOM_XmlReader::RecordType aType = ReadRecord (*myReader, myCurrentData);
171 switch (aType) {
172 case LDOM_XmlReader::XML_HEADER:
173 if (isDoctype || isElement) {
174 myError = "Unexpected XML declaration";
175 isError = Standard_True;
176 break;
177 }
178 isHeader = Standard_True;
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
244Standard_Boolean LDOMParser::ParseElement ()
245{
246 Standard_Boolean isError = Standard_False;
247 const LDOM_BasicElement * aParent = &myReader->GetElement();
248 const LDOM_BasicNode * aLastChild = NULL;
249 while (1) {
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
347Standard_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
357Standard_Boolean LDOMParser::endElement ()
358{
359 return Standard_False;
360}
361
362//=======================================================================
363//function : getCurrentElement
364//purpose :
365//=======================================================================
366
367LDOM_Element LDOMParser::getCurrentElement () const
368{
369 return LDOM_Element (myReader -> GetElement(), myDocument);
370}
371
372//=======================================================================
373//function : getDocument
374//purpose :
375//=======================================================================
376
377LDOM_Document LDOMParser::getDocument ()
378{
379 return myDocument -> Self();
380}
381