From e9947e12bc7845d666aadee10bcb9936882a4810 Mon Sep 17 00:00:00 2001 From: vro Date: Wed, 24 Feb 2016 10:35:52 +0300 Subject: [PATCH] 0027192: Improvement of storage of Ocaf document in XML file format Improvement of code in XmlMDataStd_ExtStringArrayDriver.cxx Corrected test-script --- src/DDataStd/DDataStd_BasicCommands.cxx | 2 +- .../XmlMDataStd_ExtStringArrayDriver.cxx | 203 +++++++++++++++--- .../XmlMDataStd_TreeNodeDriver.cxx | 20 +- tests/caf/basic/M4 | 133 ++++++++++++ 4 files changed, 323 insertions(+), 35 deletions(-) create mode 100755 tests/caf/basic/M4 diff --git a/src/DDataStd/DDataStd_BasicCommands.cxx b/src/DDataStd/DDataStd_BasicCommands.cxx index 732d161eb2..8580899f44 100644 --- a/src/DDataStd/DDataStd_BasicCommands.cxx +++ b/src/DDataStd/DDataStd_BasicCommands.cxx @@ -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; diff --git a/src/XmlMDataStd/XmlMDataStd_ExtStringArrayDriver.cxx b/src/XmlMDataStd/XmlMDataStd_ExtStringArrayDriver.cxx index 8ed9f9309d..42ab8da321 100644 --- a/src/XmlMDataStd/XmlMDataStd_ExtStringArrayDriver.cxx +++ b/src/XmlMDataStd/XmlMDataStd_ExtStringArrayDriver.cxx @@ -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 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 + + // Set value for the array. + aExtStringArray->SetValue(ind, xvalue); + + // Next string-value. + isym = iend + 1; + } } - XmlObjMgt::GetExtendedString( *aCurElement, aValueStr ); - aExtStringArray->SetValue( aLastInd, aValueStr ); - + // 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()); - - for ( Standard_Integer i = aL; i <= anU; i++ ) + // 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++) { - TCollection_ExtendedString aValueStr = aExtStringArray->Value( i ); - XmlObjMgt_Element aCurTarget = aDoc.createElement( ::ExtString() ); - XmlObjMgt::SetExtendedString( aCurTarget, aValueStr ); - anElement.appendChild( aCurTarget ); + 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++; + } + } + } + } + + if (found) + { + // 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); } } diff --git a/src/XmlMDataStd/XmlMDataStd_TreeNodeDriver.cxx b/src/XmlMDataStd/XmlMDataStd_TreeNodeDriver.cxx index a50848a5c8..3e906b660a 100644 --- a/src/XmlMDataStd/XmlMDataStd_TreeNodeDriver.cxx +++ b/src/XmlMDataStd/XmlMDataStd_TreeNodeDriver.cxx @@ -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 index 0000000000..bc2fbb6e4b --- /dev/null +++ b/tests/caf/basic/M4 @@ -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