0033661: Data Exchange, Step Import - Tessellated GDTs are not imported
[occt.git] / src / XmlMDF / XmlMDF.cxx
1 // Created on: 2001-07-09
2 // Created by: Julia DOROVSKIKH
3 // Copyright (c) 2001-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16
17 #include <Message_Messenger.hxx>
18 #include <Message_ProgressScope.hxx>
19 #include <Storage_Schema.hxx>
20 #include <TColStd_MapOfTransient.hxx>
21 #include <TDF_AttributeIterator.hxx>
22 #include <TDF_ChildIterator.hxx>
23 #include <TDF_Data.hxx>
24 #include <TDF_Label.hxx>
25 #include <TDF_Tool.hxx>
26 #include <XmlMDF.hxx>
27 #include <XmlMDF_ADriver.hxx>
28 #include <XmlMDF_ADriverTable.hxx>
29 #include <XmlMDF_ReferenceDriver.hxx>
30 #include <XmlMDF_TagSourceDriver.hxx>
31 #include <XmlObjMgt_Document.hxx>
32 #include <XmlObjMgt_Persistent.hxx>
33 #include <TDocStd_Owner.hxx>
34 #include <TDocStd_Document.hxx>
35 #include <Standard_GUID.hxx>
36
37 IMPLEMENT_DOMSTRING (TagString,         "tag")
38 IMPLEMENT_DOMSTRING (LabelString,       "label")
39 #define DATATYPE_MIGRATION
40 //#define DATATYPE_MIGRATION_DEB
41 //=======================================================================
42 //function : UnsuppTypesMap
43 //purpose  : 
44 //=======================================================================
45
46 static TColStd_MapOfTransient& UnsuppTypesMap ()
47 {
48   static TColStd_MapOfTransient anUnsuppTypes;
49   return anUnsuppTypes;
50 }
51
52 //=======================================================================
53 //function : FromTo
54 //purpose  : Paste transient data into DOM_Element
55 //=======================================================================
56 void XmlMDF::FromTo (const Handle(TDF_Data)&             theData,
57                      XmlObjMgt_Element&                  theElement,
58                      XmlObjMgt_SRelocationTable&         theRelocTable,
59                      const Handle(XmlMDF_ADriverTable)&  theDrivers,
60                      const Message_ProgressRange&        theRange)
61 {
62   UnsuppTypesMap().Clear();
63 //  Standard_Integer count =
64   WriteSubTree(theData->Root(), theElement, theRelocTable, theDrivers, theRange);
65   UnsuppTypesMap().Clear();
66 }
67
68 //=======================================================================
69 //function : WriteSubTree
70 //purpose  : 
71 //=======================================================================
72 Standard_Integer XmlMDF::WriteSubTree
73                       (const TDF_Label&                    theLabel,
74                        XmlObjMgt_Element&                  theElement,
75                        XmlObjMgt_SRelocationTable&         theRelocTable,
76                        const Handle(XmlMDF_ADriverTable)&  theDrivers,
77                        const Message_ProgressRange&        theRange)
78 {
79   XmlObjMgt_Document aDoc = theElement.getOwnerDocument();
80
81   // create element "label"
82   XmlObjMgt_Element aLabElem = aDoc.createElement (::LabelString());
83
84   // write attributes
85   Standard_Integer count = 0;
86   TDF_AttributeIterator itr1 (theLabel);
87   for ( ; itr1.More(); itr1.Next())
88   {
89     const Handle(TDF_Attribute)& tAtt = itr1.Value();
90     const Handle(Standard_Type)& aType = tAtt->DynamicType();
91     Handle(XmlMDF_ADriver) aDriver;
92     if (theDrivers->GetDriver(aType, aDriver))
93     {
94       count++;
95
96       //    Add source to relocation table
97       Standard_Integer anId      = theRelocTable.Add (tAtt);
98
99       //    Create DOM data item
100       XmlObjMgt_Persistent pAtt;
101       // In the document version 8 the attribute TPrsStd_AISPresentation
102       // was replaced by TDataXtd_Presentation. Therefore, for old versions
103       // we write old name of the attribute (TPrsStd_AISPresentation).
104       Standard_CString typeName = aDriver->TypeName().ToCString();
105       if (theRelocTable.GetHeaderData()->StorageVersion().IntegerValue() < TDocStd_FormatVersion_VERSION_8 &&
106           strcmp(typeName, "TDataXtd_Presentation") == 0)
107       {
108         typeName = "TPrsStd_AISPresentation";
109       }
110       pAtt.CreateElement (aLabElem, typeName, anId);
111
112       //    Paste
113       aDriver -> Paste (tAtt, pAtt, theRelocTable);
114     }
115 #ifdef OCCT_DEBUG
116     else if (!UnsuppTypesMap().Contains (aType))
117     {
118       std::cout << "attribute driver for type "<< aType -> Name()<< " not found"<< std::endl;
119       UnsuppTypesMap().Add (aType);
120     }
121 #endif
122   }
123
124   // write sub-labels
125   TDF_ChildIterator itr2 (theLabel);
126   Standard_Real child_count = 0;
127   for (; itr2.More(); ++child_count, itr2.Next())
128   {
129   }
130   itr2.Initialize(theLabel);
131   Message_ProgressScope aPS(theRange, "Writing sub-tree", child_count, true);
132   for ( ; itr2.More() && aPS.More(); itr2.Next())
133   {
134     const TDF_Label& aChildLab = itr2.Value();
135     count += WriteSubTree(aChildLab, aLabElem, theRelocTable, theDrivers, aPS.Next());
136   }
137
138   if (count > 0 || TDocStd_Owner::GetDocument(theLabel.Data())->EmptyLabelsSavingMode())
139   {
140     theElement.appendChild(aLabElem);
141
142     // set attribute "tag"
143     aLabElem.setAttribute (::TagString(), theLabel.Tag());
144   }
145   return count;
146 }
147
148 //=======================================================================
149 //function : FromTo
150 //purpose  : Paste data from DOM_Element into transient document
151 //=======================================================================
152 Standard_Boolean XmlMDF::FromTo (const XmlObjMgt_Element&           theElement,
153                                  Handle(TDF_Data)&                  theData,
154                                  XmlObjMgt_RRelocationTable&        theRelocTable,
155                                  const Handle(XmlMDF_ADriverTable)& theDrivers, 
156                                  const Message_ProgressRange&       theRange)
157 {
158   TDF_Label aRootLab = theData->Root();
159   XmlMDF_MapOfDriver aDriverMap;
160   theDrivers->CreateDrvMap (aDriverMap);
161
162   Standard_Integer count = 0;
163
164   LDOM_Node theNode = theElement.getFirstChild();
165   XmlObjMgt_Element anElem = (const XmlObjMgt_Element&)theNode;
166   while ( !anElem.isNull() )
167   {
168     if ( anElem.getNodeName().equals (::LabelString()) )
169     {
170       Standard_Integer subcount =
171         ReadSubTree(anElem, aRootLab, theRelocTable, aDriverMap, theRange);
172       // check for error
173       if (subcount < 0)
174         return Standard_False;
175
176       (void )count; // unused but set for debug
177       count += subcount;
178     }
179     //anElem = (const XmlObjMgt_Element &) anElem.getNextSibling();
180     LDOM_Node theNode1 = anElem.getNextSibling();
181     anElem = (const XmlObjMgt_Element &) theNode1;
182   }
183
184   return Standard_True;
185 }
186
187 //=======================================================================
188 //function : ReadSubTree
189 //purpose  : 
190 //=======================================================================
191 Standard_Integer XmlMDF::ReadSubTree (const XmlObjMgt_Element&     theElement,
192                                       const TDF_Label&             theLabel,
193                                       XmlObjMgt_RRelocationTable&  theRelocTable,
194                                       const XmlMDF_MapOfDriver&    theDriverMap, 
195                                       const Message_ProgressRange& theRange)
196 {
197   // Extraction of the driver subset.
198   Standard_Integer count = 0;
199
200   //XmlObjMgt_Element anElem = (const XmlObjMgt_Element &) theElement.getFirstChild();
201   LDOM_Node theNode = theElement.getFirstChild();
202   XmlObjMgt_Element anElem = (const XmlObjMgt_Element &) theNode;
203   Message_ProgressScope aPS(theRange, "Reading sub-tree", 2, true);
204   while ( !anElem.isNull() )
205   {
206     if ( anElem.getNodeType() == LDOM_Node::ELEMENT_NODE )
207     {
208       if ( anElem.getNodeName().equals (::LabelString()) )
209       {
210         // read tag
211         Standard_Integer tag;
212         XmlObjMgt_DOMString aTag (anElem.getAttribute(::TagString()));
213         if ( !aTag.GetInteger (tag) ) {
214           TCollection_ExtendedString anErrorMessage =
215             TCollection_ExtendedString ("Wrong Tag value for OCAF Label: ")
216               + aTag;
217           theDriverMap.Find("TDF_TagSource") -> myMessageDriver->Send (anErrorMessage, Message_Fail);
218           return -1;
219         }
220         // create label
221         TDF_Label aLab = theLabel.FindChild(tag, Standard_True);
222
223         // read sub-tree
224         Standard_Integer subcount =
225           ReadSubTree(anElem, aLab, theRelocTable, theDriverMap, aPS.Next());
226         // check for error
227         if (subcount == -1)
228           return -1;
229         count += subcount;
230       }
231       else
232       {
233         // read attribute
234         XmlObjMgt_DOMString aName = anElem.getNodeName();
235
236 #ifdef DATATYPE_MIGRATION
237         TCollection_AsciiString  newName;       
238         if(Storage_Schema::CheckTypeMigration(aName, newName)) {
239 #ifdef OCCT_DEBUG
240           std::cout << "CheckTypeMigration:OldType = " <<aName.GetString() << " Len = "<<strlen(aName.GetString())<<std::endl;
241           std::cout << "CheckTypeMigration:NewType = " <<newName  << " Len = "<< newName.Length()<<std::endl;
242 #endif
243           aName = newName.ToCString();
244         }
245 #endif  
246        
247         if (theDriverMap.IsBound (aName))
248         {
249           count++;
250           const Handle(XmlMDF_ADriver)& driver = theDriverMap.Find(aName);
251           XmlObjMgt_Persistent pAtt (anElem);
252           Standard_Integer anID = pAtt.Id ();
253           if (anID <= 0) {      // check for ID validity
254             TCollection_ExtendedString anErrorMessage =
255              TCollection_ExtendedString("Wrong ID of OCAF attribute with type ")
256                + aName;
257             driver -> myMessageDriver->Send (anErrorMessage, Message_Fail);
258             return -1;
259           }
260           Handle(TDF_Attribute) tAtt;
261           Standard_Boolean isBound = theRelocTable.IsBound(anID);
262           if (isBound)
263             tAtt = Handle(TDF_Attribute)::DownCast(theRelocTable.Find(anID));
264           else
265             tAtt = driver -> NewEmpty();
266
267           if (tAtt->Label().IsNull())
268           {
269             try
270             {
271               theLabel.AddAttribute (tAtt);
272             }
273             catch (const Standard_DomainError&)
274             {
275               // For attributes that can have arbitrary GUID (e.g. TDataStd_Integer), exception
276               // will be raised in valid case if attribute of that type with default GUID is already
277               // present  on the same label; the reason is that actual GUID will be read later.
278               // To avoid this, set invalid (null) GUID to the newly added attribute (see #29669)
279               static const Standard_GUID fbidGuid;
280               tAtt->SetID (fbidGuid);
281               theLabel.AddAttribute (tAtt);
282             }
283           }
284           else
285             driver->myMessageDriver->Send
286               (TCollection_ExtendedString("XmlDriver warning: ") +
287                "attempt to attach attribute " +
288                aName + " to a second label", Message_Warning);
289
290           if (! driver -> Paste (pAtt, tAtt, theRelocTable))
291           {
292             // error converting persistent to transient
293             driver->myMessageDriver->Send
294               (TCollection_ExtendedString("XmlDriver warning: ") +
295                "failure reading attribute " + aName, Message_Warning);
296           }
297           else if (isBound == Standard_False)
298             theRelocTable.Bind (anID, tAtt);
299         }
300 #ifdef OCCT_DEBUG
301         else
302         {
303           const TCollection_AsciiString anAsciiName = aName;
304           std::cerr << "XmlDriver warning: "
305                << "label contains object of unknown type "<< anAsciiName<< std::endl;
306         }
307 #endif
308       }
309     }
310     //anElem = (const XmlObjMgt_Element &) anElem.getNextSibling();
311     LDOM_Node theNode1 = anElem.getNextSibling();
312     anElem = (const XmlObjMgt_Element &) theNode1;
313
314     if (!aPS.More())
315         return -1;
316   }
317
318   // AfterRetrieval
319   if (count > 0)
320   {
321   }
322
323   return count;
324 }
325
326 //=======================================================================
327 //function : AddDrivers
328 //purpose  : 
329 //=======================================================================
330 void XmlMDF::AddDrivers (const Handle(XmlMDF_ADriverTable)& aDriverTable,
331                          const Handle(Message_Messenger)&   aMessageDriver)
332 {
333   aDriverTable->AddDriver (new XmlMDF_TagSourceDriver(aMessageDriver)); 
334   aDriverTable->AddDriver (new XmlMDF_ReferenceDriver(aMessageDriver));
335 }