0027077: OCAF: Implementation of streaming save/load (OCC26229) is incomplete/incorrect
authoribs <ibs@opencascade.com>
Thu, 14 Jan 2016 16:17:00 +0000 (19:17 +0300)
committerbugmaster <bugmaster@opencascade.com>
Thu, 28 Jan 2016 09:59:51 +0000 (12:59 +0300)
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
src/LDOM/LDOMParser.hxx
src/LDOM/LDOM_XmlReader.cxx
src/LDOM/LDOM_XmlReader.hxx
src/PCDM/PCDM.cxx
src/PCDM/PCDM_ReadWriter.cxx
src/PCDM/PCDM_TypeOfFileDriver.hxx
src/XmlLDrivers/XmlLDrivers_DocumentRetrievalDriver.cxx

index 51b2abf..a8f0e70 100644 (file)
@@ -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()";
index bf99d1c..6fc1bf0 100644 (file)
@@ -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);
 
index 51aa3d8..18e17ce 100644 (file)
@@ -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';
       }
@@ -537,6 +563,15 @@ static Standard_Boolean isName (const char  * aString,
 }
 
 //=======================================================================
+//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
 //=======================================================================
index f40de60..a0d42e1 100644 (file)
@@ -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
index 92b50b1..468de93 100644 (file)
@@ -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 ("<?xml") != -1)
+  {
+    // skip xml declaration
+    char aChar = ' ';
+    while (theIStream.good() && !theIStream.eof() && aChar != '>')
+    {
+      theIStream.get(aChar);
+    }
+
+    return PCDM_TOFD_XmlFile;
+  }
 
   theBaseDriver = NULL;
   return PCDM_TOFD_Unknown;
index 6d2c1b2..1af94f1 100644 (file)
@@ -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;
index e17e79f..8557eda 100644 (file)
@@ -22,6 +22,7 @@ enum PCDM_TypeOfFileDriver
 {
 PCDM_TOFD_File,
 PCDM_TOFD_CmpFile,
+PCDM_TOFD_XmlFile,
 PCDM_TOFD_Unknown
 };
 
index b08d16d..633dfc2 100644 (file)
@@ -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;