From e13b9464ef331b9a9d8a1caf2d11a31cab4bfdcd Mon Sep 17 00:00:00 2001 From: szy Date: Mon, 12 Mar 2018 17:50:08 +0300 Subject: [PATCH] 0029452: Application Framework - Failed to read an Ocaf XML document with 1.#QNAN value. Method XmlObjMgt::GetReal() is improved to (a) recognize NAN and infinity written by old MSVC runtime (like 1.#QNAN and 1.#INF) and (b) detect situation when there are some trailing non-space symbols after the real value, returning False in such case. Reading of real-valued attributes (single real, array, list) from OCAF XML format is improved to create valid attribute even if parsing of (some) members fails; warning is generated instead of error in such case. Added test bugs caf bug29452 --- .../XmlMDataStd_RealArrayDriver.cxx | 32 ++++++++------- src/XmlMDataStd/XmlMDataStd_RealDriver.cxx | 26 ++++++------ .../XmlMDataStd_RealListDriver.cxx | 30 +++++++------- src/XmlObjMgt/XmlObjMgt.cxx | 39 ++++++++++++++---- tests/bugs/caf/bug2269 | 2 +- tests/bugs/caf/bug29452 | 40 +++++++++++++++++++ 6 files changed, 116 insertions(+), 53 deletions(-) create mode 100644 tests/bugs/caf/bug29452 diff --git a/src/XmlMDataStd/XmlMDataStd_RealArrayDriver.cxx b/src/XmlMDataStd/XmlMDataStd_RealArrayDriver.cxx index 1fe199281e..bcc3c43fc8 100644 --- a/src/XmlMDataStd/XmlMDataStd_RealArrayDriver.cxx +++ b/src/XmlMDataStd/XmlMDataStd_RealArrayDriver.cxx @@ -62,10 +62,21 @@ Standard_Boolean XmlMDataStd_RealArrayDriver::Paste const Handle(TDF_Attribute)& theTarget, XmlObjMgt_RRelocationTable& ) const { - Standard_Integer aFirstInd, aLastInd, ind; - Standard_Real aValue; + + Handle(TDataStd_RealArray) aRealArray = Handle(TDataStd_RealArray)::DownCast(theTarget); const XmlObjMgt_Element& anElement = theSource; + // attribute id + Standard_GUID aGUID; + XmlObjMgt_DOMString aGUIDStr = anElement.getAttribute(::AttributeIDString()); + if (aGUIDStr.Type() == XmlObjMgt_DOMString::LDOM_NULL) + aGUID = TDataStd_RealArray::GetID(); //default case + else + aGUID = Standard_GUID(Standard_CString(aGUIDStr.GetString())); // user defined case + aRealArray->SetID(aGUID); + + Standard_Integer aFirstInd, aLastInd, ind; + // Read the FirstIndex; if the attribute is absent initialize to 1 XmlObjMgt_DOMString aFirstIndex= anElement.getAttribute(::FirstIndexString()); if (aFirstIndex == NULL) @@ -89,8 +100,6 @@ Standard_Boolean XmlMDataStd_RealArrayDriver::Paste return Standard_False; } - Handle(TDataStd_RealArray) aRealArray = - Handle(TDataStd_RealArray)::DownCast(theTarget); aRealArray->Init(aFirstInd, aLastInd); // Check the type of LDOMString @@ -109,6 +118,7 @@ Standard_Boolean XmlMDataStd_RealArrayDriver::Paste return Standard_False; } } else { + Standard_Real aValue; Standard_CString aValueStr = Standard_CString(aString.GetString()); for (ind = aFirstInd; ind <= aLastInd; ind++) { @@ -117,8 +127,9 @@ Standard_Boolean XmlMDataStd_RealArrayDriver::Paste TCollection_ExtendedString("Cannot retrieve real member" " for RealArray attribute as \"") + aValueStr + "\""; - myMessageDriver->Send (aMessageString, Message_Fail); - return Standard_False; + myMessageDriver->Send (aMessageString, Message_Warning); + // skip to the next space separator + while (*aValueStr != 0 && ! IsSpace (*aValueStr)) ++aValueStr; } aRealArray->SetValue(ind, aValue); } @@ -145,15 +156,6 @@ Standard_Boolean XmlMDataStd_RealArrayDriver::Paste #endif aRealArray->SetDelta(aDelta); - // attribute id - Standard_GUID aGUID; - XmlObjMgt_DOMString aGUIDStr = anElement.getAttribute(::AttributeIDString()); - if (aGUIDStr.Type() == XmlObjMgt_DOMString::LDOM_NULL) - aGUID = TDataStd_RealArray::GetID(); //default case - else - aGUID = Standard_GUID(Standard_CString(aGUIDStr.GetString())); // user defined case - - aRealArray->SetID(aGUID); return Standard_True; } diff --git a/src/XmlMDataStd/XmlMDataStd_RealDriver.cxx b/src/XmlMDataStd/XmlMDataStd_RealDriver.cxx index 2ccaad3ab1..cb1ac70429 100644 --- a/src/XmlMDataStd/XmlMDataStd_RealDriver.cxx +++ b/src/XmlMDataStd/XmlMDataStd_RealDriver.cxx @@ -53,20 +53,6 @@ Standard_Boolean XmlMDataStd_RealDriver::Paste const Handle(TDF_Attribute)& theTarget, XmlObjMgt_RRelocationTable& ) const { - Standard_Real aValue; - XmlObjMgt_DOMString aRealStr= XmlObjMgt::GetStringValue (theSource); - - if (XmlObjMgt::GetReal(aRealStr, aValue) == Standard_False) { - TCollection_ExtendedString aMessageString = - TCollection_ExtendedString("Cannot retrieve Real attribute from \"") - + aRealStr + "\""; - myMessageDriver->Send (aMessageString, Message_Fail); - return Standard_False; - } - - Handle(TDataStd_Real) anAtt = Handle(TDataStd_Real)::DownCast(theTarget); - anAtt->Set(aValue); - // attribute id Standard_GUID aGUID; const XmlObjMgt_Element& anElement = theSource; @@ -78,6 +64,18 @@ Standard_Boolean XmlMDataStd_RealDriver::Paste Handle(TDataStd_Real)::DownCast(theTarget)->SetID(aGUID); + Standard_Real aValue(0.); + const XmlObjMgt_DOMString& aRealStr= XmlObjMgt::GetStringValue (theSource); + Standard_CString aValueStr = Standard_CString (aRealStr.GetString()); + if(XmlObjMgt::GetReal(aRealStr, aValue) == Standard_False) { + TCollection_ExtendedString aMessageString = + TCollection_ExtendedString("Cannot retrieve Real attribute from \"") + + aValueStr + "\""; + myMessageDriver->Send (aMessageString, Message_Warning); + } + Handle(TDataStd_Real) anAtt = Handle(TDataStd_Real)::DownCast(theTarget); + anAtt->Set(aValue); + return Standard_True; } diff --git a/src/XmlMDataStd/XmlMDataStd_RealListDriver.cxx b/src/XmlMDataStd/XmlMDataStd_RealListDriver.cxx index c012a218a5..844f92692f 100644 --- a/src/XmlMDataStd/XmlMDataStd_RealListDriver.cxx +++ b/src/XmlMDataStd/XmlMDataStd_RealListDriver.cxx @@ -55,11 +55,20 @@ Standard_Boolean XmlMDataStd_RealListDriver::Paste(const XmlObjMgt_Persistent& const Handle(TDF_Attribute)& theTarget, XmlObjMgt_RRelocationTable& ) const { - Standard_Real aValue; - Standard_Integer aFirstInd, aLastInd, ind; + const Handle(TDataStd_RealList) aRealList = Handle(TDataStd_RealList)::DownCast(theTarget); const XmlObjMgt_Element& anElement = theSource; + // attribute id + Standard_GUID aGUID; + XmlObjMgt_DOMString aGUIDStr = anElement.getAttribute(::AttributeIDString()); + if (aGUIDStr.Type() == XmlObjMgt_DOMString::LDOM_NULL) + aGUID = TDataStd_RealList::GetID(); //default case + else + aGUID = Standard_GUID(Standard_CString(aGUIDStr.GetString())); // user defined case + aRealList->SetID(aGUID); + // Read the FirstIndex; if the attribute is absent initialize to 1 + Standard_Integer aFirstInd, aLastInd, ind; XmlObjMgt_DOMString aFirstIndex= anElement.getAttribute(::FirstIndexString()); if (aFirstIndex == NULL) aFirstInd = 1; @@ -84,7 +93,6 @@ Standard_Boolean XmlMDataStd_RealListDriver::Paste(const XmlObjMgt_Persistent& return Standard_False; } - const Handle(TDataStd_RealList) aRealList = Handle(TDataStd_RealList)::DownCast(theTarget); // Check the type of LDOMString const XmlObjMgt_DOMString& aString = XmlObjMgt::GetStringValue(anElement); if(aLastInd == 0) aFirstInd = 0; @@ -111,28 +119,20 @@ Standard_Boolean XmlMDataStd_RealListDriver::Paste(const XmlObjMgt_Persistent& Standard_CString aValueStr = Standard_CString(aString.GetString()); for (ind = aFirstInd; ind <= aLastInd; ind++) { + Standard_Real aValue; if (!XmlObjMgt::GetReal(aValueStr, aValue)) { TCollection_ExtendedString aMessageString = TCollection_ExtendedString("Cannot retrieve real member" " for RealList attribute as \"") + aValueStr + "\""; - myMessageDriver->Send (aMessageString, Message_Fail); - return Standard_False; + myMessageDriver->Send(aMessageString, Message_Warning); + // skip to the next space separator + while (*aValueStr != 0 && ! IsSpace (*aValueStr)) ++aValueStr; } aRealList->Append(aValue); } } - // attribute id - Standard_GUID aGUID; - XmlObjMgt_DOMString aGUIDStr = anElement.getAttribute(::AttributeIDString()); - if (aGUIDStr.Type() == XmlObjMgt_DOMString::LDOM_NULL) - aGUID = TDataStd_RealList::GetID(); //default case - else - aGUID = Standard_GUID(Standard_CString(aGUIDStr.GetString())); // user defined case - - aRealList->SetID(aGUID); - return Standard_True; } diff --git a/src/XmlObjMgt/XmlObjMgt.cxx b/src/XmlObjMgt/XmlObjMgt.cxx index 5544f2228b..dcb55ef4f9 100644 --- a/src/XmlObjMgt/XmlObjMgt.cxx +++ b/src/XmlObjMgt/XmlObjMgt.cxx @@ -23,6 +23,8 @@ #include #include +#include + static const char aRefPrefix [] = "/document/label"; static const char aRefElem1 [] = "/label[@tag="; static const char aRefElem2 [] = "]"; @@ -344,11 +346,37 @@ Standard_Boolean XmlObjMgt::GetReal (Standard_CString& theString, { char * ptr; errno = 0; - double aValue = Strtod (theString, &ptr); + theValue = Strtod (theString, &ptr); if (ptr == theString || errno == ERANGE || errno == EINVAL) return Standard_False; - theValue = Standard_Real (aValue); + theString = ptr; + + // detect NAN or infinite values written by old MSVC run-time as -1. with + // suffix "#QNAN" or "#SNAN" or "#INF" + if (*ptr == '#') + { + if (! strncmp (ptr, "#QNAN", 5) || ! strncmp (ptr, "#SNAN", 5)) + { + theString = ptr + 5; + theValue = std::numeric_limits::quiet_NaN(); + return Standard_True; + } + else if (! strncmp (ptr, "#INF", 4)) + { + theString = ptr + 4; + theValue = (theValue < 0 ? -std::numeric_limits::infinity() : std::numeric_limits::infinity()); + return Standard_True; + } + else + return Standard_False; + } + else if (*ptr && ! IsSpace (*ptr)) + { + // report failure if reading stopped not at the end of the string or space + return Standard_False; + } + return Standard_True; } @@ -371,13 +399,8 @@ Standard_Boolean XmlObjMgt::GetReal (const XmlObjMgt_DOMString& theString, } default: // LDOM_Ascii* { - char * ptr; const char * aString = theString.GetString(); - errno = 0; - double aValue = Strtod (aString, &ptr); - if (ptr == aString || errno == ERANGE || errno == EINVAL) - return Standard_False; - theValue = Standard_Real (aValue); + return GetReal (aString, theValue); } } return Standard_True; diff --git a/tests/bugs/caf/bug2269 b/tests/bugs/caf/bug2269 index a0cbe3ffc8..ae03d73fd2 100644 --- a/tests/bugs/caf/bug2269 +++ b/tests/bugs/caf/bug2269 @@ -1,4 +1,4 @@ -puts "REQUIRED All: XmlDriver warning: failure reading attribute TDataStd_RealArray" +puts "REQUIRED All: Cannot retrieve real member for RealArray attribute" puts "================" puts "OCC2269" diff --git a/tests/bugs/caf/bug29452 b/tests/bugs/caf/bug29452 new file mode 100644 index 0000000000..fc4d6a51a4 --- /dev/null +++ b/tests/bugs/caf/bug29452 @@ -0,0 +1,40 @@ +puts "==========" +puts "OCC29452" +puts "==========" +puts "" +################################################### +# XmlMDataStd_RealDriver: Failed to read an Ocaf XML document with 1.#QNAN value +################################################### + +# Check for presence of warning message +puts "REQUIRED ALL: Cannot retrieve real member for RealArray attribute" + +set BugNumber OCC29452 +set file [locate_data_file bug29452.xml] + +catch {Close D} +set res [Open $file D] + +set real [GetReal D 0:1] +set rlst [GetRealList D 0:1] +set rarr [GetRealArray D 0:1] + +# Check for read values +checkreal "Real value" [lindex $rlst 0] 1.1 0 1e-15 +checkreal "Real value" [lindex $rlst 2] 3.3 0 1e-15 +checkreal "Real value" [lindex $rarr 0] 0.111 0 1e-15 +checkreal "Real value" [lindex $rarr 3] 123. 0 1e-15 +checkreal "Real value" [lindex $rarr 4] 3.14e12 0 1e-15 +foreach inf [list $real [lindex $rlst 3]] { + if { [string compare "$inf" "inf"] && + [string compare "$inf" "infinity"] && + [string compare "$inf" "1.#INF"] } { + puts "Error: Real value is read as \"$inf\", expected infinity" + } +} +foreach nan [list [lindex $rlst 1] [lindex $rarr 1] [lindex $rarr 2]] { + if { [string compare "$nan" "nan"] && + [string compare "$nan" "1.#QNAN"] } { + puts "Error: Real value is read as \"$nan\", expected NAN" + } +}