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