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