0026290: It is neccessary to separate visualization part from TKCAF
[occt.git] / src / BinLDrivers / BinLDrivers_DocumentRetrievalDriver.cxx
1 // Created on: 2002-10-31
2 // Created by: Michael SAZONOV
3 // Copyright (c) 2002-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 <BinLDrivers.hxx>
18 #include <BinLDrivers_DocumentRetrievalDriver.hxx>
19 #include <BinLDrivers_DocumentSection.hxx>
20 #include <BinLDrivers_Marker.hxx>
21 #include <BinMDataStd.hxx>
22 #include <BinMDF_ADriver.hxx>
23 #include <BinMDF_ADriverTable.hxx>
24 #include <BinObjMgt_Persistent.hxx>
25 #include <CDM_Application.hxx>
26 #include <CDM_Document.hxx>
27 #include <CDM_MessageDriver.hxx>
28 #include <FSD_BinaryFile.hxx>
29 #include <FSD_FileHeader.hxx>
30 #include <PCDM_Document.hxx>
31 #include <Standard_ErrorHandler.hxx>
32 #include <Standard_Stream.hxx>
33 #include <Standard_Type.hxx>
34 #include <Storage_HeaderData.hxx>
35 #include <Storage_Schema.hxx>
36 #include <TCollection_AsciiString.hxx>
37 #include <TCollection_ExtendedString.hxx>
38 #include <TDF_Attribute.hxx>
39 #include <TDF_Data.hxx>
40 #include <TDF_Label.hxx>
41 #include <TDocStd_Document.hxx>
42 #include <TDocStd_Owner.hxx>
43
44 IMPLEMENT_STANDARD_RTTIEXT(BinLDrivers_DocumentRetrievalDriver,PCDM_RetrievalDriver)
45
46 #define SHAPESECTION_POS "SHAPE_SECTION_POS:"
47 #define SIZEOFSHAPELABEL  18
48
49 #define DATATYPE_MIGRATION
50 //#define DATATYPE_MIGRATION_DEB
51 //=======================================================================
52 //function : BinLDrivers_DocumentRetrievalDriver
53 //purpose  : Constructor
54 //=======================================================================
55
56 BinLDrivers_DocumentRetrievalDriver::BinLDrivers_DocumentRetrievalDriver ()
57 {
58   myReaderStatus = PCDM_RS_OK;
59 }
60
61 //=======================================================================
62 //function : CreateDocument
63 //purpose  : pure virtual method definition
64 //=======================================================================
65
66 Handle(CDM_Document) BinLDrivers_DocumentRetrievalDriver::CreateDocument()
67 {
68   return new TDocStd_Document(PCDM_RetrievalDriver::GetFormat());
69 }
70
71 //=======================================================================
72 //function : SchemaName
73 //purpose  : pure virtual method definition
74 //=======================================================================
75
76 TCollection_ExtendedString BinLDrivers_DocumentRetrievalDriver::SchemaName() const
77 {
78   TCollection_ExtendedString schemaname;
79   return schemaname;
80 }
81
82 //=======================================================================
83 //function : Make
84 //purpose  : pure virtual method definition
85 //=======================================================================
86
87 void BinLDrivers_DocumentRetrievalDriver::Make (const Handle(PCDM_Document)&,
88                                                const Handle(CDM_Document)&)
89 {
90 }
91
92 //=======================================================================
93 //function : Read
94 //purpose  :
95 //=======================================================================
96
97 #define START_TYPES "START_TYPES"
98 #define END_TYPES "END_TYPES"
99
100 void BinLDrivers_DocumentRetrievalDriver::Read
101                          (const TCollection_ExtendedString& theFileName,
102                           const Handle(CDM_Document)&       theNewDocument,
103                           const Handle(CDM_Application)&    theApplication)
104 {
105   myReaderStatus = PCDM_RS_DriverFailure;
106   myMsgDriver = theApplication -> MessageDriver();
107
108   const TCollection_ExtendedString aMethStr
109     ("BinLDrivers_DocumentRetrievalDriver: ");
110
111   Handle(TDocStd_Document) aDoc =
112     Handle(TDocStd_Document)::DownCast(theNewDocument);
113   if (aDoc.IsNull()) {
114 #ifdef OCCT_DEBUG
115     WriteMessage (aMethStr + "error: null document");
116 #endif
117     myReaderStatus = PCDM_RS_NoDocument;
118     return;
119   }
120
121   TCollection_AsciiString aFileName (theFileName);
122
123   // 1. Read the information section
124   Handle(Storage_HeaderData) aHeaderData;
125   Storage_Position anInfoSectionEnd = ReadInfoSection( aFileName, aHeaderData );
126   if (!anInfoSectionEnd) {
127     WriteMessage (aMethStr + "error: file has invalid header");
128     myReaderStatus = PCDM_RS_UnrecognizedFileFormat;
129     return;
130   }
131
132   // 1.a Version of writer
133   if (!aHeaderData->StorageVersion().IsIntegerValue()) {
134     // file has no format version
135     WriteMessage (aMethStr + "error: file has no format version");
136     myReaderStatus = PCDM_RS_FormatFailure;
137     return;
138   }
139   Standard_Integer aFileVer = aHeaderData->StorageVersion().IntegerValue();
140   Standard_Integer aCurrVer = BinLDrivers::StorageVersion().IntegerValue();
141   // maintain one-way compatibility starting from version 2+
142   if (!CheckDocumentVersion(aFileVer, aCurrVer)) {
143     myReaderStatus = PCDM_RS_NoVersion;
144     // file was written with another version
145     WriteMessage (aMethStr + "error: wrong file version: " +
146                   aHeaderData->StorageVersion() + " while current is " +
147                   BinLDrivers::StorageVersion());
148     return;
149   }
150
151   // 1.b Retrieve the Types table
152   TColStd_SequenceOfAsciiString aTypeNames; //Sequence of types in file
153   const TColStd_SequenceOfAsciiString& aUserInfo = aHeaderData->UserInfo();
154   Standard_Boolean begin = Standard_False;
155   Standard_Integer i;
156   for (i=1; i <= aUserInfo.Length(); i++) {
157     //const TCollection_AsciiString& aStr = aUserInfo(i);
158     TCollection_AsciiString aStr = aUserInfo(i);
159     if (aStr == START_TYPES)
160       begin = Standard_True;
161     else if (aStr == END_TYPES)
162       break;
163     else if (begin) {
164       if ( aFileVer < 8 ) {
165 #ifdef DATATYPE_MIGRATION
166         TCollection_AsciiString  newName;       
167         if(Storage_Schema::CheckTypeMigration(aStr, newName)) {
168 #ifdef OCCT_DEBUG
169           cout << "CheckTypeMigration:OldType = " <<aStr << " Len = "<<aStr.Length()<<endl;
170           cout << "CheckTypeMigration:NewType = " <<newName  << " Len = "<< newName.Length()<<endl;
171 #endif
172           aStr = newName;
173         }
174 #endif  
175       } 
176       aTypeNames.Append (aStr);    
177     }
178   }
179   if (myDrivers.IsNull())
180     myDrivers = AttributeDrivers (myMsgDriver);
181   myDrivers->AssignIds (aTypeNames); 
182
183   // recognize types not supported by drivers
184   myMapUnsupported.Clear();
185   for (i=1; i <= aTypeNames.Length(); i++)
186     if (myDrivers->GetDriver(i).IsNull()) 
187       myMapUnsupported.Add(i);
188   if (!myMapUnsupported.IsEmpty()) {
189     WriteMessage (aMethStr + "warning: "
190                   "the following attributes have no driver:");
191     for (i=1; i <= aTypeNames.Length(); i++)
192       if (myMapUnsupported.Contains(i))
193         WriteMessage (aTypeNames(i));
194   }
195
196   // Open the file stream
197 #ifdef _WIN32
198   ifstream anIS ((const wchar_t*) theFileName.ToExtString(), ios::in | ios::binary);
199 #else
200   ifstream anIS (aFileName.ToCString());
201 #endif
202
203   if (!anIS) {
204     // Can not open file
205     WriteMessage (aMethStr + "error: can't open file " + theFileName);
206     myReaderStatus = PCDM_RS_OpenError;
207     return;
208   }
209
210   // skip info section
211   anIS.seekg( (streampos) anInfoSectionEnd );
212
213   // propagate the opened document version to data drivers
214   PropagateDocumentVersion(aFileVer);
215
216   // 2. Read document contents
217
218   // 2a. Retrieve data from the stream:
219   myRelocTable.Clear();
220   mySections.Clear();
221   myPAtt.Init();
222   Handle(TDF_Data) aData = new TDF_Data();
223   streampos aDocumentPos = -1;
224
225   // 2b. Read the TOC of Sections
226   if (aFileVer >= 3) {
227     BinLDrivers_DocumentSection aSection;
228     do {
229       BinLDrivers_DocumentSection::ReadTOC (aSection, anIS);
230       mySections.Append(aSection);
231     } while
232       (!aSection.Name().IsEqual((Standard_CString)SHAPESECTION_POS));
233     aDocumentPos = anIS.tellg(); // position of root label
234
235     BinLDrivers_VectorOfDocumentSection::Iterator anIterS (mySections);
236     for (; anIterS.More(); anIterS.Next()) {
237       BinLDrivers_DocumentSection& aCurSection = anIterS.ChangeValue();
238       if (aCurSection.IsPostRead() == Standard_False) {
239         anIS.seekg ((streampos) aCurSection.Offset());
240         if (aCurSection.Name().IsEqual ((Standard_CString)SHAPESECTION_POS)) 
241           ReadShapeSection (aCurSection, anIS);
242         else
243           ReadSection (aCurSection, theNewDocument, anIS); 
244       }
245     }
246   } else { //aFileVer < 3
247     aDocumentPos = anIS.tellg(); // position of root label
248
249     // retrieve SHAPESECTION_POS string
250     char aShapeSecLabel[SIZEOFSHAPELABEL + 1];
251     aShapeSecLabel[SIZEOFSHAPELABEL] = 0x00;
252     anIS.read ((char*)&aShapeSecLabel, SIZEOFSHAPELABEL);// SHAPESECTION_POS
253     TCollection_AsciiString aShapeLabel(aShapeSecLabel);
254     // detect if a file was written in old fashion (version 2 without shapes)
255     // and if so then skip reading ShapeSection
256     if (aShapeLabel.Length() > 0) {
257       // version 2+(with shapes) and higher goes here
258       if(aShapeLabel.Length() <= 0 || aShapeLabel != SHAPESECTION_POS) {
259         WriteMessage (aMethStr + "error: Format failure");
260         myReaderStatus = PCDM_RS_FormatFailure;
261         return;
262       }
263
264       // retrieve ShapeSection Position
265       Standard_Integer aShapeSectionPos; // go to ShapeSection
266       anIS.read ((char*)&aShapeSectionPos, sizeof(Standard_Integer));
267
268 #if DO_INVERSE
269       aShapeSectionPos = InverseInt (aShapeSectionPos);
270 #endif
271 #ifdef OCCT_DEBUG
272       cout <<"aShapeSectionPos = " <<aShapeSectionPos <<endl;
273 #endif
274       if(aShapeSectionPos) { 
275         aDocumentPos = anIS.tellg();
276         anIS.seekg((streampos) aShapeSectionPos);
277
278         CheckShapeSection(aShapeSectionPos, anIS);
279         // Read Shapes
280         BinLDrivers_DocumentSection aCurSection;
281         ReadShapeSection (aCurSection, anIS, Standard_False);
282       }
283     }
284   } // end of reading Sections or shape section
285
286   // Return to read of the Document structure
287   anIS.seekg(aDocumentPos);
288
289   // read the header (tag) of the root label
290   Standard_Integer aTag;
291   anIS.read ((char*)&aTag, sizeof(Standard_Integer));
292
293   // read sub-tree of the root label
294   Standard_Integer nbRead = ReadSubTree (anIS, aData->Root());
295   myPAtt.Destroy();    // free buffer
296   myRelocTable.Clear();
297   myMapUnsupported.Clear();
298     
299   if (nbRead > 0) {
300     // attach data to the document
301     aDoc->SetData (aData);
302     TDocStd_Owner::SetDocument (aData, aDoc);
303     aDoc->SetComments(aHeaderData->Comments());
304     myReaderStatus = PCDM_RS_OK;
305   }
306
307   // Read Sections (post-reading type)
308   if (aFileVer >= 3) {
309     BinLDrivers_VectorOfDocumentSection::Iterator anIterS (mySections);
310     for (; anIterS.More(); anIterS.Next()) {
311       BinLDrivers_DocumentSection& aCurSection = anIterS.ChangeValue();
312       if (aCurSection.IsPostRead()) {
313         anIS.seekg ((streampos) aCurSection.Offset());
314         ReadSection (aCurSection, theNewDocument, anIS); 
315       }
316     }
317   }
318 }
319
320 //=======================================================================
321 //function : ReadSubTree
322 //purpose  :
323 //=======================================================================
324
325 Standard_Integer BinLDrivers_DocumentRetrievalDriver::ReadSubTree
326                          (Standard_IStream& theIS,
327                           const TDF_Label&  theLabel)
328 {
329   Standard_Integer nbRead = 0;
330   static TCollection_ExtendedString aMethStr
331     ("BinLDrivers_DocumentRetrievalDriver: ");
332
333   // Read attributes:
334   theIS >> myPAtt;
335   while (theIS && myPAtt.TypeId() > 0 &&             // not an end marker ?
336          myPAtt.Id() > 0) {                          // not a garbage ?
337     // get a driver according to TypeId
338     Handle(BinMDF_ADriver) aDriver = myDrivers->GetDriver (myPAtt.TypeId());
339     if (!aDriver.IsNull()) {
340       // create transient attribute
341       nbRead++;
342       Standard_Integer anID = myPAtt.Id();
343       Handle(TDF_Attribute) tAtt;
344       Standard_Boolean isBound = myRelocTable.IsBound(anID);
345       if (isBound)
346         tAtt = Handle(TDF_Attribute)::DownCast(myRelocTable.Find(anID));
347       else
348         tAtt = aDriver->NewEmpty();
349       if (tAtt->Label().IsNull())
350         theLabel.AddAttribute (tAtt);
351       else
352         WriteMessage (aMethStr +
353                       "warning: attempt to attach attribute " +
354                       aDriver->TypeName() + " to a second label");
355
356       Standard_Boolean ok = aDriver->Paste (myPAtt, tAtt, myRelocTable);
357       if (!ok) {
358         // error converting persistent to transient
359         WriteMessage (aMethStr + "warning: failure reading attribute " +
360                       aDriver->TypeName());
361       }
362       else if (!isBound)
363         myRelocTable.Bind (anID, tAtt);
364     }
365     else if (!myMapUnsupported.Contains(myPAtt.TypeId()))
366       WriteMessage (aMethStr + "warning: type ID not registered in header: "
367                     + myPAtt.TypeId());
368
369     // read next attribute
370     theIS >> myPAtt;
371   }
372   if (!theIS || myPAtt.TypeId() != BinLDrivers_ENDATTRLIST) {
373     // unexpected EOF or garbage data
374     WriteMessage (aMethStr + "error: unexpected EOF or garbage data");
375     myReaderStatus = PCDM_RS_UnrecognizedFileFormat;
376     return -1;
377   }
378
379   // Read children:
380   // read the tag of a child label
381   Standard_Integer aTag = BinLDrivers_ENDLABEL;
382   theIS.read ((char*) &aTag, sizeof(Standard_Integer));
383 #if DO_INVERSE
384   aTag = InverseInt (aTag);
385 #endif
386   while (theIS && aTag >= 0) { // not an end marker ?
387     // create sub-label
388     TDF_Label aLab = theLabel.FindChild (aTag, Standard_True);
389
390     // read sub-tree
391     Standard_Integer nbSubRead = ReadSubTree(theIS, aLab);
392     // check for error
393     if (nbSubRead == -1)
394       return -1;
395     nbRead += nbSubRead;
396
397     // read the tag of the next child
398     theIS.read ((char*) &aTag, sizeof(Standard_Integer));
399 #if DO_INVERSE
400     aTag = InverseInt (aTag);
401 #endif
402   }
403   if (aTag != BinLDrivers_ENDLABEL) {
404     // invalid end label marker
405     WriteMessage (aMethStr + "error: invalid end label marker");
406     myReaderStatus = PCDM_RS_UnrecognizedFileFormat;
407     return -1;
408   }
409
410   return nbRead;
411 }
412
413 //=======================================================================
414 //function : AttributeDrivers
415 //purpose  :
416 //=======================================================================
417
418 Handle(BinMDF_ADriverTable) BinLDrivers_DocumentRetrievalDriver::AttributeDrivers
419        (const Handle(CDM_MessageDriver)& theMessageDriver)
420 {
421   return BinLDrivers::AttributeDrivers (theMessageDriver);
422 }
423
424 //=======================================================================
425 //function : ReadInfoSection
426 //purpose  : Read the info  section  of  theFile, return a file
427 //           position corresponding to the info section end
428 //=======================================================================
429
430 Storage_Position BinLDrivers_DocumentRetrievalDriver::ReadInfoSection
431                          (const TCollection_AsciiString& theFileName,
432                           Handle(Storage_HeaderData)&    theData)
433 {
434   TCollection_ExtendedString aMsg
435     ( "BinLDrivers_DocumentRetrievalDriver: error: ");
436
437   FSD_BinaryFile aFileDriver;
438   Storage_Position aPos = 0;
439   if (aFileDriver.Open( theFileName, Storage_VSRead ) == Storage_VSOk)
440   {
441     Storage_Schema aSchema;
442     theData = aSchema.ReadHeaderSection( aFileDriver );
443
444     if (theData->ErrorStatus() == Storage_VSOk)
445       aPos = aFileDriver.Tell();
446     else
447       WriteMessage( aMsg + theData->ErrorStatusExtension() );
448   }
449   else
450     WriteMessage( aMsg + "can not open file " + theFileName);
451
452   aFileDriver.Close();
453
454   return aPos;
455 }
456
457 //=======================================================================
458 //function : WriteMessage
459 //purpose  : write   theMessage   to   the   MessageDriver   of
460 //           theApplication
461 //=======================================================================
462
463 void BinLDrivers_DocumentRetrievalDriver::WriteMessage
464                          (const TCollection_ExtendedString& theMsg)
465 {
466   if (!myMsgDriver.IsNull())
467     myMsgDriver->Write (theMsg.ToExtString());
468 }
469
470 //=======================================================================
471 //function : ReadSection
472 //purpose  : 
473 //=======================================================================
474
475 void BinLDrivers_DocumentRetrievalDriver::ReadSection
476                                 (BinLDrivers_DocumentSection& /*theSection*/,
477                                  const Handle(CDM_Document)&  /*theDocument*/,
478                                  Standard_IStream&            /*theIS*/)
479 {
480   // empty; should be redefined in subclasses
481 }
482
483 //=======================================================================
484 //function : ReadShapeSection
485 //purpose  : 
486 //=======================================================================
487
488 void BinLDrivers_DocumentRetrievalDriver::ReadShapeSection
489                               (BinLDrivers_DocumentSection& theSection,
490                                Standard_IStream&            /*theIS*/,
491                                const Standard_Boolean isMess)
492
493 {
494   if(isMess && theSection.Length()) {
495     const TCollection_ExtendedString aMethStr ("BinLDrivers_DocumentRetrievalDriver: ");
496     WriteMessage (aMethStr + "warning: Geometry is not supported by Lite schema. ");
497   }
498 }
499
500 //=======================================================================
501 //function : CheckShapeSection
502 //purpose  : 
503 //=======================================================================
504 void BinLDrivers_DocumentRetrievalDriver::CheckShapeSection(
505                                   const Storage_Position& ShapeSectionPos, 
506                                                     Standard_IStream& IS)
507 {
508   if (!IS.eof())
509   {
510     const std::streamoff endPos = IS.rdbuf()->pubseekoff(0L, std::ios_base::end, std::ios_base::in);
511 #ifdef OCCT_DEBUG
512     cout << "endPos = " << endPos <<endl;
513 #endif
514     if(ShapeSectionPos != endPos) {
515       const TCollection_ExtendedString aMethStr ("BinLDrivers_DocumentRetrievalDriver: ");
516       WriteMessage (aMethStr + "warning: Geometry is not supported by Lite schema. ");
517     }
518   }
519 }
520
521 //=======================================================================
522 //function : PropagateDocumentVersion
523 //purpose  : 
524 //=======================================================================
525 void BinLDrivers_DocumentRetrievalDriver::PropagateDocumentVersion(const Standard_Integer theDocVersion )
526 {
527   BinMDataStd::SetDocumentVersion(theDocVersion);
528 }
529
530 //=======================================================================
531 //function : CheckDocumentVersion
532 //purpose  : 
533 //=======================================================================
534 Standard_Boolean BinLDrivers_DocumentRetrievalDriver::CheckDocumentVersion(
535                                                           const Standard_Integer theFileVersion,
536                                                           const Standard_Integer theCurVersion)
537 {
538   if (theFileVersion < 2 || theFileVersion > theCurVersion) {
539     // file was written with another version
540     return Standard_False;
541   }
542   return Standard_True;
543 }
544