mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-04-21 10:13:43 +03:00
0027077: OCAF: Implementation of streaming save/load (OCC26229) is incomplete/incorrect
XmlOcaf reading is non-seekable // 1. Read method of XmlLDrivers_DocumentRetrievalDriver extended to read complete document (with "document" tag) in compatible mode (when reading is performed from file) // 2. the empty statement removed // 3. the description of LDOMPARSER::parse method extended
This commit is contained in:
parent
3f8122493a
commit
5fce160515
@ -111,7 +111,9 @@ const TCollection_AsciiString& LDOMParser::GetError
|
|||||||
//purpose :
|
//purpose :
|
||||||
//=======================================================================
|
//=======================================================================
|
||||||
|
|
||||||
Standard_Boolean LDOMParser::parse (istream& anInput)
|
Standard_Boolean LDOMParser::parse (istream& anInput,
|
||||||
|
const Standard_Boolean theTagPerStep,
|
||||||
|
const Standard_Boolean theWithoutRoot)
|
||||||
{
|
{
|
||||||
// Open the DOM Document
|
// Open the DOM Document
|
||||||
myDocument = new LDOM_MemManager (20000);
|
myDocument = new LDOM_MemManager (20000);
|
||||||
@ -119,10 +121,10 @@ Standard_Boolean LDOMParser::parse (istream& anInput)
|
|||||||
|
|
||||||
// Create the Reader instance
|
// Create the Reader instance
|
||||||
if (myReader) delete myReader;
|
if (myReader) delete myReader;
|
||||||
myReader = new LDOM_XmlReader (myDocument, myError);
|
myReader = new LDOM_XmlReader (myDocument, myError, theTagPerStep);
|
||||||
|
|
||||||
// Parse
|
// Parse
|
||||||
return ParseDocument (anInput);
|
return ParseDocument (anInput, theWithoutRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
//=======================================================================
|
//=======================================================================
|
||||||
@ -151,14 +153,18 @@ Standard_Boolean LDOMParser::parse (const char * const aFileName)
|
|||||||
//purpose : parse the whole document (abstracted from the XML source)
|
//purpose : parse the whole document (abstracted from the XML source)
|
||||||
//=======================================================================
|
//=======================================================================
|
||||||
|
|
||||||
Standard_Boolean LDOMParser::ParseDocument (istream& theIStream)
|
Standard_Boolean LDOMParser::ParseDocument (istream& theIStream, const Standard_Boolean theWithoutRoot)
|
||||||
{
|
{
|
||||||
Standard_Boolean isError = Standard_False;
|
Standard_Boolean isError = Standard_False;
|
||||||
Standard_Boolean isElement = Standard_False;
|
Standard_Boolean isElement = Standard_False;
|
||||||
Standard_Boolean isDoctype = Standard_False;
|
Standard_Boolean isDoctype = Standard_False;
|
||||||
|
|
||||||
|
Standard_Boolean isInsertFictRootElement = Standard_False;
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
LDOM_XmlReader::RecordType aType = ReadRecord (*myReader, theIStream, myCurrentData);
|
LDOM_XmlReader::RecordType aType = (theWithoutRoot && !isInsertFictRootElement ?
|
||||||
|
LDOM_XmlReader::XML_START_ELEMENT :
|
||||||
|
ReadRecord (*myReader, theIStream, myCurrentData));
|
||||||
switch (aType) {
|
switch (aType) {
|
||||||
case LDOM_XmlReader::XML_HEADER:
|
case LDOM_XmlReader::XML_HEADER:
|
||||||
if (isDoctype || isElement) {
|
if (isDoctype || isElement) {
|
||||||
@ -195,7 +201,18 @@ Standard_Boolean LDOMParser::ParseDocument (istream& theIStream)
|
|||||||
case LDOM_XmlReader::XML_START_ELEMENT:
|
case LDOM_XmlReader::XML_START_ELEMENT:
|
||||||
if (isElement == Standard_False) {
|
if (isElement == Standard_False) {
|
||||||
isElement = Standard_True;
|
isElement = Standard_True;
|
||||||
myDocument -> myRootElement = &myReader -> GetElement ();
|
|
||||||
|
if (theWithoutRoot && !isInsertFictRootElement)
|
||||||
|
{
|
||||||
|
isInsertFictRootElement = Standard_True;
|
||||||
|
|
||||||
|
// create fiction root element
|
||||||
|
TCollection_AsciiString aFicName ("document");
|
||||||
|
myReader->CreateElement (aFicName.ToCString(), aFicName.Length());
|
||||||
|
}
|
||||||
|
|
||||||
|
myDocument->myRootElement = &myReader->GetElement();
|
||||||
|
|
||||||
if (startElement()) {
|
if (startElement()) {
|
||||||
isError = Standard_True;
|
isError = Standard_True;
|
||||||
myError = "User abort at startElement()";
|
myError = "User abort at startElement()";
|
||||||
|
@ -48,8 +48,16 @@ class LDOMParser
|
|||||||
// Returns True if error occurred, then GetError() can be called
|
// Returns True if error occurred, then GetError() can be called
|
||||||
|
|
||||||
Standard_EXPORT Standard_Boolean
|
Standard_EXPORT Standard_Boolean
|
||||||
parse (istream& anInput);
|
parse (istream& anInput,
|
||||||
|
const Standard_Boolean theTagPerStep = Standard_False,
|
||||||
|
const Standard_Boolean theWithoutRoot = Standard_False);
|
||||||
// Parse a C++ stream
|
// Parse a C++ stream
|
||||||
|
// theTagPerStep - if true - extract characters from anInput until '>'
|
||||||
|
// extracted character and parse only these characters.
|
||||||
|
// if false - extract until eof
|
||||||
|
// theWithoutRoot - if true - create fictive "document" element before parsing
|
||||||
|
// and consider that document start element has been already read
|
||||||
|
// - if false - parse a document as usual (parse header, document tag and etc)
|
||||||
// Returns True if error occurred, then GetError() can be called
|
// Returns True if error occurred, then GetError() can be called
|
||||||
|
|
||||||
Standard_EXPORT const TCollection_AsciiString&
|
Standard_EXPORT const TCollection_AsciiString&
|
||||||
@ -73,7 +81,7 @@ class LDOMParser
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// ---------- PRIVATE METHODS ----------
|
// ---------- PRIVATE METHODS ----------
|
||||||
Standard_Boolean ParseDocument (Standard_IStream& theIStream);
|
Standard_Boolean ParseDocument (Standard_IStream& theIStream, const Standard_Boolean theWithoutRoot = Standard_False);
|
||||||
|
|
||||||
Standard_Boolean ParseElement (Standard_IStream& theIStream);
|
Standard_Boolean ParseElement (Standard_IStream& theIStream);
|
||||||
|
|
||||||
|
@ -64,14 +64,16 @@ static Standard_Boolean isName (const char * aString,
|
|||||||
|
|
||||||
LDOM_XmlReader::LDOM_XmlReader (
|
LDOM_XmlReader::LDOM_XmlReader (
|
||||||
const Handle(LDOM_MemManager)& theDocument,
|
const Handle(LDOM_MemManager)& theDocument,
|
||||||
TCollection_AsciiString& theErrorString)
|
TCollection_AsciiString& theErrorString,
|
||||||
|
const Standard_Boolean theTagPerStep)
|
||||||
: myEOF (Standard_False),
|
: myEOF (Standard_False),
|
||||||
myError (theErrorString),
|
myError (theErrorString),
|
||||||
myDocument (theDocument),
|
myDocument (theDocument),
|
||||||
myElement (NULL),
|
myElement (NULL),
|
||||||
myLastChild(NULL),
|
myLastChild(NULL),
|
||||||
myPtr (&myBuffer[0]),
|
myPtr (&myBuffer[0]),
|
||||||
myEndPtr (&myBuffer[0])
|
myEndPtr (&myBuffer[0]),
|
||||||
|
myTagPerStep (theTagPerStep)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,17 +91,25 @@ LDOM_XmlReader::RecordType LDOM_XmlReader::ReadRecord (Standard_IStream& theIStr
|
|||||||
const char * aStartData = NULL, * aNameEnd = NULL, * aPtr;
|
const char * aStartData = NULL, * aNameEnd = NULL, * aPtr;
|
||||||
LDOMBasicString anAttrName, anAttrValue;
|
LDOMBasicString anAttrName, anAttrValue;
|
||||||
char anAttDelimiter = '\0';
|
char anAttDelimiter = '\0';
|
||||||
|
Standard_Boolean aHasRead = Standard_False;
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
// Check if the current file buffer is exhausted
|
// Check if the current file buffer is exhausted
|
||||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
// There should always be some bytes available in the buffer for analysis
|
// There should always be some bytes available in the buffer for analysis
|
||||||
Standard_Integer aBytesRest = (Standard_Integer)(myEndPtr - myPtr);
|
Standard_Integer aBytesRest = (Standard_Integer)(myEndPtr - myPtr);
|
||||||
if (aBytesRest < XML_MIN_BUFFER) {
|
if (aBytesRest < XML_MIN_BUFFER)
|
||||||
if (myEOF == Standard_True) {
|
{
|
||||||
|
if (myEOF == Standard_True)
|
||||||
|
{
|
||||||
if (aBytesRest <= 0)
|
if (aBytesRest <= 0)
|
||||||
break; // END of processing
|
break; // END of processing
|
||||||
} else {
|
}
|
||||||
|
else if (myTagPerStep && aHasRead)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// If we are reading some data, save the beginning and preserve the state
|
// If we are reading some data, save the beginning and preserve the state
|
||||||
if (aStartData /* && aState != STATE_WAITING */) {
|
if (aStartData /* && aState != STATE_WAITING */) {
|
||||||
if (myPtr > aStartData)
|
if (myPtr > aStartData)
|
||||||
@ -113,11 +123,27 @@ LDOM_XmlReader::RecordType LDOM_XmlReader::ReadRecord (Standard_IStream& theIStr
|
|||||||
// Read the full buffer and reset start and end buffer pointers
|
// Read the full buffer and reset start and end buffer pointers
|
||||||
myPtr = &myBuffer[0];
|
myPtr = &myBuffer[0];
|
||||||
Standard_Size aNBytes;
|
Standard_Size aNBytes;
|
||||||
theIStream.read (&myBuffer[aBytesRest],
|
|
||||||
XML_BUFFER_SIZE - aBytesRest);
|
if (myTagPerStep)
|
||||||
|
{
|
||||||
|
theIStream.getline (&myBuffer[aBytesRest], XML_BUFFER_SIZE - aBytesRest, '>');
|
||||||
|
aHasRead = Standard_True;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
theIStream.read (&myBuffer[aBytesRest], XML_BUFFER_SIZE - aBytesRest);
|
||||||
|
}
|
||||||
aNBytes = (Standard_Size)theIStream.gcount();
|
aNBytes = (Standard_Size)theIStream.gcount();
|
||||||
|
|
||||||
if (aNBytes == 0)
|
if (aNBytes == 0)
|
||||||
|
{
|
||||||
myEOF = Standard_True; // END-OF-FILE
|
myEOF = Standard_True; // END-OF-FILE
|
||||||
|
}
|
||||||
|
else if (myTagPerStep)
|
||||||
|
{
|
||||||
|
// replace \0 (being inserted by getline method) with >
|
||||||
|
myBuffer[aBytesRest + aNBytes - 1] = '>';
|
||||||
|
}
|
||||||
myEndPtr = &myBuffer[aBytesRest + aNBytes];
|
myEndPtr = &myBuffer[aBytesRest + aNBytes];
|
||||||
myBuffer[aBytesRest + aNBytes] = '\0';
|
myBuffer[aBytesRest + aNBytes] = '\0';
|
||||||
}
|
}
|
||||||
@ -536,6 +562,15 @@ static Standard_Boolean isName (const char * aString,
|
|||||||
return aResult;
|
return aResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=======================================================================
|
||||||
|
//function : CreateElement
|
||||||
|
//purpose :
|
||||||
|
//=======================================================================
|
||||||
|
void LDOM_XmlReader::CreateElement( const char *theName, const Standard_Integer theLen )
|
||||||
|
{
|
||||||
|
myElement = &LDOM_BasicElement::Create (theName, theLen, myDocument);
|
||||||
|
}
|
||||||
|
|
||||||
//=======================================================================
|
//=======================================================================
|
||||||
//function : getInteger
|
//function : getInteger
|
||||||
//purpose : Try to initialize theValue as Integer; return False on success
|
//purpose : Try to initialize theValue as Integer; return False on success
|
||||||
|
@ -48,7 +48,8 @@ class LDOM_XmlReader
|
|||||||
|
|
||||||
// ---------- PUBLIC METHODS ----------
|
// ---------- PUBLIC METHODS ----------
|
||||||
LDOM_XmlReader (const Handle(LDOM_MemManager)& aDocument,
|
LDOM_XmlReader (const Handle(LDOM_MemManager)& aDocument,
|
||||||
TCollection_AsciiString& anErrorString);
|
TCollection_AsciiString& anErrorString,
|
||||||
|
const Standard_Boolean theTagPerStep = Standard_False);
|
||||||
// Constructor - takes a file descriptor for input
|
// Constructor - takes a file descriptor for input
|
||||||
// Constructor - takes an istream for input
|
// Constructor - takes an istream for input
|
||||||
|
|
||||||
@ -58,6 +59,8 @@ class LDOM_XmlReader
|
|||||||
LDOM_BasicElement& GetElement () const { return * myElement; }
|
LDOM_BasicElement& GetElement () const { return * myElement; }
|
||||||
// get the last element retrieved from the stream
|
// get the last element retrieved from the stream
|
||||||
|
|
||||||
|
void CreateElement (const char *theName, const Standard_Integer theLen);
|
||||||
|
|
||||||
static Standard_Boolean getInteger (LDOMBasicString& theValue,
|
static Standard_Boolean getInteger (LDOMBasicString& theValue,
|
||||||
const char * theStart,
|
const char * theStart,
|
||||||
const char * theEnd);
|
const char * theEnd);
|
||||||
@ -82,6 +85,7 @@ class LDOM_XmlReader
|
|||||||
const char * myPtr;
|
const char * myPtr;
|
||||||
const char * myEndPtr;
|
const char * myEndPtr;
|
||||||
char myBuffer [XML_BUFFER_SIZE+4];
|
char myBuffer [XML_BUFFER_SIZE+4];
|
||||||
|
Standard_Boolean myTagPerStep;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -93,19 +93,10 @@ PCDM_TypeOfFileDriver PCDM::FileDriverType (Standard_IStream& theIStream, PCDM_B
|
|||||||
{
|
{
|
||||||
TCollection_AsciiString aReadMagicNumber;
|
TCollection_AsciiString aReadMagicNumber;
|
||||||
|
|
||||||
|
// read magic number from the file
|
||||||
if (theIStream.good())
|
if (theIStream.good())
|
||||||
{
|
{
|
||||||
streampos aDocumentPos = theIStream.tellg();
|
|
||||||
|
|
||||||
// read magic number from the file
|
|
||||||
aReadMagicNumber = Storage_BaseDriver::ReadMagicNumber (theIStream);
|
aReadMagicNumber = Storage_BaseDriver::ReadMagicNumber (theIStream);
|
||||||
|
|
||||||
if (!theIStream.good())
|
|
||||||
{
|
|
||||||
theIStream.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
theIStream.seekg(aDocumentPos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(aReadMagicNumber == FSD_CmpFile::MagicNumber())
|
if(aReadMagicNumber == FSD_CmpFile::MagicNumber())
|
||||||
@ -123,6 +114,17 @@ PCDM_TypeOfFileDriver PCDM::FileDriverType (Standard_IStream& theIStream, PCDM_B
|
|||||||
theBaseDriver = new FSD_BinaryFile;
|
theBaseDriver = new FSD_BinaryFile;
|
||||||
return PCDM_TOFD_File;
|
return PCDM_TOFD_File;
|
||||||
}
|
}
|
||||||
|
else if (aReadMagicNumber.Search ("<?xml") != -1)
|
||||||
|
{
|
||||||
|
// skip xml declaration
|
||||||
|
char aChar = ' ';
|
||||||
|
while (theIStream.good() && !theIStream.eof() && aChar != '>')
|
||||||
|
{
|
||||||
|
theIStream.get(aChar);
|
||||||
|
}
|
||||||
|
|
||||||
|
return PCDM_TOFD_XmlFile;
|
||||||
|
}
|
||||||
|
|
||||||
theBaseDriver = NULL;
|
theBaseDriver = NULL;
|
||||||
return PCDM_TOFD_Unknown;
|
return PCDM_TOFD_Unknown;
|
||||||
|
@ -167,15 +167,11 @@ TCollection_ExtendedString PCDM_ReadWriter::FileFormat (Standard_IStream& theISt
|
|||||||
TCollection_ExtendedString aFormat;
|
TCollection_ExtendedString aFormat;
|
||||||
|
|
||||||
Storage_BaseDriver* aFileDriver;
|
Storage_BaseDriver* aFileDriver;
|
||||||
if (PCDM::FileDriverType (theIStream, aFileDriver) == PCDM_TOFD_Unknown)
|
if (PCDM::FileDriverType (theIStream, aFileDriver) == PCDM_TOFD_XmlFile)
|
||||||
{
|
{
|
||||||
return ::TryXmlDriverType (theIStream);
|
return ::TryXmlDriverType (theIStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
// the stream starts with a magic number, FileDriverType has read
|
|
||||||
// them already but returned the stream pos to initial state,
|
|
||||||
// thus we should read them before reading of info section
|
|
||||||
aFileDriver->ReadMagicNumber(theIStream);
|
|
||||||
|
|
||||||
aFileDriver->ReadCompleteInfo (theIStream, theData);
|
aFileDriver->ReadCompleteInfo (theIStream, theData);
|
||||||
|
|
||||||
@ -230,23 +226,14 @@ static TCollection_ExtendedString TryXmlDriverType (Standard_IStream& theIStream
|
|||||||
|
|
||||||
if (theIStream.good())
|
if (theIStream.good())
|
||||||
{
|
{
|
||||||
streampos aDocumentPos = theIStream.tellg();
|
|
||||||
|
|
||||||
// Parse the file; if there is no error or an error appears before retrieval
|
// Parse the file; if there is no error or an error appears before retrieval
|
||||||
// of the DocumentElement, the XML format cannot be defined
|
// of the DocumentElement, the XML format cannot be defined
|
||||||
if (aParser.parse (theIStream))
|
if (aParser.parse (theIStream, Standard_True))
|
||||||
{
|
{
|
||||||
LDOM_Element anElement = aParser.GetElement();
|
LDOM_Element anElement = aParser.GetElement();
|
||||||
if (anElement.getTagName().equals (LDOMString(aDocumentElementName)))
|
if (anElement.getTagName().equals (LDOMString(aDocumentElementName)))
|
||||||
theFormat = anElement.getAttribute ("format");
|
theFormat = anElement.getAttribute ("format");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!theIStream.good())
|
|
||||||
{
|
|
||||||
theIStream.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
theIStream.seekg(aDocumentPos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return theFormat;
|
return theFormat;
|
||||||
|
@ -22,6 +22,7 @@ enum PCDM_TypeOfFileDriver
|
|||||||
{
|
{
|
||||||
PCDM_TOFD_File,
|
PCDM_TOFD_File,
|
||||||
PCDM_TOFD_CmpFile,
|
PCDM_TOFD_CmpFile,
|
||||||
|
PCDM_TOFD_XmlFile,
|
||||||
PCDM_TOFD_Unknown
|
PCDM_TOFD_Unknown
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -216,7 +216,11 @@ void XmlLDrivers_DocumentRetrievalDriver::Read (Standard_IStream& t
|
|||||||
// 1. Read DOM_Document from file
|
// 1. Read DOM_Document from file
|
||||||
LDOMParser aParser;
|
LDOMParser aParser;
|
||||||
|
|
||||||
if (aParser.parse(theIStream))
|
// if myFileName is not empty, "document" tag is required to be read
|
||||||
|
// from the received document
|
||||||
|
Standard_Boolean aWithoutRoot = myFileName.IsEmpty();
|
||||||
|
|
||||||
|
if (aParser.parse(theIStream, Standard_False, aWithoutRoot))
|
||||||
{
|
{
|
||||||
TCollection_AsciiString aData;
|
TCollection_AsciiString aData;
|
||||||
cout << aParser.GetError(aData) << ": " << aData << endl;
|
cout << aParser.GetError(aData) << ": " << aData << endl;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user