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