0031340: LDOM fails to read XML file starting with BOM
[occt.git] / src / LDOM / LDOM_XmlReader.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
04232180 16//AGV 060302: Input from std::istream
7fd59977 17// AGV 130302: bug corr: was error if strlen(root_elem_name) < 7
18
19#include <LDOM_XmlReader.hxx>
20#include <Standard_Stream.hxx>
21#include <LDOM_MemManager.hxx>
22#include <LDOM_BasicAttribute.hxx>
23#include <LDOM_CharReference.hxx>
24#include <LDOM_OSStream.hxx>
25
26#include <string.h>
27#include <errno.h>
57c28b61 28#ifdef _MSC_VER
7fd59977 29#include <io.h>
30#else
31#include <unistd.h>
32#endif
33
34//#include <ctype.h>
35
36const int XML_MIN_BUFFER = 10;
7fd59977 37
38typedef enum {
39 STATE_WAITING = 0,
40 STATE_HEADER,
41 STATE_DOCTYPE,
42 STATE_DOCTYPE_MARKUP,
43 STATE_ELEMENT,
44 STATE_ELEMENT_END,
45 STATE_ATTRIBUTE_NAME,
46 STATE_ATTRIBUTE_EQUAL,
47 STATE_ATTRIBUTE_VALUE,
48 STATE_COMMENT,
49 STATE_CDATA,
50 STATE_TEXT
51} ParserState;
52
53#define TEXT_COMPARE(aPtr,aPattern) \
54 (memcmp ((aPtr), (aPattern), sizeof(aPattern) - 1) == 0)
55
56static Standard_Boolean isName (const char * aString,
57 const char * aStringEnd,
58 const char *& aNameEnd);
59
60//=======================================================================
61//function : LDOM_XmlReader()
62//purpose : Constructor (file descriptor)
63//=======================================================================
64
4ff92abe 65LDOM_XmlReader::LDOM_XmlReader (
cbff1e55 66 const Handle(LDOM_MemManager)& theDocument,
5fce1605 67 TCollection_AsciiString& theErrorString,
68 const Standard_Boolean theTagPerStep)
cbff1e55 69: myEOF (Standard_False),
cbff1e55 70 myError (theErrorString),
71 myDocument (theDocument),
72 myElement (NULL),
73 myLastChild(NULL),
74 myPtr (&myBuffer[0]),
5fce1605 75 myEndPtr (&myBuffer[0]),
8f34d47e 76 myTagPerStep (theTagPerStep),
77 myBOM (LDOM_OSStream::BOM_UNDEFINED)
cbff1e55 78{
79}
7fd59977 80
81//=======================================================================
82//function : ReadRecord
83//purpose : Read a record from XML file
84//=======================================================================
85
4ff92abe 86LDOM_XmlReader::RecordType LDOM_XmlReader::ReadRecord (Standard_IStream& theIStream,
87 LDOM_OSStream& theData)
7fd59977 88{
89 theData.Clear();
90 myError.Clear();
91 ParserState aState = STATE_WAITING;
1d47d8d0 92 const char * aStartData = NULL, * aNameEnd = NULL, * aPtr;
7fd59977 93 LDOMBasicString anAttrName, anAttrValue;
94 char anAttDelimiter = '\0';
5fce1605 95 Standard_Boolean aHasRead = Standard_False;
8f34d47e 96 Standard_Boolean isFileStart = !myEOF && theIStream.tellg() == std::iostream::pos_type(0);
7fd59977 97
302f96fb 98 for(;;) {
7fd59977 99 // Check if the current file buffer is exhausted
100 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
101 // There should always be some bytes available in the buffer for analysis
7dc9e047 102 Standard_Integer aBytesRest = (Standard_Integer)(myEndPtr - myPtr);
5fce1605 103 if (aBytesRest < XML_MIN_BUFFER)
104 {
105 if (myEOF == Standard_True)
106 {
7fd59977 107 if (aBytesRest <= 0)
108 break; // END of processing
5fce1605 109 }
110 else if (myTagPerStep && aHasRead)
111 {
18151f1a 112 // in myTagPerStep mode, we should parse the buffer to the end before
113 // getting more characters from the stream.
5fce1605 114 }
115 else
116 {
3358ed64 117 // If we are reading some data, save the beginning and preserve the state
7fd59977 118 if (aStartData /* && aState != STATE_WAITING */) {
119 if (myPtr > aStartData)
120 theData.rdbuf()->sputn(aStartData, myPtr - aStartData);
121 aStartData = &myBuffer[0];
122 }
3358ed64 123 // Copy the rest of file data to the beginning of buffer
7fd59977 124 if (aBytesRest > 0)
3358ed64 125 {
126 // do not use memcpy here because aBytesRest may be greater than myPtr-myBuffer, so, overlap
127 memmove (&myBuffer[0], myPtr, aBytesRest);
128 }
7fd59977 129
3358ed64 130 // Read the full buffer and reset start and end buffer pointers
7fd59977 131 myPtr = &myBuffer[0];
60be1f9b 132 Standard_Size aNBytes;
5fce1605 133
134 if (myTagPerStep)
135 {
136 theIStream.getline (&myBuffer[aBytesRest], XML_BUFFER_SIZE - aBytesRest, '>');
137 aHasRead = Standard_True;
138 }
139 else
140 {
141 theIStream.read (&myBuffer[aBytesRest], XML_BUFFER_SIZE - aBytesRest);
142 }
143 aNBytes = (Standard_Size)theIStream.gcount();
144
7fd59977 145 if (aNBytes == 0)
5fce1605 146 {
7fd59977 147 myEOF = Standard_True; // END-OF-FILE
5fce1605 148 }
149 else if (myTagPerStep)
150 {
151 // replace \0 (being inserted by getline method) with >
152 myBuffer[aBytesRest + aNBytes - 1] = '>';
153 }
7fd59977 154 myEndPtr = &myBuffer[aBytesRest + aNBytes];
155 myBuffer[aBytesRest + aNBytes] = '\0';
156 }
157 }
8f34d47e 158 if (isFileStart)
159 {
160 isFileStart = Standard_False;
161 // check for BOM block
162 Standard_Utf8UChar aFirstChar = Standard_Utf8UChar(myPtr[0]);
163 switch(aFirstChar) {
164 case 0xEF:
165 if (Standard_Utf8UChar(myPtr[1]) == 0xBB && Standard_Utf8UChar(myPtr[2]) == 0xBF)
166 {
167 myBOM = LDOM_OSStream::BOM_UTF8;
168 myPtr += 3;
169 }
170 break;
171 case 0xFE:
172 if (Standard_Utf8UChar(myPtr[1]) == 0xFF)
173 {
174 myBOM = LDOM_OSStream::BOM_UTF16BE;
175 myPtr += 2;
176 }
177 break;
178 case 0xFF:
179 if (Standard_Utf8UChar(myPtr[1]) == 0xFE)
180 {
181 if (myPtr[2] == 0 && myPtr[3] == 0)
182 {
183 myBOM = LDOM_OSStream::BOM_UTF32LE;
184 myPtr += 4;
185 }
186 else
187 {
188 myBOM = LDOM_OSStream::BOM_UTF16LE;
189 myPtr += 2;
190 }
191 }
192 break;
193 case 0x00:
194 if (myPtr[1] == 0 && Standard_Utf8UChar(myPtr[2]) == 0xFE && Standard_Utf8UChar(myPtr[3]) == 0xFF)
195 {
196 myBOM = LDOM_OSStream::BOM_UTF32BE;
197 myPtr += 4;
198 }
199 break;
200 case 0x2B:
201 if (myPtr[1] == 47 && myPtr[2] == 118 &&
202 (myPtr[3] == 43 || myPtr[3] == 47 || myPtr[3] == 56 || myPtr[3] == 57))
203 {
204 myBOM = LDOM_OSStream::BOM_UTF7;
205 if (myPtr[3] == 56 && myPtr[3] == 45)
206 myPtr += 5;
207 else
208 myPtr += 4;
209 }
210 break;
211 case 0xF7:
212 if (myPtr[1] == 100 && myPtr[2] == 76)
213 {
214 myBOM = LDOM_OSStream::BOM_UTF1;
215 myPtr += 3;
216 }
217 break;
218 case 0xDD:
219 if (myPtr[1] == 115 && myPtr[2] == 102 && myPtr[3] == 115)
220 {
221 myBOM = LDOM_OSStream::BOM_UTFEBCDIC;
222 myPtr += 4;
223 }
224 break;
225 case 0x0E:
226 if (Standard_Utf8UChar(myPtr[1]) == 0xFE && Standard_Utf8UChar(myPtr[2]) == 0xFF)
227 {
228 myBOM = LDOM_OSStream::BOM_SCSU;
229 myPtr += 3;
230 }
231 break;
232 case 0xFB:
233 if (Standard_Utf8UChar(myPtr[1]) == 0xEE && myPtr[2] == 40)
234 {
235 myBOM = LDOM_OSStream::BOM_BOCU1;
236 myPtr += 3;
237 }
238 break;
239 case 0x84:
240 if (myPtr[1] == 49 && Standard_Utf8UChar(myPtr[2]) == 0x95 && myPtr[3] == 51)
241 {
242 myBOM = LDOM_OSStream::BOM_GB18030;
243 myPtr += 4;
244 }
245 break;
246 }
247 if (myBOM != LDOM_OSStream::BOM_UNDEFINED)
248 continue;
249 }
7fd59977 250
251 // Check the character data
252 switch (aState) {
253
254 // Checking the characters in STATE_WAITING (blank, TEXT or markup)
255 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
256 case STATE_WAITING:
257 switch (myPtr[0]) {
258 case ' ':
259 case '\t':
260 case '\n':
261 case '\r':
262 ++ myPtr;
263 continue;
264 case '<':
265 // XML markup found, then make detect the record type
266 switch (myPtr[1]) {
267 case '?':
268 aState = STATE_HEADER;
269 myPtr += 2;
270 aStartData = myPtr;
271 continue;
272 case '/':
273 aState = STATE_ELEMENT_END;
274 myPtr += 2;
275 aStartData = myPtr;
276 continue;
277 case '!':
278 if (myPtr[2] == '-' && myPtr[3] == '-') {
279 aState = STATE_COMMENT;
280 myPtr += 4;
281 } else if (TEXT_COMPARE (&myPtr[2], "DOCTYPE")) {
282 char ch = myPtr[9];
283 if (ch != ' ' && ch != '\t' && ch != '\n' && ch != '\r')
284 break;
285 aState = STATE_DOCTYPE;
286 myPtr += 10;
287 } else if (TEXT_COMPARE (&myPtr[2], "[CDATA[")) {
288 aState = STATE_CDATA;
289 myPtr += 9;
290 } else break; // ERROR
291 aStartData = myPtr;
292 continue;
293 default:
294 if (::isName (&myPtr[1], myEndPtr, aNameEnd)) {
295 aStartData = myPtr + 1;
296 myPtr = aNameEnd;
297 if (myPtr < myEndPtr) {
298 myElement = & LDOM_BasicElement::Create (aStartData,
7dc9e047 299 (Standard_Integer)(myPtr - aStartData),
7fd59977 300 myDocument);
301 myLastChild = NULL;
302 aState = STATE_ATTRIBUTE_NAME;
303 aStartData = NULL;
304 }else
305 aState = STATE_ELEMENT;
306 continue;
307 } // otherwise ERROR
308 } // end of switch
309 myError = "Unknown XML object: ";
a738b534 310 myError += TCollection_AsciiString (myPtr, XML_MIN_BUFFER);
7fd59977 311 return XML_UNKNOWN;
312 case '\0':
313 if (myEOF == Standard_True) continue;
b1811c1d 314 Standard_FALLTHROUGH
7fd59977 315 default:
316 // Limitation: we do not treat '&' as special character
317 aPtr = (const char *) memchr (myPtr, '<', myEndPtr - myPtr);
318 if (aPtr) {
319 // The end of text field reached
320 theData.rdbuf()->sputn(myPtr, aPtr - myPtr);
321 myPtr = aPtr;
322 return XML_TEXT;
323 }
324 aState = STATE_TEXT;
325 aStartData = myPtr;
326 myPtr = myEndPtr;
18151f1a 327 aHasRead = Standard_False;
7fd59977 328 } // end of checking in STATE_WAITING
329 continue;
330
331 // Checking the characters in STATE_HEADER, seek for "?>" sequence
332 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
333 case STATE_HEADER:
334 aPtr = (const char *) memchr (aStartData, '?', (myEndPtr-1) - aStartData);
335 if (aPtr) {
336 // The end of XML declaration found
337 if (aPtr[1] != '>') { // ERROR
338 myError = "Character \'>\' is expected in the end of XML declaration";
339 return XML_UNKNOWN;
340 }
341 // The XML declaration is retrieved
342 theData.rdbuf()->sputn(aStartData, aPtr - aStartData);
343 myPtr = aPtr + 2;
344 return XML_HEADER;
345 }
346 myPtr = myEndPtr - 1;
18151f1a 347 aHasRead = Standard_False;
7fd59977 348 continue;
349
350 // Checking the characters in STATE_DOCTYPE, seek for "]>" sequence
351 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
352 case STATE_DOCTYPE:
353 for (aPtr = aStartData; aPtr < myEndPtr-1; aPtr++) {
354 const int aChar = aPtr[0];
355 if (aChar == '[') {
356 aState = STATE_DOCTYPE_MARKUP;
357 aStartData = &aPtr[1];
358 goto state_doctype_markup;
359 }
360 if (aChar == '>') {
361 // The DOCTYPE declaration is retrieved
362 theData.rdbuf()->sputn(aStartData, aPtr - aStartData - 1);
363 myPtr = aPtr + 1;
364 return XML_DOCTYPE;
365 }
366 }
367 myPtr = myEndPtr - 1;
18151f1a 368 aHasRead = Standard_False;
7fd59977 369 continue;
370
371 state_doctype_markup:
372 case STATE_DOCTYPE_MARKUP:
373 aPtr = (const char *) memchr (aStartData, ']', (myEndPtr-1) - aStartData);
374 if (aPtr) {
375 // The end of DOCTYPE declaration found
376 if (aPtr[1] != '>') { // ERROR
377 myError =
378 "Character \'>\' is expected in the end of DOCTYPE declaration";
379 return XML_UNKNOWN;
380 }
381 // The DOCTYPE declaration is retrieved
382 theData.rdbuf()->sputn(aStartData, aPtr - aStartData);
383 myPtr = aPtr + 2;
384 return XML_DOCTYPE;
385 }
386 myPtr = myEndPtr - 1;
18151f1a 387 aHasRead = Standard_False;
7fd59977 388 continue;
389
390 // Checking the characters in STATE_COMMENT, seek for "-->" sequence
391 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
392 case STATE_COMMENT:
393 aPtr = aStartData;
302f96fb 394 for(;;) {
7fd59977 395 aPtr = (const char *) memchr (aPtr, '-', (myEndPtr - 2) - aPtr);
396 if (aPtr == NULL) break;
397 if (aPtr[1] != '-') ++ aPtr;
398 else {
399 if (aPtr[2] != '>') { // ERROR
400 myError = "Character \'>\' is expected in the end of comment";
401 return XML_UNKNOWN;
402 }
403 theData.rdbuf()->sputn(aStartData, aPtr - aStartData);
404 myPtr = aPtr + 3;
405 return XML_COMMENT;
406 }
407 }
408 myPtr = myEndPtr - 2;
18151f1a 409 aHasRead = Standard_False;
7fd59977 410 continue;
411
412 // Checking the characters in STATE_TEXT, seek for "<"
413 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
414 case STATE_TEXT:
415 aPtr = (const char *) memchr (aStartData, '<', myEndPtr - aStartData);
416 if (aPtr) {
417 // The end of text field reached
418 theData.rdbuf()->sputn(aStartData, aPtr - aStartData);
419 myPtr = aPtr;
420 return XML_TEXT;
421 }
422 myPtr = myEndPtr;
18151f1a 423 aHasRead = Standard_False;
7fd59977 424 continue;
425
426 // Checking the characters in STATE_CDATA, seek for "]]"
427 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
428 case STATE_CDATA:
429 aPtr = aStartData;
302f96fb 430 for(;;) {
7fd59977 431 aPtr = (const char *) memchr (aPtr, ']', (myEndPtr - 1) - aStartData);
432 if (aPtr == NULL) break;
433 if (aPtr[1] != ']') { // ERROR
434 myError = "Characters \']]\' are expected in the end of CDATA";
435 return XML_UNKNOWN;
436 }
437 theData.rdbuf()->sputn(aStartData, aPtr - aStartData);
438 myPtr = aPtr + 2;
439 return XML_CDATA;
440 }
441 myPtr = myEndPtr - 1;
18151f1a 442 aHasRead = Standard_False;
7fd59977 443 continue;
444
445 // Checking the characters in STATE_ELEMENT, seek the end of TagName
446 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
447 case STATE_ELEMENT:
448 if (::isName (myPtr, myEndPtr, aNameEnd) == Standard_False)
449 if (theData.Length() == 0 || aNameEnd != myPtr) {
450 myError = "Invalid tag name";
451 return XML_UNKNOWN;
452 }
453 {
454 theData.rdbuf()->sputn(aStartData, aNameEnd - aStartData);
455 char* aDataString = (char *)theData.str();
456 myElement = & LDOM_BasicElement::Create (aDataString, theData.Length(),
457 myDocument);
458 theData.Clear();
459 myLastChild = NULL;
460 delete [] aDataString;
461 aState = STATE_ATTRIBUTE_NAME;
462 aStartData = NULL;
463 myPtr = aNameEnd;
464 continue;
465 }
466 // Parsing a single attribute (STATE_ATTRIBUTE)
467 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
468 case STATE_ATTRIBUTE_NAME: // attribute name
469 switch (myPtr[0]) {
470 case ' ' :
471 case '\t':
472 case '\n':
473 case '\r':
474 if (aStartData) goto attr_name;
475 ++ myPtr;
476 continue;
477 case '/' :
478 if (aStartData)
479 myError = "Inexpected end of attribute";
480 else if (myPtr[1] != '>')
481 myError = "Improper element tag termination";
482 else {
483 myPtr += 2;
0797d9d3 484#ifdef OCCT_DEBUG
7fd59977 485 theData.Clear();
486 theData << myElement->GetTagName();
487#endif
488 return XML_FULL_ELEMENT;
489 }
490 return XML_UNKNOWN;
491 case '>' :
492 if (aStartData) {
493 myError = "Inexpected end of attribute";
494 return XML_UNKNOWN;
495 }
496 ++ myPtr;
0797d9d3 497#ifdef OCCT_DEBUG
7fd59977 498 theData.Clear();
499 theData << myElement->GetTagName();
500#endif
501 return XML_START_ELEMENT;
502 default :
503 if (::isName (myPtr, myEndPtr, aNameEnd) == Standard_False)
504 if (theData.Length() == 0 || aNameEnd != myPtr) {
505 myError = "Invalid attribute name";
506 return XML_UNKNOWN;
507 }
508 if (aNameEnd >= myEndPtr)
509 aStartData = myPtr;
510 else {
511 if (theData.Length() == 0)
7dc9e047 512 anAttrName = LDOMBasicString(myPtr, (Standard_Integer)(aNameEnd - myPtr), myDocument);
7fd59977 513 else {
514 theData.rdbuf()->sputn(myPtr, aNameEnd - myPtr);
515attr_name:
516 char* aDataString = (char *)theData.str();
517 theData.Clear();
518 anAttrName = LDOMBasicString (aDataString, myDocument);
519 delete [] aDataString;
520 }
521 aStartData = NULL;
522 aState = STATE_ATTRIBUTE_EQUAL;
523 }
524 myPtr = aNameEnd;
525 continue;
526 }
527 case STATE_ATTRIBUTE_EQUAL: // attribute 'equal' sign
528 switch (myPtr[0]) {
529 case '=' :
530 aState = STATE_ATTRIBUTE_VALUE;
b1811c1d 531 Standard_FALLTHROUGH
7fd59977 532 case ' ' :
533 case '\t':
534 case '\n':
535 case '\r':
536 ++ myPtr;
537 continue;
538 default:
539 myError = "Equal sign expected in attribute definition";
540 return XML_UNKNOWN;
541 }
542
543 case STATE_ATTRIBUTE_VALUE: // attribute value
544 switch (myPtr[0]) {
545 case ' ' :
546 case '\t':
547 case '\n':
548 case '\r':
549 if (aStartData == NULL) {
550 ++ myPtr;
551 continue;
552 default:
553 if (anAttDelimiter == '\0') {
554 myError = "Expected an attribute value";
555 return XML_UNKNOWN;
556 case '\"':
557 case '\'':
558 if (aStartData == NULL) {
559 aStartData = &myPtr[1];
560 anAttDelimiter = myPtr[0];
561 }
562 }
563 }
564 // Limitation: we do not take into account that '<' and '&'
565 // are not allowed in attribute values
566 aPtr = (const char *) memchr (aStartData, anAttDelimiter,
567 myEndPtr - aStartData);
568 if (aPtr) {
569 (char&) aPtr[0] = '\0';
570 anAttDelimiter = '\0';
571 char * aDataString = (char *) aStartData;
572 const char * ePtr = aPtr;
573
574 // Append the end of the string to previously taken data
575 if (theData.Length() > 0) {
576 theData.rdbuf()->sputn(aStartData, aPtr-aStartData);
577 aDataString = (char *)theData.str();
578 ePtr = strchr (aDataString, '\0');
579 }
580
581 Standard_Integer aDataLen;
582 aDataString = LDOM_CharReference::Decode (aDataString, aDataLen);
583 if (IsDigit(aDataString[0])) {
584 if (getInteger (anAttrValue, aDataString, ePtr))
585 anAttrValue = LDOMBasicString (aDataString,aDataLen,myDocument);
586 } else
587 anAttrValue = LDOMBasicString (aDataString, aDataLen, myDocument);
588
589 if (theData.Length() > 0) {
590 theData.Clear();
591 delete [] aDataString;
592 }
593 // Create an attribute
594 myLastChild = myElement -> AddAttribute (anAttrName, anAttrValue,
595 myDocument, myLastChild);
596 myPtr = aPtr + 1;
597 aStartData = NULL;
598 aState = STATE_ATTRIBUTE_NAME;
18151f1a 599 }
600 else {
7fd59977 601 myPtr = myEndPtr;
18151f1a 602 aHasRead = Standard_False;
603 }
7fd59977 604 continue;
605 }
606 // Checking the characters in STATE_ELEMENT_END, seek for ">"
607 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
608 case STATE_ELEMENT_END:
609 aPtr = (const char *) memchr (aStartData, '>', myEndPtr - aStartData);
610 if (aPtr) {
611 // The end of the end-element markup
612 theData.rdbuf()->sputn(aStartData, aPtr - aStartData);
613 myPtr = aPtr + 1;
614 return XML_END_ELEMENT;
615 }
616 myPtr = myEndPtr;
18151f1a 617 aHasRead = Standard_False;
7fd59977 618 continue;
619 }
620 }
621 if (aState != STATE_WAITING) {
622 myError = "Unexpected end of file";
623 return XML_UNKNOWN;
624 }
625 return XML_EOF;
626}
627
628//=======================================================================
629//function : isName
630//type : static
631//purpose : Check if aString is a valid XML Name
632//=======================================================================
633
634static Standard_Boolean isName (const char * aString,
635 const char * aStringEnd,
636 const char *& aNameEnd)
637{
638 Standard_Boolean aResult;
302f96fb 639 char aCh = aString[0];
7fd59977 640 if (IsAlphabetic(aCh) || aCh == '_' || aCh == ':') {
641 const char * aPtr = &aString[1];
642 while (aPtr < aStringEnd) {
643 aCh = * aPtr;
644 switch (aCh) {
645 case ' ' :
646 case '\n':
647 case '\r':
648 case '\t':
649 case '=' :
650 case '\0':
651 case '/' :
652 case '>' :
653 aNameEnd = aPtr;
654 return Standard_True;
655 default:
656 if (IsAlphanumeric(aCh) == 0) {
657 aNameEnd = aPtr;
658 return Standard_False;
659 }
b1811c1d 660 Standard_FALLTHROUGH
7fd59977 661 case '.' :
662 case '-' :
663 case '_' :
664 case ':' :
665 ++ aPtr;
666 }
667 }
668 aNameEnd = aPtr;
669 aResult = Standard_True;
670 } else {
671 aNameEnd = aString;
672 aResult = Standard_False;
673 }
674 return aResult;
675}
676
677//=======================================================================
5fce1605 678//function : CreateElement
679//purpose :
680//=======================================================================
681void LDOM_XmlReader::CreateElement( const char *theName, const Standard_Integer theLen )
682{
683 myElement = &LDOM_BasicElement::Create (theName, theLen, myDocument);
684}
685
686//=======================================================================
7fd59977 687//function : getInteger
688//purpose : Try to initialize theValue as Integer; return False on success
689//=======================================================================
690
691Standard_Boolean LDOM_XmlReader::getInteger (LDOMBasicString& theValue,
692 const char * theStart,
693 const char * theEnd)
694{
695 char * ptr;
696 errno = 0;
697 if (theEnd - theStart == 1 || theStart[0] != '0')
698 {
699 long aResult = strtol (theStart, &ptr, 10);
700 if (ptr == theEnd && errno == 0)
701 {
702 theValue = Standard_Integer(aResult);
703 return Standard_False;
704 }
705 }
706 return Standard_True;
707}