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