0024023: Revamp the OCCT Handle -- general
[occt.git] / src / XmlLDrivers / XmlLDrivers_DocumentRetrievalDriver.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 #include <XmlLDrivers_DocumentRetrievalDriver.ixx>
17
18 #include <XmlLDrivers.hxx>
19 #include <XmlMDF.hxx>
20 #include <XmlObjMgt_RRelocationTable.hxx>
21 #include <XmlObjMgt_Document.hxx>
22 #include <XmlObjMgt.hxx>
23 #include <XmlMDataStd.hxx>
24 #include <LDOM_LDOMImplementation.hxx>
25 #include <LDOM_DocumentType.hxx>
26 #include <LDOMParser.hxx>
27
28 #include <TDF_Data.hxx>
29 #include <TDocStd_Owner.hxx>
30 #include <TDocStd_Document.hxx>
31 #include <CDM_MessageDriver.hxx>
32 #include <CDM_MetaData.hxx>
33 #include <TCollection_AsciiString.hxx>
34 #include <UTL.hxx>
35 #include <OSD_Path.hxx>
36
37 #ifdef WNT
38 # include <tchar.h>
39 #endif  // WNT
40
41 #include <locale.h>
42 #include <Standard_Failure.hxx>
43 #include <Standard_ErrorHandler.hxx>
44
45 #define START_REF         "START_REF"
46 #define END_REF           "END_REF"
47 #define REFERENCE_COUNTER "REFERENCE_COUNTER"
48
49 //#define TAKE_TIMES
50 static void take_time (const Standard_Integer, const char *,
51                        const Handle(CDM_MessageDriver)&)
52 #ifdef TAKE_TIMES
53 ;
54 #else
55 {}
56 #endif
57
58 static Standard_Integer RemoveExtraSeparator(TCollection_AsciiString& aString) {
59
60   Standard_Integer i, j, len ;
61
62   len = aString.Length() ;
63 #ifdef WNT
64   // Case of network path, such as \\MACHINE\dir
65   for (i = j = 2 ; j <= len ; i++,j++) {
66 #else
67   for (i = j = 1 ; j <= len ; i++,j++) {
68 #endif
69       Standard_Character c = aString.Value(j) ;
70       aString.SetValue(i,c) ;
71       if (c == '/')
72           while(j < len && aString.Value(j+1) == '/') j++ ;
73   }
74   len = i-1 ;
75   if (aString.Value(len) == '/') len-- ;  
76   aString.Trunc(len) ;
77   return len ;
78 }
79 static TCollection_AsciiString GetDirFromFile(const TCollection_ExtendedString& aFileName) {
80   TCollection_AsciiString theCFile=UTL::CString(aFileName);
81   TCollection_AsciiString theDirectory;
82   Standard_Integer i=theCFile.SearchFromEnd("/");
83 #ifdef WNT    
84 //    if(i==-1) i=theCFile.SearchFromEnd("\\");
85   if(theCFile.SearchFromEnd("\\") > i)
86     i=theCFile.SearchFromEnd("\\");
87 #endif
88   if(i!=-1) theDirectory=theCFile.SubString(1,i);
89   return theDirectory;
90 }
91
92 static TCollection_AsciiString AbsolutePath(
93                             const TCollection_AsciiString& aDirPath,
94                             const TCollection_AsciiString& aRelFilePath)
95 {
96   TCollection_AsciiString EmptyString = "" ;
97 #ifdef WNT
98   if (aRelFilePath.Search(":") == 2 ||
99       (aRelFilePath.Search("\\") == 1 && aRelFilePath.Value(2) == '\\'))
100 #else
101   if(aRelFilePath.Search("/") == 1)
102 #endif
103     return aRelFilePath ;
104   
105   TCollection_AsciiString DirPath = aDirPath, RelFilePath = aRelFilePath  ;
106   Standard_Integer i,len ;
107   
108 #ifdef WNT
109   if(DirPath.Search(":") != 2 &&
110      (DirPath.Search("\\") != 1 || DirPath.Value(2) != '\\'))
111 #else
112   if (DirPath.Search("/") != 1 )
113 #endif
114     return EmptyString ;
115
116 #ifdef WNT
117   DirPath.ChangeAll('\\','/') ;
118   RelFilePath.ChangeAll('\\','/') ;      
119 #endif
120   
121   RemoveExtraSeparator(DirPath) ;
122   len = RemoveExtraSeparator(RelFilePath) ;
123   
124   while (RelFilePath.Search("../") == 1) {
125       if (len == 3)
126     return EmptyString ;
127       RelFilePath = RelFilePath.SubString(4,len) ;
128       len -= 3 ;
129       if (DirPath.IsEmpty())
130     return EmptyString ;
131       i = DirPath.SearchFromEnd("/") ;
132       if (i < 0)
133           return EmptyString ;
134       DirPath.Trunc(i-1) ;
135   }  
136   TCollection_AsciiString retx;
137   retx= DirPath;
138   retx+= "/";
139   retx+=RelFilePath ;
140   return retx;
141 }
142
143 //=======================================================================
144 //function : XmlLDrivers_DocumentRetrievalDriver
145 //purpose  : Constructor
146 //=======================================================================
147 XmlLDrivers_DocumentRetrievalDriver::XmlLDrivers_DocumentRetrievalDriver()
148 {
149   myReaderStatus = PCDM_RS_OK;
150 }
151
152 //=======================================================================
153 //function : CreateDocument
154 //purpose  : pure virtual method definition
155 //=======================================================================
156 Handle(CDM_Document) XmlLDrivers_DocumentRetrievalDriver::CreateDocument()
157 {
158   return new TDocStd_Document(PCDM_RetrievalDriver::GetFormat());
159 }
160
161 //=======================================================================
162 //function : SchemaName
163 //purpose  : pure virtual method definition
164 //=======================================================================
165 TCollection_ExtendedString XmlLDrivers_DocumentRetrievalDriver::SchemaName() const
166 {
167   TCollection_ExtendedString schemaname;
168   return schemaname; 
169 }
170
171 //=======================================================================
172 //function : Make
173 //purpose  : pure virtual method definition
174 //=======================================================================
175 void XmlLDrivers_DocumentRetrievalDriver::Make (const Handle(PCDM_Document)&,
176                                                const Handle(CDM_Document)&)
177 {
178 }
179
180 //=======================================================================
181 //function : Read
182 //purpose  : 
183 //=======================================================================
184 void XmlLDrivers_DocumentRetrievalDriver::Read
185   (const TCollection_ExtendedString& theFileName,
186    const Handle(CDM_Document)&       theNewDocument,
187    const Handle(CDM_Application)&    theApplication)
188 {
189   myReaderStatus = PCDM_RS_DriverFailure;
190   myFileName = theFileName;
191   Handle(CDM_MessageDriver) aMessageDriver = theApplication -> MessageDriver();
192   ::take_time (~0, " +++++ Start RETRIEVE procedures ++++++", aMessageDriver);
193
194   // 1. Read DOM_Document from file
195   LDOMParser aParser;
196   TCollection_AsciiString aName (theFileName,'?');
197   if (aParser.parse(aName.ToCString()))
198   {
199     TCollection_AsciiString aData;
200     cout << aParser.GetError(aData) << ": " << aData << endl;
201     myReaderStatus = PCDM_RS_FormatFailure;
202     return;
203   }
204   const XmlObjMgt_Element anElement= aParser.getDocument().getDocumentElement();
205   ::take_time (0, " +++++ Fin parsing XML :       ", aMessageDriver);
206
207   ReadFromDomDocument (anElement, theNewDocument, theApplication);
208 }
209
210 //=======================================================================
211 //function : ReadFromDomDocument
212 //purpose  : management of the macro-structure of XML document data
213 //remark   : If the application needs to use myRelocTable to retrieve additional
214 //           data from LDOM, this method should be reimplemented
215 //=======================================================================
216
217 void XmlLDrivers_DocumentRetrievalDriver::ReadFromDomDocument
218                                 (const XmlObjMgt_Element&       theElement,
219                                  const Handle(CDM_Document)&    theNewDocument,
220                                  const Handle(CDM_Application)& theApplication)
221 {
222   const Handle(CDM_MessageDriver) aMsgDriver =
223     theApplication -> MessageDriver();
224   // 1. Read info // to be done
225   TCollection_AsciiString anAbsoluteDirectory = GetDirFromFile(myFileName);
226   Standard_Integer aCurDocVersion = 0;
227   TCollection_ExtendedString anInfo;
228   const XmlObjMgt_Element anInfoElem =
229     theElement.GetChildByTagName ("info");
230   if (anInfoElem != NULL) {
231     XmlObjMgt_DOMString aDocVerStr = anInfoElem.getAttribute("DocVersion");
232     if(aDocVerStr == NULL)
233       aCurDocVersion = 2;
234     else if (!aDocVerStr.GetInteger(aCurDocVersion)) {
235       TCollection_ExtendedString aMsg =
236         TCollection_ExtendedString ("Cannot retrieve the current Document version"
237                                     " attribute as \"") + aDocVerStr + "\"";
238       if(!aMsgDriver.IsNull()) 
239         aMsgDriver->Write(aMsg.ToExtString());
240     }
241     
242     // oan: OCC22305 - check a document verison and if it's greater than
243     // current version of storage driver set an error status and return
244     if( aCurDocVersion > XmlLDrivers::StorageVersion().IntegerValue() )
245     {
246       TCollection_ExtendedString aMsg =
247         TCollection_ExtendedString ("error: wrong file version: ") +
248                                     aDocVerStr  + " while current is " +
249                                     XmlLDrivers::StorageVersion();
250       myReaderStatus = PCDM_RS_NoVersion;
251       if(!aMsgDriver.IsNull()) 
252         aMsgDriver->Write(aMsg.ToExtString());
253       return;
254     }
255
256     if( aCurDocVersion < 2) aCurDocVersion = 2;
257
258     PropagateDocumentVersion(aCurDocVersion);
259
260     Standard_Boolean isRef = Standard_False;
261     for (LDOM_Node aNode = anInfoElem.getFirstChild();
262          aNode != NULL; aNode = aNode.getNextSibling()) {
263       if (aNode.getNodeType() == LDOM_Node::ELEMENT_NODE) {
264         if (XmlObjMgt::GetExtendedString ((LDOM_Element&)aNode, anInfo)) {
265
266     // Read ref counter
267     if(anInfo.Search(REFERENCE_COUNTER) != -1) {
268       try {
269         OCC_CATCH_SIGNALS
270         TCollection_AsciiString anInf(anInfo,'?');
271         //Standard_Integer aRefCounter = anInf.Token(" ",2).IntegerValue();
272         //theNewDocument->SetReferenceCounter(aRefCounter);
273       }
274       catch (Standard_Failure) { 
275         //    cout << "warning: could not read the reference counter in " << aFileName << endl;
276         TCollection_ExtendedString aMsg("Warning: ");
277         aMsg = aMsg.Cat("could not read the reference counter").Cat("\0");
278         if(!aMsgDriver.IsNull()) 
279     aMsgDriver->Write(aMsg.ToExtString());
280       }
281     }
282     
283     if(anInfo == END_REF)
284       isRef = Standard_False;
285     if(isRef) { // Process References
286       
287       Standard_Integer pos=anInfo.Search(" ");
288       if(pos != -1) {
289         // Parce RefId, DocumentVersion and FileName
290         Standard_Integer aRefId;
291         TCollection_ExtendedString aFileName;
292         Standard_Integer aDocumentVersion;
293
294
295         TCollection_ExtendedString aRest=anInfo.Split(pos);
296         aRefId = UTL::IntegerValue(anInfo);
297         
298         Standard_Integer pos2 = aRest.Search(" ");
299         
300         aFileName = aRest.Split(pos2);
301         aDocumentVersion = UTL::IntegerValue(aRest);
302         
303         TCollection_AsciiString aPath = UTL::CString(aFileName);
304         TCollection_AsciiString anAbsolutePath;
305         if(!anAbsoluteDirectory.IsEmpty()) {
306     anAbsolutePath = AbsolutePath(anAbsoluteDirectory,aPath);
307     if(!anAbsolutePath.IsEmpty()) aPath=anAbsolutePath;
308         }
309         if(!aMsgDriver.IsNull()) {
310     //      cout << "reference found; ReferenceIdentifier: " << theReferenceIdentifier << "; File:" << thePath << ", version:" << theDocumentVersion;
311     TCollection_ExtendedString aMsg("Warning: ");
312     aMsg = aMsg.Cat("reference found; ReferenceIdentifier:  ").Cat(aRefId).Cat("; File:").Cat(aPath).Cat(", version:").Cat(aDocumentVersion).Cat("\0");
313     aMsgDriver->Write(aMsg.ToExtString());
314         }
315         // Add new ref!
316         /////////////
317     TCollection_ExtendedString theFolder,theName;
318         //TCollection_ExtendedString theFile=myReferences(myIterator).FileName();
319         TCollection_ExtendedString f(aPath);
320 #ifndef WNT
321         
322         Standard_Integer i= f.SearchFromEnd("/");
323         TCollection_ExtendedString n = f.Split(i); 
324         f.Trunc(f.Length()-1);
325         theFolder = f;
326         theName = n;
327 #else
328         OSD_Path p = UTL::Path(f);
329         Standard_ExtCharacter      chr;
330         TCollection_ExtendedString dir, dirRet, name;
331         
332         dir = UTL::Disk(p);
333         dir += UTL::Trek(p);
334         
335         for ( int i = 1; i <= dir.Length (); ++i ) {
336     
337     chr = dir.Value ( i );
338     
339     switch ( chr ) {
340       
341     case _TEXT( '|' ):
342       dirRet += _TEXT( "/" );
343       break;
344       
345     case _TEXT( '^' ):
346       
347       dirRet += _TEXT( ".." );
348       break;
349       
350     default:
351       dirRet += chr;
352       
353     }  
354         }
355         theFolder = dirRet;
356         theName   = UTL::Name(p); theName+= UTL::Extension(p);
357 #endif  // WNT
358         
359         Handle(CDM_MetaData) aMetaData =  CDM_MetaData::LookUp(theFolder,theName,aPath,aPath,UTL::IsReadOnly(aFileName));
360 ////////////
361         theNewDocument->CreateReference(aMetaData,aRefId,
362              theApplication,aDocumentVersion,Standard_False);
363
364         
365       }
366
367       
368     }
369     if(anInfo == START_REF)
370       isRef = Standard_True;
371         }
372       }
373     }
374   }
375
376   // 2. Read comments
377   TCollection_ExtendedString aComment;
378   const XmlObjMgt_Element aCommentsElem =
379     theElement.GetChildByTagName ("comments");
380   if (aCommentsElem != NULL)
381   {
382     for (LDOM_Node aNode = aCommentsElem.getFirstChild();
383          aNode != NULL; aNode = aNode.getNextSibling())
384     {
385       if (aNode.getNodeType() == LDOM_Node::ELEMENT_NODE)
386       {
387         if (XmlObjMgt::GetExtendedString ((LDOM_Element&)aNode, aComment))
388         {
389           theNewDocument->AddComment(aComment);
390         }
391       }
392     }
393   }
394
395   // 2. Read Shapes section
396   if (myDrivers.IsNull()) myDrivers = AttributeDrivers (aMsgDriver);  
397   const Handle(XmlMDF_ADriver) aNSDriver = ReadShapeSection(theElement, aMsgDriver);
398   if(!aNSDriver.IsNull())
399     ::take_time (0, " +++++ Fin reading Shapes :    ", aMsgDriver);
400
401   // 5. Read document contents
402   try
403   {
404     OCC_CATCH_SIGNALS
405 #ifdef OCCT_DEBUG
406     TCollection_ExtendedString aMessage ("PasteDocument");
407     aMsgDriver -> Write (aMessage.ToExtString());
408 #endif
409     if (!MakeDocument(theElement, theNewDocument))
410       myReaderStatus = PCDM_RS_MakeFailure;
411     else
412       myReaderStatus = PCDM_RS_OK;
413   }
414   catch (Standard_Failure)
415   {
416     TCollection_ExtendedString anErrorString (Standard_Failure::Caught()->GetMessageString());
417     aMsgDriver -> Write (anErrorString.ToExtString());
418   }
419
420   //    Wipe off the shapes written to the <shapes> section
421   ShapeSetCleaning(aNSDriver);
422
423   //    Clean the relocation table.
424   //    If the application needs to use myRelocTable to retrieve additional
425   //    data from LDOM, this method should be reimplemented avoiding this step
426   myRelocTable.Clear();
427   ::take_time (0, " +++++ Fin reading data OCAF : ", aMsgDriver);
428 }
429
430 //=======================================================================
431 //function : MakeDocument
432 //purpose  : 
433 //=======================================================================
434 Standard_Boolean XmlLDrivers_DocumentRetrievalDriver::MakeDocument
435                                     (const XmlObjMgt_Element&    theElement,
436                                      const Handle(CDM_Document)& theTDoc)
437 {
438   Standard_Boolean aResult = Standard_False;
439   Handle(TDocStd_Document) TDOC = Handle(TDocStd_Document)::DownCast(theTDoc);
440   myRelocTable.Clear();
441   if (!TDOC.IsNull()) 
442   {
443     Handle(TDF_Data) aTDF = new TDF_Data();
444     aResult = XmlMDF::FromTo (theElement, aTDF, myRelocTable, myDrivers);
445     if (aResult) {
446       TDOC->SetData (aTDF);
447       TDocStd_Owner::SetDocument (aTDF, TDOC);
448     }
449   }
450   return aResult;
451 }
452
453 //=======================================================================
454 //function : AttributeDrivers
455 //purpose  : 
456 //=======================================================================
457 Handle(XmlMDF_ADriverTable) XmlLDrivers_DocumentRetrievalDriver::AttributeDrivers
458        (const Handle(CDM_MessageDriver)& theMessageDriver) 
459 {
460   return XmlLDrivers::AttributeDrivers (theMessageDriver);
461 }
462
463 //=======================================================================
464 //function : take_time
465 //class    : static
466 //purpose  : output astronomical time elapsed
467 //=======================================================================
468 #ifdef TAKE_TIMES
469 #include <time.h>
470 #include <sys/timeb.h>
471 #include <sys/types.h>
472 #include <stdio.h>
473 #ifndef WNT
474 extern "C" int ftime (struct timeb *tp);
475 #endif
476 extern struct timeb  tmbuf0;
477
478 static void take_time (const Standard_Integer isReset, const char * aHeader,
479                        const Handle(CDM_MessageDriver)& aMessageDriver)
480 {
481   struct timeb  tmbuf;
482   ftime (&tmbuf);
483   TCollection_ExtendedString aMessage ((Standard_CString)aHeader);
484   if (isReset) tmbuf0 = tmbuf;
485   else {
486     char take_tm_buf [64];
487     Sprintf (take_tm_buf, "%9.2f s ++++",
488              double(tmbuf.time - tmbuf0.time) +
489              double(tmbuf.millitm - tmbuf0.millitm)/1000.);
490     aMessage += take_tm_buf;
491   }
492   aMessageDriver -> Write (aMessage.ToExtString());
493 }
494 #endif
495
496 //=======================================================================
497 //function : PropagateDocumentVersion
498 //purpose  : 
499 //=======================================================================
500 void XmlLDrivers_DocumentRetrievalDriver::PropagateDocumentVersion(
501                                    const Standard_Integer theDocVersion )
502 {
503   XmlMDataStd::SetDocumentVersion(theDocVersion);
504 }
505
506 //=======================================================================
507 //function : ReadShapeSection
508 //purpose  : definition of ReadShapeSection
509 //=======================================================================
510 Handle(XmlMDF_ADriver) XmlLDrivers_DocumentRetrievalDriver::ReadShapeSection(
511                                const XmlObjMgt_Element&       /*theElement*/,
512              const Handle(CDM_MessageDriver)& /*aMsgDriver*/)
513 {
514   Handle(XmlMDF_ADriver) aDriver;
515   //empty; to be redefined
516   return aDriver;
517 }
518
519 //=======================================================================
520 //function : ShapeSetCleaning
521 //purpose  : definition of ShapeSetCleaning
522 //=======================================================================
523 void XmlLDrivers_DocumentRetrievalDriver::ShapeSetCleaning(
524             const Handle(XmlMDF_ADriver)& /*theDriver*/) 
525 {}