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