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 | // |
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. |
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> |
d9ff84e8 |
26 | #include <TCollection_ExtendedString.hxx> |
7fd59977 |
27 | |
28 | #include <fcntl.h> |
57c28b61 |
29 | #ifdef _MSC_VER |
7fd59977 |
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; |
57c28b61 |
66 | #ifdef _WIN32 |
7fd59977 |
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 |
d9ff84e8 |
138 | #ifdef _WIN32 |
139 | TCollection_ExtendedString aFileNameW(aFileName, Standard_True); |
140 | int aFile = _wopen ((const wchar_t*) aFileNameW.ToExtString(), O_RDONLY); |
141 | #else |
7fd59977 |
142 | int aFile = open (aFileName, O_RDONLY); |
d9ff84e8 |
143 | #endif |
7fd59977 |
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; |
7fd59977 |
168 | Standard_Boolean isDoctype = Standard_False; |
169 | |
302f96fb |
170 | for(;;) { |
7fd59977 |
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 | } |
7fd59977 |
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; |
302f96fb |
249 | for(;;) { |
7fd59977 |
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 | |