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 | |
43 | LDOMParser::~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 |
54 | static |
55 | #else |
56 | inline |
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 | |
101 | const 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 | |
115 | Standard_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 | |
134 | Standard_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 | |
162 | Standard_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 | |
302f96fb |
169 | for(;;) { |
7fd59977 |
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 | |
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 | |