From 5fce1605152239f33b4471e789b0466bfcf0413d Mon Sep 17 00:00:00 2001 From: ibs Date: Thu, 14 Jan 2016 19:17:00 +0300 Subject: [PATCH] 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 --- src/LDOM/LDOMParser.cxx | 29 ++++++++--- src/LDOM/LDOMParser.hxx | 12 ++++- src/LDOM/LDOM_XmlReader.cxx | 51 ++++++++++++++++--- src/LDOM/LDOM_XmlReader.hxx | 6 ++- src/PCDM/PCDM.cxx | 22 ++++---- src/PCDM/PCDM_ReadWriter.cxx | 19 ++----- src/PCDM/PCDM_TypeOfFileDriver.hxx | 1 + .../XmlLDrivers_DocumentRetrievalDriver.cxx | 6 ++- 8 files changed, 102 insertions(+), 44 deletions(-) diff --git a/src/LDOM/LDOMParser.cxx b/src/LDOM/LDOMParser.cxx index 51b2abf346..a8f0e70fd7 100644 --- a/src/LDOM/LDOMParser.cxx +++ b/src/LDOM/LDOMParser.cxx @@ -111,7 +111,9 @@ const TCollection_AsciiString& LDOMParser::GetError //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 myDocument = new LDOM_MemManager (20000); @@ -119,10 +121,10 @@ Standard_Boolean LDOMParser::parse (istream& anInput) // Create the Reader instance if (myReader) delete myReader; - myReader = new LDOM_XmlReader (myDocument, myError); + myReader = new LDOM_XmlReader (myDocument, myError, theTagPerStep); // 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) //======================================================================= -Standard_Boolean LDOMParser::ParseDocument (istream& theIStream) +Standard_Boolean LDOMParser::ParseDocument (istream& theIStream, const Standard_Boolean theWithoutRoot) { Standard_Boolean isError = Standard_False; Standard_Boolean isElement = Standard_False; Standard_Boolean isDoctype = Standard_False; + Standard_Boolean isInsertFictRootElement = Standard_False; + 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) { case LDOM_XmlReader::XML_HEADER: if (isDoctype || isElement) { @@ -195,7 +201,18 @@ Standard_Boolean LDOMParser::ParseDocument (istream& theIStream) case LDOM_XmlReader::XML_START_ELEMENT: if (isElement == Standard_False) { 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()) { isError = Standard_True; myError = "User abort at startElement()"; diff --git a/src/LDOM/LDOMParser.hxx b/src/LDOM/LDOMParser.hxx index bf99d1c6c9..6fc1bf0c9a 100644 --- a/src/LDOM/LDOMParser.hxx +++ b/src/LDOM/LDOMParser.hxx @@ -48,8 +48,16 @@ class LDOMParser // Returns True if error occurred, then GetError() can be called 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 + // 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 Standard_EXPORT const TCollection_AsciiString& @@ -73,7 +81,7 @@ class LDOMParser private: // ---------- 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); diff --git a/src/LDOM/LDOM_XmlReader.cxx b/src/LDOM/LDOM_XmlReader.cxx index 51aa3d8949..18e17cec7c 100644 --- a/src/LDOM/LDOM_XmlReader.cxx +++ b/src/LDOM/LDOM_XmlReader.cxx @@ -64,14 +64,16 @@ static Standard_Boolean isName (const char * aString, LDOM_XmlReader::LDOM_XmlReader ( const Handle(LDOM_MemManager)& theDocument, - TCollection_AsciiString& theErrorString) + TCollection_AsciiString& theErrorString, + const Standard_Boolean theTagPerStep) : myEOF (Standard_False), myError (theErrorString), myDocument (theDocument), myElement (NULL), myLastChild(NULL), 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; LDOMBasicString anAttrName, anAttrValue; char anAttDelimiter = '\0'; + Standard_Boolean aHasRead = Standard_False; for(;;) { // Check if the current file buffer is exhausted // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // There should always be some bytes available in the buffer for analysis Standard_Integer aBytesRest = (Standard_Integer)(myEndPtr - myPtr); - if (aBytesRest < XML_MIN_BUFFER) { - if (myEOF == Standard_True) { + if (aBytesRest < XML_MIN_BUFFER) + { + if (myEOF == Standard_True) + { if (aBytesRest <= 0) break; // END of processing - } else { + } + else if (myTagPerStep && aHasRead) + { + } + else + { // If we are reading some data, save the beginning and preserve the state if (aStartData /* && aState != STATE_WAITING */) { 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 myPtr = &myBuffer[0]; Standard_Size aNBytes; - theIStream.read (&myBuffer[aBytesRest], - XML_BUFFER_SIZE - aBytesRest); - aNBytes = (Standard_Size)theIStream.gcount(); + + 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(); + if (aNBytes == 0) + { 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]; myBuffer[aBytesRest + aNBytes] = '\0'; } @@ -536,6 +562,15 @@ static Standard_Boolean isName (const char * aString, 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 //purpose : Try to initialize theValue as Integer; return False on success diff --git a/src/LDOM/LDOM_XmlReader.hxx b/src/LDOM/LDOM_XmlReader.hxx index f40de60740..a0d42e1603 100644 --- a/src/LDOM/LDOM_XmlReader.hxx +++ b/src/LDOM/LDOM_XmlReader.hxx @@ -48,7 +48,8 @@ class LDOM_XmlReader // ---------- PUBLIC METHODS ---------- 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 an istream for input @@ -58,6 +59,8 @@ class LDOM_XmlReader LDOM_BasicElement& GetElement () const { return * myElement; } // get the last element retrieved from the stream + void CreateElement (const char *theName, const Standard_Integer theLen); + static Standard_Boolean getInteger (LDOMBasicString& theValue, const char * theStart, const char * theEnd); @@ -82,6 +85,7 @@ class LDOM_XmlReader const char * myPtr; const char * myEndPtr; char myBuffer [XML_BUFFER_SIZE+4]; + Standard_Boolean myTagPerStep; }; #endif diff --git a/src/PCDM/PCDM.cxx b/src/PCDM/PCDM.cxx index 92b50b1a0c..468de93b95 100644 --- a/src/PCDM/PCDM.cxx +++ b/src/PCDM/PCDM.cxx @@ -93,19 +93,10 @@ PCDM_TypeOfFileDriver PCDM::FileDriverType (Standard_IStream& theIStream, PCDM_B { TCollection_AsciiString aReadMagicNumber; + // read magic number from the file if (theIStream.good()) { - streampos aDocumentPos = theIStream.tellg(); - - // read magic number from the file aReadMagicNumber = Storage_BaseDriver::ReadMagicNumber (theIStream); - - if (!theIStream.good()) - { - theIStream.clear(); - } - - theIStream.seekg(aDocumentPos); } if(aReadMagicNumber == FSD_CmpFile::MagicNumber()) @@ -123,6 +114,17 @@ PCDM_TypeOfFileDriver PCDM::FileDriverType (Standard_IStream& theIStream, PCDM_B theBaseDriver = new FSD_BinaryFile; return PCDM_TOFD_File; } + else if (aReadMagicNumber.Search ("') + { + theIStream.get(aChar); + } + + return PCDM_TOFD_XmlFile; + } theBaseDriver = NULL; return PCDM_TOFD_Unknown; diff --git a/src/PCDM/PCDM_ReadWriter.cxx b/src/PCDM/PCDM_ReadWriter.cxx index 6d2c1b25d5..1af94f1247 100644 --- a/src/PCDM/PCDM_ReadWriter.cxx +++ b/src/PCDM/PCDM_ReadWriter.cxx @@ -167,15 +167,11 @@ TCollection_ExtendedString PCDM_ReadWriter::FileFormat (Standard_IStream& theISt TCollection_ExtendedString aFormat; Storage_BaseDriver* aFileDriver; - if (PCDM::FileDriverType (theIStream, aFileDriver) == PCDM_TOFD_Unknown) + if (PCDM::FileDriverType (theIStream, aFileDriver) == PCDM_TOFD_XmlFile) { 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); @@ -230,23 +226,14 @@ static TCollection_ExtendedString TryXmlDriverType (Standard_IStream& theIStream if (theIStream.good()) { - streampos aDocumentPos = theIStream.tellg(); - // Parse the file; if there is no error or an error appears before retrieval // of the DocumentElement, the XML format cannot be defined - if (aParser.parse (theIStream)) + if (aParser.parse (theIStream, Standard_True)) { LDOM_Element anElement = aParser.GetElement(); if (anElement.getTagName().equals (LDOMString(aDocumentElementName))) theFormat = anElement.getAttribute ("format"); } - - if (!theIStream.good()) - { - theIStream.clear(); - } - - theIStream.seekg(aDocumentPos); } return theFormat; diff --git a/src/PCDM/PCDM_TypeOfFileDriver.hxx b/src/PCDM/PCDM_TypeOfFileDriver.hxx index e17e79fe28..8557eda396 100644 --- a/src/PCDM/PCDM_TypeOfFileDriver.hxx +++ b/src/PCDM/PCDM_TypeOfFileDriver.hxx @@ -22,6 +22,7 @@ enum PCDM_TypeOfFileDriver { PCDM_TOFD_File, PCDM_TOFD_CmpFile, +PCDM_TOFD_XmlFile, PCDM_TOFD_Unknown }; diff --git a/src/XmlLDrivers/XmlLDrivers_DocumentRetrievalDriver.cxx b/src/XmlLDrivers/XmlLDrivers_DocumentRetrievalDriver.cxx index b08d16d4a2..633dfc2b89 100644 --- a/src/XmlLDrivers/XmlLDrivers_DocumentRetrievalDriver.cxx +++ b/src/XmlLDrivers/XmlLDrivers_DocumentRetrievalDriver.cxx @@ -216,7 +216,11 @@ void XmlLDrivers_DocumentRetrievalDriver::Read (Standard_IStream& t // 1. Read DOM_Document from file 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; cout << aParser.GetError(aData) << ": " << aData << endl;