1
0
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:
ibs 2016-01-14 19:17:00 +03:00 committed by bugmaster
parent 3f8122493a
commit 5fce160515
8 changed files with 102 additions and 44 deletions

View File

@ -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()";

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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
}; };

View File

@ -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;