1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-07 18:30:55 +03:00
occt/src/XmlMDF/XmlMDF.cxx
abv 60fddce474 0029669: Crash on opening a document with same Ocaf attributes with different IDs
Added protection against clash of attributes with the same GUID when more than one attribute of the same type but with different GUIDs are stored in the file.
If attribute with default GUID has already been read, then adding next empty attribute of the same type (done at start of its reading) will fail; in such case another attempt is made with Null GUID.
2018-05-25 21:55:00 +03:00

351 lines
12 KiB
C++

// Created on: 2001-07-09
// Created by: Julia DOROVSKIKH
// Copyright (c) 2001-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <Message_Messenger.hxx>
#include <Storage_Schema.hxx>
#include <TColStd_MapOfTransient.hxx>
#include <TDF_Attribute.hxx>
#include <TDF_AttributeIterator.hxx>
#include <TDF_ChildIterator.hxx>
#include <TDF_Data.hxx>
#include <TDF_Label.hxx>
#include <TDF_TagSource.hxx>
#include <TDF_Tool.hxx>
#include <XmlMDF.hxx>
#include <XmlMDF_ADriver.hxx>
#include <XmlMDF_ADriverTable.hxx>
#include <XmlMDF_DataMapIteratorOfTypeADriverMap.hxx>
#include <XmlMDF_ReferenceDriver.hxx>
#include <XmlMDF_TagSourceDriver.hxx>
#include <XmlObjMgt_Document.hxx>
#include <XmlObjMgt_DOMString.hxx>
#include <XmlObjMgt_Persistent.hxx>
#include <XmlLDrivers.hxx>
#include <TDocStd_Owner.hxx>
#include <TDocStd_Document.hxx>
#include <Standard_GUID.hxx>
IMPLEMENT_DOMSTRING (TagString, "tag")
IMPLEMENT_DOMSTRING (LabelString, "label")
#define DATATYPE_MIGRATION
//#define DATATYPE_MIGRATION_DEB
//=======================================================================
//function : UnsuppTypesMap
//purpose :
//=======================================================================
static TColStd_MapOfTransient& UnsuppTypesMap ()
{
static TColStd_MapOfTransient anUnsuppTypes;
return anUnsuppTypes;
}
//=======================================================================
//function : FromTo
//purpose : Paste transient data into DOM_Element
//=======================================================================
void XmlMDF::FromTo (const Handle(TDF_Data)& theData,
XmlObjMgt_Element& theElement,
XmlObjMgt_SRelocationTable& theRelocTable,
const Handle(XmlMDF_ADriverTable)& theDrivers)
{
UnsuppTypesMap().Clear();
// Standard_Integer count =
WriteSubTree(theData->Root(), theElement, theRelocTable, theDrivers);
UnsuppTypesMap().Clear();
}
//=======================================================================
//function : WriteSubTree
//purpose :
//=======================================================================
Standard_Integer XmlMDF::WriteSubTree
(const TDF_Label& theLabel,
XmlObjMgt_Element& theElement,
XmlObjMgt_SRelocationTable& theRelocTable,
const Handle(XmlMDF_ADriverTable)& theDrivers)
{
XmlObjMgt_Document aDoc = theElement.getOwnerDocument();
// create element "label"
XmlObjMgt_Element aLabElem = aDoc.createElement (::LabelString());
// Extraction of the driver subset.
const XmlMDF_TypeADriverMap& aDriverMap = theDrivers->GetDrivers();
// write attributes
Standard_Integer count = 0;
TDF_AttributeIterator itr1 (theLabel);
for ( ; itr1.More(); itr1.Next())
{
const Handle(TDF_Attribute)& tAtt = itr1.Value();
const Handle(Standard_Type)& aType = tAtt->DynamicType();
if (aDriverMap.IsBound (aType))
{
const Handle(XmlMDF_ADriver)& aDriver = aDriverMap.Find (aType);
count++;
// Add source to relocation table
Standard_Integer anId = theRelocTable.Add (tAtt);
// Create DOM data item
XmlObjMgt_Persistent pAtt;
// In the document version 8 the attribute TPrsStd_AISPresentation
// was replaced by TDataXtd_Presentation. Therefore, for old versions
// we write old name of the attribute (TPrsStd_AISPresentation).
Standard_CString typeName = aDriver->TypeName().ToCString();
if (XmlLDrivers::StorageVersion() < 8 &&
strcmp(typeName, "TDataXtd_Presentation") == 0)
{
typeName = "TPrsStd_AISPresentation";
}
pAtt.CreateElement (aLabElem, typeName, anId);
// Paste
aDriver -> Paste (tAtt, pAtt, theRelocTable);
}
#ifdef OCCT_DEBUG
else if (!UnsuppTypesMap().Contains (aType))
{
cout << "attribute driver for type "<< aType -> Name()<< " not found"<< endl;
UnsuppTypesMap().Add (aType);
}
#endif
}
// write sub-labels
TDF_ChildIterator itr2 (theLabel);
for ( ; itr2.More(); itr2.Next())
{
const TDF_Label& aChildLab = itr2.Value();
count += WriteSubTree(aChildLab, aLabElem, theRelocTable, theDrivers);
}
if (count > 0 || TDocStd_Owner::GetDocument(theLabel.Data())->EmptyLabelsSavingMode())
{
theElement.appendChild(aLabElem);
// set attribute "tag"
aLabElem.setAttribute (::TagString(), theLabel.Tag());
}
return count;
}
//=======================================================================
//function : FromTo
//purpose : Paste data from DOM_Element into transient document
//=======================================================================
Standard_Boolean XmlMDF::FromTo (const XmlObjMgt_Element& theElement,
Handle(TDF_Data)& theData,
XmlObjMgt_RRelocationTable& theRelocTable,
const Handle(XmlMDF_ADriverTable)& theDrivers)
{
TDF_Label aRootLab = theData->Root();
XmlMDF_MapOfDriver aDriverMap;
CreateDrvMap (theDrivers, aDriverMap);
Standard_Integer count = 0;
LDOM_Node theNode = theElement.getFirstChild();
XmlObjMgt_Element anElem = (const XmlObjMgt_Element&)theNode;
while ( !anElem.isNull() )
{
if ( anElem.getNodeName().equals (::LabelString()) )
{
Standard_Integer subcount =
ReadSubTree(anElem, aRootLab, theRelocTable, aDriverMap);
// check for error
if (subcount < 0)
return Standard_False;
count += subcount;
}
//anElem = (const XmlObjMgt_Element &) anElem.getNextSibling();
LDOM_Node theNode1 = anElem.getNextSibling();
anElem = (const XmlObjMgt_Element &) theNode1;
}
return Standard_True;
}
//=======================================================================
//function : ReadSubTree
//purpose :
//=======================================================================
Standard_Integer XmlMDF::ReadSubTree (const XmlObjMgt_Element& theElement,
const TDF_Label& theLabel,
XmlObjMgt_RRelocationTable& theRelocTable,
const XmlMDF_MapOfDriver& theDriverMap)
{
// Extraction of the driver subset.
Standard_Integer count = 0;
//XmlObjMgt_Element anElem = (const XmlObjMgt_Element &) theElement.getFirstChild();
LDOM_Node theNode = theElement.getFirstChild();
XmlObjMgt_Element anElem = (const XmlObjMgt_Element &) theNode;
while ( !anElem.isNull() )
{
if ( anElem.getNodeType() == LDOM_Node::ELEMENT_NODE )
{
if ( anElem.getNodeName().equals (::LabelString()) )
{
// read tag
Standard_Integer tag;
XmlObjMgt_DOMString aTag (anElem.getAttribute(::TagString()));
if ( !aTag.GetInteger (tag) ) {
TCollection_ExtendedString anErrorMessage =
TCollection_ExtendedString ("Wrong Tag value for OCAF Label: ")
+ aTag;
theDriverMap.Find("TDF_TagSource") -> myMessageDriver->Send (anErrorMessage, Message_Fail);
return -1;
}
// create label
TDF_Label aLab = theLabel.FindChild(tag, Standard_True);
// read sub-tree
Standard_Integer subcount =
ReadSubTree(anElem, aLab, theRelocTable, theDriverMap);
// check for error
if (subcount == -1)
return -1;
count += subcount;
}
else
{
// read attribute
XmlObjMgt_DOMString aName = anElem.getNodeName();
#ifdef DATATYPE_MIGRATION
TCollection_AsciiString newName;
if(Storage_Schema::CheckTypeMigration(aName, newName)) {
#ifdef OCCT_DEBUG
cout << "CheckTypeMigration:OldType = " <<aName.GetString() << " Len = "<<strlen(aName.GetString())<<endl;
cout << "CheckTypeMigration:NewType = " <<newName << " Len = "<< newName.Length()<<endl;
#endif
aName = newName.ToCString();
}
#endif
if (theDriverMap.IsBound (aName))
{
count++;
const Handle(XmlMDF_ADriver)& driver = theDriverMap.Find(aName);
XmlObjMgt_Persistent pAtt (anElem);
Standard_Integer anID = pAtt.Id ();
if (anID <= 0) { // check for ID validity
TCollection_ExtendedString anErrorMessage =
TCollection_ExtendedString("Wrong ID of OCAF attribute with type ")
+ aName;
driver -> myMessageDriver->Send (anErrorMessage, Message_Fail);
return -1;
}
Handle(TDF_Attribute) tAtt;
Standard_Boolean isBound = theRelocTable.IsBound(anID);
if (isBound)
tAtt = Handle(TDF_Attribute)::DownCast(theRelocTable.Find(anID));
else
tAtt = driver -> NewEmpty();
if (tAtt->Label().IsNull())
{
try
{
theLabel.AddAttribute (tAtt);
}
catch (const Standard_DomainError&)
{
// For attributes that can have arbitrary GUID (e.g. TDataStd_Integer), exception
// will be raised in valid case if attribute of that type with default GUID is already
// present on the same label; the reason is that actual GUID will be read later.
// To avoid this, set invalid (null) GUID to the newly added attribute (see #29669)
static const Standard_GUID fbidGuid;
tAtt->SetID (fbidGuid);
theLabel.AddAttribute (tAtt);
}
}
else
driver->myMessageDriver->Send
(TCollection_ExtendedString("XmlDriver warning: ") +
"attempt to attach attribute " +
aName + " to a second label", Message_Warning);
if (! driver -> Paste (pAtt, tAtt, theRelocTable))
{
// error converting persistent to transient
driver->myMessageDriver->Send
(TCollection_ExtendedString("XmlDriver warning: ") +
"failure reading attribute " + aName, Message_Warning);
}
else if (isBound == Standard_False)
theRelocTable.Bind (anID, tAtt);
}
#ifdef OCCT_DEBUG
else
{
const TCollection_AsciiString anAsciiName = aName;
cerr << "XmlDriver warning: "
<< "label contains object of unknown type "<< anAsciiName<< endl;
}
#endif
}
}
//anElem = (const XmlObjMgt_Element &) anElem.getNextSibling();
LDOM_Node theNode1 = anElem.getNextSibling();
anElem = (const XmlObjMgt_Element &) theNode1;
}
// AfterRetrieval
if (count > 0)
{
}
return count;
}
//=======================================================================
//function : AddDrivers
//purpose :
//=======================================================================
void XmlMDF::AddDrivers (const Handle(XmlMDF_ADriverTable)& aDriverTable,
const Handle(Message_Messenger)& aMessageDriver)
{
aDriverTable->AddDriver (new XmlMDF_TagSourceDriver(aMessageDriver));
aDriverTable->AddDriver (new XmlMDF_ReferenceDriver(aMessageDriver));
}
//=======================================================================
//function : CreateDrvMap
//purpose :
//=======================================================================
void XmlMDF::CreateDrvMap (const Handle(XmlMDF_ADriverTable)& theDrivers,
XmlMDF_MapOfDriver& theAsciiDriverMap)
{
const XmlMDF_TypeADriverMap& aDriverMap = theDrivers->GetDrivers();
XmlMDF_DataMapIteratorOfTypeADriverMap anIter (aDriverMap);
while (anIter.More()) {
const Handle(XmlMDF_ADriver)& aDriver = anIter.Value();
const TCollection_AsciiString aTypeName = aDriver -> TypeName();
if (theAsciiDriverMap.IsBound (aTypeName) == Standard_False)
theAsciiDriverMap.Bind (aTypeName, aDriver);
else
aDriver -> myMessageDriver->Send
(TCollection_ExtendedString ("Warning: skipped driver name: \"")
+ aTypeName + '\"', Message_Warning);
anIter.Next();
}
}