1 // Created on: 2002-10-31
2 // Created by: Michael SAZONOV
3 // Copyright (c) 2002-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
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.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
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 <Message_Messenger.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_FormatVersion.hxx>
45 #include <TDocStd_Owner.hxx>
46 #include <Message_ProgressScope.hxx>
49 IMPLEMENT_STANDARD_RTTIEXT(BinLDrivers_DocumentRetrievalDriver,PCDM_RetrievalDriver)
51 #define SHAPESECTION_POS "SHAPE_SECTION_POS:"
52 #define SIZEOFSHAPELABEL 18
54 #define DATATYPE_MIGRATION
55 //#define DATATYPE_MIGRATION_DEB
56 //=======================================================================
57 //function : BinLDrivers_DocumentRetrievalDriver
58 //purpose : Constructor
59 //=======================================================================
61 BinLDrivers_DocumentRetrievalDriver::BinLDrivers_DocumentRetrievalDriver ()
63 myReaderStatus = PCDM_RS_OK;
66 //=======================================================================
69 //=======================================================================
70 void BinLDrivers_DocumentRetrievalDriver::Read
71 (const TCollection_ExtendedString& theFileName,
72 const Handle(CDM_Document)& theNewDocument,
73 const Handle(CDM_Application)& theApplication,
74 const Message_ProgressRange& theRange)
76 std::ifstream aFileStream;
77 OSD_OpenStream (aFileStream, theFileName, std::ios::in | std::ios::binary);
79 if (aFileStream.is_open() && aFileStream.good())
81 Handle(Storage_Data) dData;
82 TCollection_ExtendedString aFormat = PCDM_ReadWriter::FileFormat (aFileStream, dData);
84 Read(aFileStream, dData, theNewDocument, theApplication, theRange);
87 myReaderStatus = PCDM_RS_UserBreak;
93 myReaderStatus = PCDM_RS_OpenError;
97 #define MODIFICATION_COUNTER "MODIFICATION_COUNTER: "
98 #define REFERENCE_COUNTER "REFERENCE_COUNTER: "
100 #define START_TYPES "START_TYPES"
101 #define END_TYPES "END_TYPES"
103 //=======================================================================
106 //=======================================================================
107 void BinLDrivers_DocumentRetrievalDriver::Read (Standard_IStream& theIStream,
108 const Handle(Storage_Data)& theStorageData,
109 const Handle(CDM_Document)& theDoc,
110 const Handle(CDM_Application)& theApplication,
111 const Message_ProgressRange& theRange)
113 myReaderStatus = PCDM_RS_DriverFailure;
114 myMsgDriver = theApplication -> MessageDriver();
116 const TCollection_ExtendedString aMethStr
117 ("BinLDrivers_DocumentRetrievalDriver: ");
119 Handle(TDocStd_Document) aDoc =
120 Handle(TDocStd_Document)::DownCast(theDoc);
123 myMsgDriver->Send (aMethStr + "error: null document", Message_Fail);
125 myReaderStatus = PCDM_RS_NoDocument;
129 // 1. the information section
130 Handle(Storage_HeaderData) aHeaderData;
132 if (!theStorageData.IsNull())
134 aHeaderData = theStorageData->HeaderData();
137 if (!aHeaderData.IsNull())
139 for (Standard_Integer i = 1; i <= aHeaderData->UserInfo().Length(); i++)
141 const TCollection_AsciiString& aLine = aHeaderData->UserInfo().Value(i);
143 if(aLine.Search(REFERENCE_COUNTER) != -1)
145 theDoc->SetReferenceCounter (aLine.Token(" ", 2).IntegerValue());
147 else if(aLine.Search(MODIFICATION_COUNTER) != -1)
149 theDoc->SetModifications (aLine.Token(" ", 2).IntegerValue());
154 // 1.a Version of writer
155 if (!aHeaderData->StorageVersion().IsIntegerValue()) {
156 // file has no format version
157 myMsgDriver->Send (aMethStr + "error: file has no format version", Message_Fail);
158 myReaderStatus = PCDM_RS_FormatFailure;
161 Standard_Integer aFileVer = aHeaderData->StorageVersion().IntegerValue();
162 Standard_Integer aCurrVer = TDocStd_Document::CurrentStorageFormatVersion();
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 myMsgDriver->Send (aMethStr + "error: wrong file version: " +
168 aHeaderData->StorageVersion() + " while current is " +
169 TDocStd_Document::CurrentStorageFormatVersion(), Message_Fail);
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;
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)
186 if ( aFileVer < TDocStd_FormatVersion_VERSION_8) {
187 #ifdef DATATYPE_MIGRATION
188 TCollection_AsciiString newName;
189 if(Storage_Schema::CheckTypeMigration(aStr, newName)) {
191 std::cout << "CheckTypeMigration:OldType = " <<aStr << " Len = "<<aStr.Length()<<std::endl;
192 std::cout << "CheckTypeMigration:NewType = " <<newName << " Len = "<< newName.Length()<<std::endl;
198 aTypeNames.Append (aStr);
201 if (myDrivers.IsNull())
202 myDrivers = AttributeDrivers (myMsgDriver);
203 myDrivers->AssignIds (aTypeNames);
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 myMsgDriver->Send (aMethStr + "warning: "
212 "the following attributes have no driver:", Message_Warning);
213 for (i=1; i <= aTypeNames.Length(); i++)
214 if (myMapUnsupported.Contains(i))
215 myMsgDriver->Send (aTypeNames(i), Message_Warning);
218 // 2. Read document contents
219 // 2a. Retrieve data from the stream:
220 myRelocTable.Clear();
221 myRelocTable.SetHeaderData(aHeaderData);
224 Handle(TDF_Data) aData = new TDF_Data();
225 std::streampos aDocumentPos = -1;
227 Message_ProgressScope aPS(theRange, "Reading data", 3);
229 // 2b. Read the TOC of Sections
230 if (aFileVer >= TDocStd_FormatVersion_VERSION_3) {
231 BinLDrivers_DocumentSection aSection;
233 BinLDrivers_DocumentSection::ReadTOC (aSection, theIStream, aFileVer);
234 mySections.Append(aSection);
235 } while(!aSection.Name().IsEqual((Standard_CString)SHAPESECTION_POS) && !theIStream.eof());
237 if (theIStream.eof()) {
238 // There is no shape section in the file.
239 myMsgDriver->Send (aMethStr + "error: shape section is not found", Message_Fail);
240 myReaderStatus = PCDM_RS_ReaderException;
244 aDocumentPos = theIStream.tellg(); // position of root label
246 BinLDrivers_VectorOfDocumentSection::Iterator anIterS (mySections);
247 for (; anIterS.More(); anIterS.Next()) {
248 BinLDrivers_DocumentSection& aCurSection = anIterS.ChangeValue();
249 if (aCurSection.IsPostRead() == Standard_False) {
250 theIStream.seekg ((std::streampos) aCurSection.Offset());
251 if (aCurSection.Name().IsEqual ((Standard_CString)SHAPESECTION_POS))
253 ReadShapeSection (aCurSection, theIStream, false, aPS.Next());
256 myReaderStatus = PCDM_RS_UserBreak;
261 ReadSection (aCurSection, theDoc, theIStream);
264 } else { //aFileVer < 3
265 aDocumentPos = theIStream.tellg(); // position of root label
267 // retrieve SHAPESECTION_POS string
268 char aShapeSecLabel[SIZEOFSHAPELABEL + 1];
269 aShapeSecLabel[SIZEOFSHAPELABEL] = 0x00;
270 theIStream.read ((char*)&aShapeSecLabel, SIZEOFSHAPELABEL);// SHAPESECTION_POS
271 TCollection_AsciiString aShapeLabel(aShapeSecLabel);
272 // detect if a file was written in old fashion (version 2 without shapes)
273 // and if so then skip reading ShapeSection
274 if (aShapeLabel.Length() > 0) {
275 // version 2+(with shapes) and higher goes here
276 if(aShapeLabel.Length() <= 0 || aShapeLabel != SHAPESECTION_POS) {
277 myMsgDriver->Send (aMethStr + "error: Format failure", Message_Fail);
278 myReaderStatus = PCDM_RS_FormatFailure;
282 // retrieve ShapeSection Position
283 Standard_Integer aShapeSectionPos; // go to ShapeSection
284 theIStream.read ((char*)&aShapeSectionPos, sizeof(Standard_Integer));
287 aShapeSectionPos = InverseInt (aShapeSectionPos);
290 std::cout <<"aShapeSectionPos = " <<aShapeSectionPos <<std::endl;
292 if(aShapeSectionPos) {
293 aDocumentPos = theIStream.tellg();
294 theIStream.seekg((std::streampos) aShapeSectionPos);
296 CheckShapeSection(aShapeSectionPos, theIStream);
298 BinLDrivers_DocumentSection aCurSection;
299 ReadShapeSection (aCurSection, theIStream, Standard_False, aPS.Next());
302 myReaderStatus = PCDM_RS_UserBreak;
307 } // end of reading Sections or shape section
309 // Return to read of the Document structure
310 theIStream.seekg(aDocumentPos);
312 // read the header (tag) of the root label
313 Standard_Integer aTag;
314 theIStream.read ((char*)&aTag, sizeof(Standard_Integer));
316 // read sub-tree of the root label
317 Standard_Integer nbRead = ReadSubTree (theIStream, aData->Root(), aPS.Next());
320 myReaderStatus = PCDM_RS_UserBreak;
327 myReaderStatus = PCDM_RS_UserBreak;
333 // attach data to the document
334 aDoc->SetData (aData);
335 TDocStd_Owner::SetDocument (aData, aDoc);
336 aDoc->SetComments(aHeaderData->Comments());
337 myReaderStatus = PCDM_RS_OK;
340 // Read Sections (post-reading type)
341 if (aFileVer >= TDocStd_FormatVersion_VERSION_3) {
342 BinLDrivers_VectorOfDocumentSection::Iterator aSectIter (mySections);
343 for (; aSectIter.More(); aSectIter.Next()) {
344 BinLDrivers_DocumentSection& aCurSection = aSectIter.ChangeValue();
345 if (aCurSection.IsPostRead()) {
346 theIStream.seekg ((std::streampos) aCurSection.Offset());
347 ReadSection (aCurSection, theDoc, theIStream);
353 //=======================================================================
354 //function : ReadSubTree
356 //=======================================================================
358 Standard_Integer BinLDrivers_DocumentRetrievalDriver::ReadSubTree
359 (Standard_IStream& theIS,
360 const TDF_Label& theLabel,
361 const Message_ProgressRange& theRange)
363 Standard_Integer nbRead = 0;
364 TCollection_ExtendedString aMethStr
365 ("BinLDrivers_DocumentRetrievalDriver: ");
367 Message_ProgressScope aPS(theRange, "Reading sub tree", 2, true);
371 while (theIS && myPAtt.TypeId() > 0 && // not an end marker ?
372 myPAtt.Id() > 0 && // not a garbage ?
377 myReaderStatus = PCDM_RS_UserBreak;
381 // get a driver according to TypeId
382 Handle(BinMDF_ADriver) aDriver = myDrivers->GetDriver (myPAtt.TypeId());
383 if (!aDriver.IsNull()) {
384 // create transient attribute
386 Standard_Integer anID = myPAtt.Id();
387 Handle(TDF_Attribute) tAtt;
388 Standard_Boolean isBound = myRelocTable.IsBound(anID);
390 tAtt = Handle(TDF_Attribute)::DownCast(myRelocTable.Find(anID));
392 tAtt = aDriver->NewEmpty();
394 if (tAtt->Label().IsNull())
398 theLabel.AddAttribute (tAtt);
400 catch (const Standard_DomainError&)
402 // For attributes that can have arbitrary GUID (e.g. TDataStd_Integer), exception
403 // will be raised in valid case if attribute of that type with default GUID is already
404 // present on the same label; the reason is that actual GUID will be read later.
405 // To avoid this, set invalid (null) GUID to the newly added attribute (see #29669)
406 static const Standard_GUID fbidGuid;
407 tAtt->SetID (fbidGuid);
408 theLabel.AddAttribute (tAtt);
412 myMsgDriver->Send (aMethStr +
413 "warning: attempt to attach attribute " +
414 aDriver->TypeName() + " to a second label", Message_Warning);
416 Standard_Boolean ok = aDriver->Paste (myPAtt, tAtt, myRelocTable);
418 // error converting persistent to transient
419 myMsgDriver->Send (aMethStr + "warning: failure reading attribute " +
420 aDriver->TypeName(), Message_Warning);
423 myRelocTable.Bind (anID, tAtt);
425 else if (!myMapUnsupported.Contains(myPAtt.TypeId()))
426 myMsgDriver->Send (aMethStr + "warning: type ID not registered in header: "
427 + myPAtt.TypeId(), Message_Warning);
429 // read next attribute
432 if (!theIS || myPAtt.TypeId() != BinLDrivers_ENDATTRLIST) {
433 // unexpected EOF or garbage data
434 myMsgDriver->Send (aMethStr + "error: unexpected EOF or garbage data", Message_Fail);
435 myReaderStatus = PCDM_RS_UnrecognizedFileFormat;
440 // read the tag of a child label
441 Standard_Integer aTag = BinLDrivers_ENDLABEL;
442 theIS.read ((char*) &aTag, sizeof(Standard_Integer));
444 aTag = InverseInt (aTag);
447 while (theIS && aTag >= 0 && !theIS.eof()) { // not an end marker ?
449 TDF_Label aLab = theLabel.FindChild (aTag, Standard_True);
452 myReaderStatus = PCDM_RS_UserBreak;
458 Standard_Integer nbSubRead = ReadSubTree (theIS, aLab, aPS.Next());
464 // read the tag of the next child
465 theIS.read ((char*) &aTag, sizeof(Standard_Integer));
467 aTag = InverseInt (aTag);
471 if (aTag != BinLDrivers_ENDLABEL) {
472 // invalid end label marker
473 myMsgDriver->Send (aMethStr + "error: invalid end label marker", Message_Fail);
474 myReaderStatus = PCDM_RS_UnrecognizedFileFormat;
481 //=======================================================================
482 //function : AttributeDrivers
484 //=======================================================================
486 Handle(BinMDF_ADriverTable) BinLDrivers_DocumentRetrievalDriver::AttributeDrivers
487 (const Handle(Message_Messenger)& theMessageDriver)
489 return BinLDrivers::AttributeDrivers (theMessageDriver);
492 //=======================================================================
493 //function : ReadSection
495 //=======================================================================
497 void BinLDrivers_DocumentRetrievalDriver::ReadSection
498 (BinLDrivers_DocumentSection& /*theSection*/,
499 const Handle(CDM_Document)& /*theDocument*/,
500 Standard_IStream& /*theIS*/)
502 // empty; should be redefined in subclasses
505 //=======================================================================
506 //function : ReadShapeSection
508 //=======================================================================
510 void BinLDrivers_DocumentRetrievalDriver::ReadShapeSection
511 (BinLDrivers_DocumentSection& theSection,
512 Standard_IStream& /*theIS*/,
513 const Standard_Boolean isMess,
514 const Message_ProgressRange &/*theRange*/)
517 if(isMess && theSection.Length()) {
518 const TCollection_ExtendedString aMethStr ("BinLDrivers_DocumentRetrievalDriver: ");
519 myMsgDriver->Send (aMethStr + "warning: Geometry is not supported by Lite schema. ", Message_Warning);
523 //=======================================================================
524 //function : CheckShapeSection
526 //=======================================================================
527 void BinLDrivers_DocumentRetrievalDriver::CheckShapeSection(
528 const Storage_Position& ShapeSectionPos,
529 Standard_IStream& IS)
533 const std::streamoff endPos = IS.rdbuf()->pubseekoff(0L, std::ios_base::end, std::ios_base::in);
535 std::cout << "endPos = " << endPos <<std::endl;
537 if(ShapeSectionPos != endPos) {
538 const TCollection_ExtendedString aMethStr ("BinLDrivers_DocumentRetrievalDriver: ");
539 myMsgDriver->Send (aMethStr + "warning: Geometry is not supported by Lite schema. ", Message_Warning);
544 //=======================================================================
547 //=======================================================================
548 void BinLDrivers_DocumentRetrievalDriver::Clear()
550 myPAtt.Destroy(); // free buffer
551 myRelocTable.Clear();
552 myMapUnsupported.Clear();
555 //=======================================================================
556 //function : CheckDocumentVersion
558 //=======================================================================
559 Standard_Boolean BinLDrivers_DocumentRetrievalDriver::CheckDocumentVersion(
560 const Standard_Integer theFileVersion,
561 const Standard_Integer theCurVersion)
563 if (theFileVersion < TDocStd_FormatVersion_VERSION_2 || theFileVersion > theCurVersion) {
564 // file was written with another version
565 return Standard_False;
567 return Standard_True;