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