0026229: Add the possibility in OCAF to open/save a document from/to a stream object
[occt.git] / src / LDOM / LDOMParser.cxx
CommitLineData
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
41LDOMParser::~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
52static
53#else
54inline
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
100const 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
114Standard_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
133Standard_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 154Standard_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 234Standard_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
337Standard_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
347Standard_Boolean LDOMParser::endElement ()
348{
349 return Standard_False;
350}
351
352//=======================================================================
353//function : getCurrentElement
354//purpose :
355//=======================================================================
356
357LDOM_Element LDOMParser::getCurrentElement () const
358{
359 return LDOM_Element (myReader -> GetElement(), myDocument);
360}
361
362//=======================================================================
363//function : getDocument
364//purpose :
365//=======================================================================
366
367LDOM_Document LDOMParser::getDocument ()
368{
369 return myDocument -> Self();
370}
371