0027192: Improvement of storage of Ocaf document in XML file format
authorvro <vro@opencascade.com>
Wed, 24 Feb 2016 07:35:52 +0000 (10:35 +0300)
committerbugmaster <bugmaster@opencascade.com>
Fri, 8 Apr 2016 08:42:05 +0000 (11:42 +0300)
Improvement of code in XmlMDataStd_ExtStringArrayDriver.cxx

Corrected test-script

src/DDataStd/DDataStd_BasicCommands.cxx
src/XmlMDataStd/XmlMDataStd_ExtStringArrayDriver.cxx
src/XmlMDataStd/XmlMDataStd_TreeNodeDriver.cxx
tests/caf/basic/M4 [new file with mode: 0755]

index 732d161..8580899 100644 (file)
@@ -1153,7 +1153,7 @@ static Standard_Integer DDataStd_GetExtStringArrayValue (Draw_Interpretor& di,
     return 1;
   } else {
     const TCollection_ExtendedString& value = A->Value(index);
-    di << value << "\n";
+    di << value ;
   }
 
   return 0; 
index 8ed9f93..42ab8da 100644 (file)
@@ -30,6 +30,24 @@ IMPLEMENT_DOMSTRING (FirstIndexString, "first")
 IMPLEMENT_DOMSTRING (LastIndexString, "last")
 IMPLEMENT_DOMSTRING (ExtString,       "string")
 IMPLEMENT_DOMSTRING (IsDeltaOn,       "delta")
+IMPLEMENT_DOMSTRING (Separator,       "separator")
+
+// Searches for a symbol within an array of strings.
+// Returns TRUE if the symbol is found.
+static Standard_Boolean Contains(const Handle(TDataStd_ExtStringArray)& arr,
+                                 const TCollection_ExtendedString& c)
+{
+  for (Standard_Integer i = arr->Lower(); i <= arr->Upper(); i++)
+  {
+    const TCollection_ExtendedString& value = arr->Value(i);
+    if (value.Search(c) != -1)
+    {
+      return Standard_True;
+    }
+  }
+  return Standard_False;
+}
+
 //=======================================================================
 //function : XmlMDataStd_ExtStringArrayDriver
 //purpose  : Constructor
@@ -85,32 +103,84 @@ Standard_Boolean XmlMDataStd_ExtStringArrayDriver::Paste
     return Standard_False;
   }
 
+  // Read separator.
+  TCollection_ExtendedString separator;
+  XmlObjMgt_DOMString aSeparator = anElement.getAttribute(::Separator());
+  if (aSeparator.Type() != XmlObjMgt_DOMString::LDOM_NULL)
+    separator = aSeparator.GetString();
+
   Handle(TDataStd_ExtStringArray) aExtStringArray =
     Handle(TDataStd_ExtStringArray)::DownCast(theTarget);
   aExtStringArray->Init(aFirstInd, aLastInd);
   
-  if ( !anElement.hasChildNodes() )
-  {
-    TCollection_ExtendedString aMessageString =
-      TCollection_ExtendedString("Cannot retrieve array of extended string");
-    WriteMessage (aMessageString);
-    return Standard_False;
-  }
-
-  LDOM_Node aCurNode = anElement.getFirstChild();
-  LDOM_Element* aCurElement = (LDOM_Element*)&aCurNode;
-  TCollection_ExtendedString aValueStr;
-  for (ind = aFirstInd; ind <= aLastInd && *aCurElement != anElement.getLastChild(); ind++)
+  // Read string values.
+  if ( !separator.Length() && anElement.hasChildNodes() )
   {
+    // Read values written by <string>VALUE<\string> notion - as children of the attribute.
+    LDOM_Node aCurNode = anElement.getFirstChild();
+    LDOM_Element* aCurElement = (LDOM_Element*)&aCurNode;
+    TCollection_ExtendedString aValueStr;
+    for (ind = aFirstInd; ind <= aLastInd && *aCurElement != anElement.getLastChild(); ind++)
+    {
+      XmlObjMgt::GetExtendedString( *aCurElement, aValueStr );
+      aExtStringArray->SetValue(ind, aValueStr);
+      aCurNode = aCurElement->getNextSibling();
+      aCurElement = (LDOM_Element*)&aCurNode;
+    }
     XmlObjMgt::GetExtendedString( *aCurElement, aValueStr );
-    aExtStringArray->SetValue(ind, aValueStr);
-    aCurNode = aCurElement->getNextSibling();
-    aCurElement = (LDOM_Element*)&aCurNode;
+    aExtStringArray->SetValue( aLastInd, aValueStr );
   }
