da434e52696edefa69d365b7344392e4137a4f7e
[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 <Storage_Schema.hxx>
19 #include <TColStd_MapOfTransient.hxx>
20 #include <TDF_Attribute.hxx>
21 #include <TDF_AttributeIterator.hxx>
22 #include <TDF_ChildIterator.hxx>
23 #include <TDF_Data.hxx>
24 #include <TDF_Label.hxx>
25 #include <TDF_TagSource.hxx>
26 #include <TDF_Tool.hxx>
27 #include <XmlMDF.hxx>
28 #include <XmlMDF_ADriver.hxx>
29 #include <XmlMDF_ADriverTable.hxx>
30 #include <XmlMDF_DataMapIteratorOfTypeADriverMap.hxx>
31 #include <XmlMDF_ReferenceDriver.hxx>
32 #include <XmlMDF_TagSourceDriver.hxx>
33 #include <XmlObjMgt_Document.hxx>
34 #include <XmlObjMgt_DOMString.hxx>
35 #include <XmlObjMgt_Persistent.hxx>
36 #include <XmlLDrivers.hxx>
37 #include <TDocStd_Owner.hxx>
38 #include <TDocStd_Document.hxx>
39 #include <Standard_GUID.hxx>
40
41 IMPLEMENT_DOMSTRING (TagString,         "tag")
42 IMPLEMENT_DOMSTRING (LabelString,       "label")
43 #define DATATYPE_MIGRATION
44 //#define DATATYPE_MIGRATION_DEB
45 //=======================================================================
46 //function : UnsuppTypesMap
47 //purpose  : 
48 //=======================================================================
49
50 static TColStd_MapOfTransient& UnsuppTypesMap ()
51 {
52   static TColStd_MapOfTransient anUnsuppTypes;
53   return anUnsuppTypes;
54 }
55
56 //=======================================================================
57 //function : FromTo
58 //purpose  : Paste transient data into DOM_Element
59 //=======================================================================
60 void XmlMDF::FromTo (const Handle(TDF_Data)&             theData,
61                      XmlObjMgt_Element&                  theElement,
62                      XmlObjMgt_SRelocationTable&         theRelocTable,
63                      const Handle(XmlMDF_ADriverTable)&  theDrivers)
64 {
65   UnsuppTypesMap().Clear();
66 //  Standard_Integer count =
67   WriteSubTree(theData->Root(), theElement, theRelocTable, theDrivers);
68   UnsuppTypesMap().Clear();
69 }
70
71 //=======================================================================
72 //function : WriteSubTree
73 //purpose  : 
74 //=======================================================================
75 Standard_Integer XmlMDF::WriteSubTree
76                       (const TDF_Label&                    theLabel,
77                        XmlObjMgt_Element&                  theElement,
78                        XmlObjMgt_SRelocationTable&         theRelocTable,
79                        const Handle(XmlMDF_ADriverTable)&  theDrivers)
80 {
81   XmlObjMgt_Document aDoc = theElement.getOwnerDocument();
82
83   // create element "label"
84   XmlObjMgt_Element aLabElem = aDoc.createElement (::LabelString());
85
86   // Extraction of the driver subset.
87   const XmlMDF_TypeADriverMap& aDriverMap = theDrivers->GetDrivers();
88
89   // write attributes
90   Standard_Integer count = 0;
91   TDF_AttributeIterator itr1 (theLabel);
92   for ( ; itr1.More(); itr1.Next())
93   {
94     const Handle(TDF_Attribute)& tAtt = itr1.Value();
95     const Handle(Standard_Type)& aType = tAtt->DynamicType();
96     if (aDriverMap.IsBound (aType))
97     {
98       const Handle(XmlMDF_ADriver)& aDriver = aDriverMap.Find (aType);
99       count++;
100
101       //    Add source to relocation table
102       Standard_Integer anId      = theRelocTable.Add (tAtt);
103
104       //    Create DOM data item
105       XmlObjMgt_Persistent pAtt;
106       // In the document version 8 the attribute TPrsStd_AISPresentation
107       // was replaced by TDataXtd_Presentation. Therefore, for old versions
108       // we write old name of the attribute (TPrsStd_AISPresentation).
109       Standard_CString typeName = aDriver->TypeName().ToCString();
110       if (XmlLDrivers::StorageVersion() < 8 &&
111           strcmp(typeName, "TDataXtd_Presentation") == 0)
112       {
113         typeName = "TPrsStd_AISPresentation";
114       }
115       pAtt.CreateElement (aLabElem, typeName, anId);
116
117       //    Paste
118       aDriver -> Paste (tAtt, pAtt, theRelocTable);
119     }
120 #ifdef OCCT_DEBUG
121     else if (!UnsuppTypesMap().Contains (aType))
122     {
123       std::cout << "attribute driver for type "<< aType -> Name()<< " not found"<< std::endl;
124       UnsuppTypesMap().Add (aType);
125     }
126 #endif
127   }
128
129   // write sub-labels
130   TDF_ChildIterator itr2 (theLabel);
131   for ( ; itr2.More(); itr2.Next())
132   {
133     const TDF_Label& aChildLab = itr2.Value();
134     count += WriteSubTree(aChildLab, aLabElem, theRelocTable, theDrivers);
135   }
136
137   if (count > 0 || TDocStd_Owner::GetDocument(theLabel.Data())->EmptyLabelsSavingMode())
138   {
139     theElement.appendChild(aLabElem);
140
141     // set attribute "tag"
142     aLabElem.setAttribute (::TagString(), theLabel.Tag());
143   }
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 {
157   TDF_Label aRootLab = theData->Root();
158   XmlMDF_MapOfDriver aDriverMap;
159   CreateDrvMap (theDrivers, aDriverMap);
160
161   Standard_Integer count = 0;
162
163   LDOM_Node theNode = theElement.getFirstChild();
164   XmlObjMgt_Element anElem = (const XmlObjMgt_Element&)theNode;
165   while ( !anElem.isNull() )
166   {
167     if ( anElem.getNodeName().equals (::LabelString()) )
168     {
169       Standard_Integer subcount =
170         ReadSubTree(anElem, aRootLab, theRelocTable, aDriverMap);
171       // check for error
172       if (subcount < 0)
173         return Standard_False;
174       count += subcount;
175     }
176     //anElem = (const XmlObjMgt_Element &) anElem.getNextSibling();
177     LDOM_Node theNode1 = anElem.getNextSibling();
178     anElem = (const XmlObjMgt_Element &) theNode1;
179   }
180
181   return Standard_True;
182 }
183
184 //=======================================================================
185 //function : ReadSubTree
186 //purpose  : 
187 //=======================================================================
188 Standard_Integer XmlMDF::ReadSubTree (const XmlObjMgt_Element&    theElement,
189                                       const TDF_Label&            theLabel,
190                                       XmlObjMgt_RRelocationTable& theRelocTable,
191                                       const XmlMDF_MapOfDriver&   theDriverMap)
192 {
193   // Extraction of the driver subset.
194   Standard_Integer count = 0;
195
196   //XmlObjMgt_Element anElem = (const XmlObjMgt_Element &) theElement.getFirstChild();
197   LDOM_Node theNode = theElement.getFirstChild();
198   XmlObjMgt_Element anElem = (const XmlObjMgt_Element &) theNode;
199   while ( !anElem.isNull() )
200   {
201     if ( anElem.getNodeType() == LDOM_Node::ELEMENT_NODE )
202     {
203       if ( anElem.getNodeName().equals (::LabelString()) )
204       {
205         // read tag
206         Standard_Integer tag;
207         XmlObjMgt_DOMString aTag (anElem.getAttribute(::TagString()));
208         if ( !aTag.GetInteger (tag) ) {
209           TCollection_ExtendedString anErrorMessage =
210             TCollection_ExtendedString ("Wrong Tag value for OCAF Label: ")
211               + aTag;
212           theDriverMap.Find("TDF_TagSource") -> myMessageDriver->Send (anErrorMessage, Message_Fail);
213           return -1;
214         }
215         // create label
216         TDF_Label aLab = theLabel.FindChild(tag, Standard_True);
217
218         // read sub-tree
219         Standard_Integer subcount =
220           ReadSubTree(anElem, aLab, theRelocTable, theDriverMap);
221         // check for error
222         if (subcount == -1)
223           return -1;
224         count += subcount;
225       }
226       else
227       {
228         // read attribute
229         XmlObjMgt_DOMString aName = anElem.getNodeName();
230
231 #ifdef DATATYPE_MIGRATION
232         TCollection_AsciiString  newName;       
233         if(Storage_Schema::CheckTypeMigration(aName, newName)) {
234 #ifdef OCCT_DEBUG
235           std::cout << "CheckTypeMigration:OldType = " <<aName.GetString() << " Len = "<<strlen(aName.GetString())<<std::endl;
236           std::cout << "CheckTypeMigration:NewType = " <<newName  << " Len = "<< newName.Length()<<std::endl;
237 #endif
238           aName = newName.ToCString();
239         }
240 #endif  
241        
242         if (theDriverMap.IsBound (aName))
243         {
244           count++;
245           const Handle(XmlMDF_ADriver)& driver = theDriverMap.Find(aName);
246           XmlObjMgt_Persistent pAtt (anElem);
247           Standard_Integer anID = pAtt.Id ();
248           if (anID <= 0) {      // check for ID validity
249             TCollection_ExtendedString anErrorMessage =
250              TCollection_ExtendedString("Wrong ID of OCAF attribute with type ")
251                + aName;
252             driver -> myMessageDriver->Send (anErrorMessage, Message_Fail);
253             return -1;
254           }
255           Handle(TDF_Attribute) tAtt;
256           Standard_Boolean isBound = theRelocTable.IsBound(anID);
257           if (isBound)
258             tAtt = Handle(TDF_Attribute)::DownCast(theRelocTable.Find(anID));
259           else
260             tAtt = driver -> NewEmpty();
261
262           if (tAtt->Label().IsNull())
263           {
264             try
265             {
266               theLabel.AddAttribute (tAtt);
267             }
268             catch (const Standard_DomainError&)
269             {
270               // For attributes that can have arbitrary GUID (e.g. TDataStd_Integer), exception
271               // will be raised in valid case if attribute of that type with default GUID is already
272               // present  on the same label; the reason is that actual GUID will be read later.
273               // To avoid this, set invalid (null) GUID to the newly added attribute (see #29669)
274               static const Standard_GUID fbidGuid;
275               tAtt->SetID (fbidGuid);
276               theLabel.AddAttribute (tAtt);
277             }
278           }
279           else
280             driver->myMessageDriver->Send
281               (TCollection_ExtendedString("XmlDriver warning: ") +
282                "attempt to attach attribute " +
283                aName + " to a second label", Message_Warning);
284
285           if (! driver -> Paste (pAtt, tAtt, theRelocTable))
286           {
287             // error converting persistent to transient
288             driver->myMessageDriver->Send
289               (TCollection_ExtendedString("XmlDriver warning: ") +
290                "failure reading attribute " + aName, Message_Warning);
291           }
292           else if (isBound == Standard_False)
293             theRelocTable.Bind (anID, tAtt);
294         }
295 #ifdef OCCT_DEBUG
296         else
297         {
298           const TCollection_AsciiString anAsciiName = aName;
299           std::cerr << "XmlDriver warning: "
300                << "label contains object of unknown type "<< anAsciiName<< std::endl;
301         }
302 #endif
303       }
304     }
305     //anElem = (const XmlObjMgt_Element &) anElem.getNextSibling();
306     LDOM_Node theNode1 = anElem.getNextSibling();
307     anElem = (const XmlObjMgt_Element &) theNode1;
308   }
309
310   // AfterRetrieval
311   if (count > 0)
312   {
313   }
314
315   return count;
316 }
317
318 //=======================================================================
319 //function : AddDrivers
320 //purpose  : 
321 //=======================================================================
322 void XmlMDF::AddDrivers (const Handle(XmlMDF_ADriverTable)& aDriverTable,
323                          const Handle(Message_Messenger)&   aMessageDriver)
324 {
325   aDriverTable->AddDriver (new XmlMDF_TagSourceDriver(aMessageDriver)); 
326   aDriverTable->AddDriver (new XmlMDF_ReferenceDriver(aMessageDriver));
327 }
328
329 //=======================================================================
330 //function : CreateDrvMap
331 //purpose  : 
332 //=======================================================================
333
334 void XmlMDF::CreateDrvMap (const Handle(XmlMDF_ADriverTable)& theDrivers,
335                            XmlMDF_MapOfDriver&                theAsciiDriverMap)
336 {
337   const XmlMDF_TypeADriverMap& aDriverMap = theDrivers->GetDrivers();
338   XmlMDF_DataMapIteratorOfTypeADriverMap anIter (aDriverMap);
339   while (anIter.More()) {
340     const Handle(XmlMDF_ADriver)& aDriver = anIter.Value();
341     const TCollection_AsciiString aTypeName = aDriver -> TypeName();
342     if (theAsciiDriverMap.IsBound (aTypeName) == Standard_False)
343       theAsciiDriverMap.Bind (aTypeName, aDriver);
344     else
345       aDriver -> myMessageDriver->Send
346         (TCollection_ExtendedString ("Warning: skipped driver name: \"")
347          + aTypeName + '\"', Message_Warning);
348     anIter.Next();
349   }
350 }