+  else
+  {
+    TCollection_ExtendedString xstr;
+    XmlObjMgt::GetExtendedString(anElement, xstr);
+#ifdef _DEBUG
+    TCollection_AsciiString cstr(xstr, '?');
+#endif
+
+    // Split strings by the separator.
+    Standard_Integer isym(1); // index of symbol in xstr
+    Standard_ExtCharacter xsep = separator.Value(1);
+    for (ind = aFirstInd; ind <= aLastInd; ind++)
+    {
+      // Calculate length of the string-value.
+      Standard_Integer iend = isym;
+      while (iend < xstr.Length())
+      {
+        if (xstr.Value(iend) == xsep)
+        {
+          break;
+        }
+        iend++;
+      }
+      if (iend <= xstr.Length() && 
+          xstr.Value(iend) != xsep)
+      {
+        iend++;
+      }
+
+      // Allocate the string-value.
+      TCollection_ExtendedString xvalue(iend - isym, '\0');
+
+      // Set string-value.
+      for (Standard_Integer i = isym; i < iend; ++i)
+      {
+        const Standard_ExtCharacter x = xstr.Value(i);
+        xvalue.SetValue(i - isym + 1, x);
+      }
+#ifdef _DEBUG
+      TCollection_AsciiString cvalue(xvalue, '?');
+#endif
 
-  XmlObjMgt::GetExtendedString( *aCurElement, aValueStr );
-  aExtStringArray->SetValue( aLastInd, aValueStr );
+      // Set value for the array.
+      aExtStringArray->SetValue(ind, xvalue);
 
+      // Next string-value.
+      isym = iend + 1;
+    }
+  }
+
+  // Read delta-flag.
   Standard_Boolean aDelta(Standard_False);
   
   if(XmlMDataStd::DocumentVersion() > 2) {
@@ -147,7 +217,7 @@ void XmlMDataStd_ExtStringArrayDriver::Paste (const Handle(TDF_Attribute)& theSo
   Handle(TDataStd_ExtStringArray) aExtStringArray =
     Handle(TDataStd_ExtStringArray)::DownCast(theSource);
 
-  Standard_Integer aL = aExtStringArray->Lower(), anU = aExtStringArray->Upper();
+  Standard_Integer aL = aExtStringArray->Lower(), anU = aExtStringArray->Upper(), i;
 
   XmlObjMgt_Element& anElement = theTarget;
 
@@ -155,14 +225,93 @@ void XmlMDataStd_ExtStringArrayDriver::Paste (const Handle(TDF_Attribute)& theSo
   anElement.setAttribute(::LastIndexString(), anU);
   anElement.setAttribute(::IsDeltaOn(), aExtStringArray->GetDelta()); 
 
-  // store a set of elements with string in each of them
-  XmlObjMgt_Document aDoc (anElement.getOwnerDocument());
+  // Find a separator.
+  Standard_Boolean found(Standard_True);
+  // Preferrable symbols for the separator: - _ . : ^ ~
+  // Don't use a space as a separator: XML low-level parser sometimes "eats" it.
+  Standard_Character c = '-';
+  static Standard_Character aPreferable[] = "-_.:^~";
+  for (i = 0; found && aPreferable[i]; i++)
+  {
+    c = aPreferable[i];
+    found = Contains(aExtStringArray, TCollection_ExtendedString(c));
+  }
+  // If all prefferable symbols exist in the array, 
+  // try to use any other simple symbols.
+  if (found)
+  {
+    c = '!';
+    while (found && c < '~')
+    {
+      found = Standard_False;
+#ifdef _DEBUG
+      TCollection_AsciiString cseparator(c); // deb
+#endif
+      TCollection_ExtendedString separator(c);
+      found = Contains(aExtStringArray, separator);
+      if (found)
+      {
+        c++;
+        // Skip forbidden symbols for XML.
+        while (c < '~' && (c == '&' || c == '<'))
+        {
+          c++;
+        }
+      }
+    }
+  }
   
-  for ( Standard_Integer i = aL; i <= anU; i++ )
+  if (found)
   {
-    TCollection_ExtendedString aValueStr = aExtStringArray->Value( i );
-    XmlObjMgt_Element aCurTarget = aDoc.createElement( ::ExtString() );
-    XmlObjMgt::SetExtendedString( aCurTarget, aValueStr );
-    anElement.appendChild( aCurTarget );
+      // There is no unique separator. Use child elements for storage of strings of the array.
+
+      // store a set of elements with string in each of them
+      XmlObjMgt_Document aDoc (anElement.getOwnerDocument());
+      for ( i = aL; i <= anU; i++ )
+      {
+        const TCollection_ExtendedString& aValueStr = aExtStringArray->Value( i );
+        XmlObjMgt_Element aCurTarget = aDoc.createElement( ::ExtString() );
+        XmlObjMgt::SetExtendedString( aCurTarget, aValueStr );
+        anElement.appendChild( aCurTarget );
+      }
+  }
+  else
+  {
+      // Set the separator.
+      TCollection_AsciiString csep(c);
+      anElement.setAttribute(::Separator(), csep.ToCString());
+
+      // Calculate length of the common string.
+      Standard_Integer len(0);
+      for (i = aL; i <= anU; i++)
+      {
+        const TCollection_ExtendedString& aValueStr = aExtStringArray->Value(i);
+        len += aValueStr.Length();
+        len++; // for separator or ending \0 symbol
+      }
+      if (!len)
+        len++; // for end of line \0 symbol
+
+      // Merge all strings of the array into one extended string separated by the "separator".
+      Standard_Integer isym(1);
+      TCollection_ExtendedString xstr(len, c);
+      for (i = aL; i <= anU; i++)
+      {
+        const TCollection_ExtendedString& aValueStr = aExtStringArray->Value(i);
+        for (Standard_Integer k = 1; k <= aValueStr.Length(); k++)
+        {
+          xstr.SetValue(isym++, aValueStr.Value(k));
+        }
+        xstr.SetValue(isym++, c);
+      }
+      if (xstr.SearchFromEnd(c) == isym - 1)
+        isym--; // replace the last separator by '\0'
+      xstr.SetValue(isym, '\0');
+#ifdef _DEBUG
+      TCollection_AsciiString cstr(xstr, '?'); // deb
+#endif
+
+      // Set UNICODE value.
+      XmlObjMgt::SetExtendedString(theTarget, xstr);
   }
 }
index a50848a..3e906b6 100644 (file)
@@ -59,8 +59,12 @@ Standard_Boolean XmlMDataStd_TreeNodeDriver::Paste
   const XmlObjMgt_Element& anElement = theSource;
 
   // tree id
+  Standard_GUID aGUID;
   XmlObjMgt_DOMString aGUIDStr = anElement.getAttribute(::TreeIdString());
-  Standard_GUID aGUID (Standard_CString(aGUIDStr.GetString()));
+  if (aGUIDStr.Type() == XmlObjMgt_DOMString::LDOM_NULL)
+    aGUID = TDataStd_TreeNode::GetDefaultTreeID();
+  else
+    aGUID = Standard_GUID(Standard_CString(aGUIDStr.GetString()));
   aT->SetTreeID(aGUID);
 
   // children
@@ -111,11 +115,13 @@ void XmlMDataStd_TreeNodeDriver::Paste
   Handle(TDataStd_TreeNode) aS = Handle(TDataStd_TreeNode)::DownCast(theSource);
 
   // tree id
-  Standard_Integer aNb;
-  Standard_Character aGuidStr [40];
-  Standard_PCharacter pGuidStr=aGuidStr;
-  aS->ID().ToCString (pGuidStr);
-  theTarget.Element().setAttribute(::TreeIdString(), aGuidStr);
+  if (aS->ID() != TDataStd_TreeNode::GetDefaultTreeID())
+  {
+    Standard_Character aGuidStr [40];
+    Standard_PCharacter pGuidStr=aGuidStr;
+    aS->ID().ToCString (pGuidStr);
+    theTarget.Element().setAttribute(::TreeIdString(), aGuidStr);
+  }
 
   // Find number of children.
   int nbChildren = aS->NbChildren();
@@ -130,7 +136,7 @@ void XmlMDataStd_TreeNodeDriver::Paste
   Handle(TDataStd_TreeNode) aF = aS->First();
   while (!aF.IsNull())
   {
-    aNb = theRelocTable.FindIndex(aF);
+    Standard_Integer aNb = theRelocTable.FindIndex(aF);
     if (aNb == 0)
     {
       aNb = theRelocTable.Add(aF);
diff --git a/tests/caf/basic/M4 b/tests/caf/basic/M4
new file mode 100755 (executable)
index 0000000..bc2fbb6
--- /dev/null
@@ -0,0 +1,133 @@
+puts "================"
+puts "OCC27192"
+puts "================"
+puts ""
+######################################################
+# Improvement of storage of Ocaf document in XML file format
+######################################################
+
+#pload FULL
+NewDocument M4 XmlOcaf
+
+# Simple array with many separators inside.
+SetExtStringArray M4 0:1 0 1 6
+set S1 "Hello 1"
+SetExtStringArrayValue M4 0:1 1 ${S1}
+set S2 "Hello_2"
+SetExtStringArrayValue M4 0:1 2 ${S2}
+set S3 "Hello*3"
+SetExtStringArrayValue M4 0:1 3 ${S3}
+set S4 "Hello-4"
+SetExtStringArrayValue M4 0:1 4 ${S4}
+set S5 "Hello5"
+SetExtStringArrayValue M4 0:1 5 ${S5}
+set Sempty ""
+SetExtStringArrayValue M4 0:1 6 ${Sempty}
+SetNode M4 0:1
+
+#An array with empty strings.
+SetExtStringArray M4 0:2 0 0 3
+SetExtStringArrayValue M4 0:2 0 ${Sempty}
+set SH "H"
+SetExtStringArrayValue M4 0:2 1 ${SH}
+SetExtStringArrayValue M4 0:2 2 ${Sempty}
+SetExtStringArrayValue M4 0:2 3 ${Sempty}
+SetNode M4 0:2
+AppendNode M4 0:1 0:2
+
+#An empty array.
+SetExtStringArray M4 0:3 0 0 0
+SetNode M4 0:3
+AppendNode M4 0:1 0:3
+
+#Save & Close.
+set aFile ${imagedir}/OCC27192.xml
+#
+file delete ${aFile}
+#
+if { [file exists ${aFile}] } {
+       puts "There is ${aFile} old file"
+       puts "OCC27192: ERROR (old file)"
+}
+#
+catch {SaveAs M4 ${aFile}}
+if { ![file exists ${aFile}] } {
+       puts "There is not ${aFile} file; SaveAs command: Error"
+       puts "OCC27192: ERROR (Save failed)"
+}
+Close M4
+
+#Open the document and check the values.
+catch {Open ${aFile} MM4}
+
+set IsGood 1
+
+#Check ExtStringArrays:
+#0:1
+set V1 [GetExtStringArrayValue MM4 0:1 1]
+if { ${V1} != ${S1} } {
+   set IsGood 0
+   puts "${V1}!=${S1}"
+}
+set V2 [GetExtStringArrayValue MM4 0:1 2]
+if { ${V2} != ${S2} } {
+   set IsGood 0
+   puts "${V2}!=${S2}"
+}
+set V3 [GetExtStringArrayValue MM4 0:1 3]
+if { ${V3} != ${S3} } {
+   set IsGood 0
+   puts "${V3}!=${S3}"
+}
+set V4 [GetExtStringArrayValue MM4 0:1 4]
+if { ${V4} != ${S4} } {
+   set IsGood 0
+   puts "${V4}!=${S4}"
+}
+set V5 [GetExtStringArrayValue MM4 0:1 5]
+if { ${V5} != ${S5} } {
+   set IsGood 0
+   puts "${V5}!=${S5}"
+}
+set V6 [GetExtStringArrayValue MM4 0:1 6]
+if { ${V6} != ${Sempty} } {
+   set IsGood 0
+   puts "${V6}!=${Sempty}"
+}
+
+#0:2
+set V7 [GetExtStringArrayValue MM4 0:2 0]
+if { ${V7} != ${Sempty} } {
+   set IsGood 0
+   puts "${V7}!=${Sempty}"
+}
+set V8 [GetExtStringArrayValue MM4 0:2 1]
+if { ${V8} != ${SH} } {
+   set IsGood 0
+   puts "${V8}!=${SH}"
+}
+set V9 [GetExtStringArrayValue MM4 0:2 2]
+if { ${V9} != ${Sempty} } {
+   set IsGood 0
+   puts "${V9}!=${Sempty}"
+}
+set V10 [GetExtStringArrayValue MM4 0:2 3]
+if { ${V10} != ${Sempty} } {
+   set IsGood 0
+   puts "${V10}!=${Sempty}"
+}
+
+#0:3
+set V11 [GetExtStringArrayValue MM4 0:3 0]
+if { ${V11} != ${Sempty} } {
+   set IsGood 0
+   puts "${V11}!=${Sempty}"
+}
+
+if { ${IsGood} == 0} {
+  puts "OCC27192: Error"
+} else {
+  puts "OCC27192: OK"
+}
+
+Close MM4