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 <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>
44 IMPLEMENT_STANDARD_RTTIEXT(BinLDrivers_DocumentRetrievalDriver,PCDM_RetrievalDriver)
46 #define SHAPESECTION_POS "SHAPE_SECTION_POS:"
47 #define SIZEOFSHAPELABEL 18
49 #define DATATYPE_MIGRATION
50 //#define DATATYPE_MIGRATION_DEB
51 //=======================================================================
52 //function : BinLDrivers_DocumentRetrievalDriver
53 //purpose : Constructor
54 //=======================================================================
56 BinLDrivers_DocumentRetrievalDriver::BinLDrivers_DocumentRetrievalDriver ()
58 myReaderStatus = PCDM_RS_OK;
61 //=======================================================================
62 //function : CreateDocument
63 //purpose : pure virtual method definition
64 //=======================================================================
66 Handle(CDM_Document) BinLDrivers_DocumentRetrievalDriver::CreateDocument()
68 return new TDocStd_Document(PCDM_RetrievalDriver::GetFormat());
71 //=======================================================================
72 //function : SchemaName
73 //purpose : pure virtual method definition
74 //=======================================================================
76 TCollection_ExtendedString BinLDrivers_DocumentRetrievalDriver::SchemaName() const
78 TCollection_ExtendedString schemaname;
82 //=======================================================================
84 //purpose : pure virtual method definition
85 //=======================================================================
87 void BinLDrivers_DocumentRetrievalDriver::Make (const Handle(PCDM_Document)&,
88 const Handle(CDM_Document)&)
92 //=======================================================================
95 //=======================================================================
97 #define START_TYPES "START_TYPES"
98 #define END_TYPES "END_TYPES"
100 void BinLDrivers_DocumentRetrievalDriver::Read
101 (const TCollection_ExtendedString& theFileName,
102 const Handle(CDM_Document)& theNewDocument,
103 const Handle(CDM_Application)& theApplication)
105 myReaderStatus = PCDM_RS_DriverFailure;
106 myMsgDriver = theApplication -> MessageDriver();
108 const TCollection_ExtendedString aMethStr
109 ("BinLDrivers_DocumentRetrievalDriver: ");
111 Handle(TDocStd_Document) aDoc =
112 Handle(TDocStd_Document)::DownCast(theNewDocument);
115 WriteMessage (aMethStr + "error: null document");
117 myReaderStatus = PCDM_RS_NoDocument;
121 TCollection_AsciiString aFileName (theFileName);
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;
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;
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());
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;
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)
164 if ( aFileVer < 8 ) {
165 #ifdef DATATYPE_MIGRATION
166 TCollection_AsciiString newName;
167 if(Storage_Schema::CheckTypeMigration(aStr, newName)) {
169 cout << "CheckTypeMigration:OldType = " <<aStr << " Len = "<<aStr.Length()<<endl;
170 cout << "CheckTypeMigration:NewType = " <<newName << " Len = "<< newName.Length()<<endl;
176 aTypeNames.Append (aStr);
179 if (myDrivers.IsNull())
180 myDrivers = AttributeDrivers (myMsgDriver);
181 myDrivers->AssignIds (aTypeNames);
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));
196 // Open the file stream
198 ifstream anIS ((const wchar_t*) theFileName.ToExtString(), ios::in | ios::binary);
200 ifstream anIS (aFileName.ToCString());
205 WriteMessage (aMethStr + "error: can't open file " + theFileName);
206 myReaderStatus = PCDM_RS_OpenError;
211 anIS.seekg( (streampos) anInfoSectionEnd );
213 // propagate the opened document version to data drivers
214 PropagateDocumentVersion(aFileVer);
216 // 2. Read document contents
218 // 2a. Retrieve data from the stream:
219 myRelocTable.Clear();
222 Handle(TDF_Data) aData = new TDF_Data();
223 streampos aDocumentPos = -1;
225 // 2b. Read the TOC of Sections
227 BinLDrivers_DocumentSection aSection;
229 BinLDrivers_DocumentSection::ReadTOC (aSection, anIS);
230 mySections.Append(aSection);
232 (!aSection.Name().IsEqual((Standard_CString)SHAPESECTION_POS));
233 aDocumentPos = anIS.tellg(); // position of root label
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);
243 ReadSection (aCurSection, theNewDocument, anIS);
246 } else { //aFileVer < 3
247 aDocumentPos = anIS.tellg(); // position of root label
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;
264 // retrieve ShapeSection Position
265 Standard_Integer aShapeSectionPos; // go to ShapeSection
266 anIS.read ((char*)&aShapeSectionPos, sizeof(Standard_Integer));
269 aShapeSectionPos = InverseInt (aShapeSectionPos);
272 cout <<"aShapeSectionPos = " <<aShapeSectionPos <<endl;
274 if(aShapeSectionPos) {
275 aDocumentPos = anIS.tellg();
276 anIS.seekg((streampos) aShapeSectionPos);
278 CheckShapeSection(aShapeSectionPos, anIS);
280 BinLDrivers_DocumentSection aCurSection;
281 ReadShapeSection (aCurSection, anIS, Standard_False);
284 } // end of reading Sections or shape section
286 // Return to read of the Document structure
287 anIS.seekg(aDocumentPos);
289 // read the header (tag) of the root label
290 Standard_Integer aTag;
291 anIS.read ((char*)&aTag, sizeof(Standard_Integer));
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();
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;
307 // Read Sections (post-reading type)
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);
320 //=======================================================================
321 //function : ReadSubTree
323 //=======================================================================
325 Standard_Integer BinLDrivers_DocumentRetrievalDriver::ReadSubTree
326 (Standard_IStream& theIS,
327 const TDF_Label& theLabel)
329 Standard_Integer nbRead = 0;
330 static TCollection_ExtendedString aMethStr
331 ("BinLDrivers_DocumentRetrievalDriver: ");
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
342 Standard_Integer anID = myPAtt.Id();
343 Handle(TDF_Attribute) tAtt;
344 Standard_Boolean isBound = myRelocTable.IsBound(anID);
346 tAtt = Handle(TDF_Attribute)::DownCast(myRelocTable.Find(anID));
348 tAtt = aDriver->NewEmpty();
349 if (tAtt->Label().IsNull())
350 theLabel.AddAttribute (tAtt);
352 WriteMessage (aMethStr +
353 "warning: attempt to attach attribute " +
354 aDriver->TypeName() + " to a second label");
356 Standard_Boolean ok = aDriver->Paste (myPAtt, tAtt, myRelocTable);
358 // error converting persistent to transient
359 WriteMessage (aMethStr + "warning: failure reading attribute " +
360 aDriver->TypeName());
363 myRelocTable.Bind (anID, tAtt);
365 else if (!myMapUnsupported.Contains(myPAtt.TypeId()))
366 WriteMessage (aMethStr + "warning: type ID not registered in header: "
369 // read next attribute
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;
380 // read the tag of a child label
381 Standard_Integer aTag = BinLDrivers_ENDLABEL;
382 theIS.read ((char*) &aTag, sizeof(Standard_Integer));
384 aTag = InverseInt (aTag);
386 while (theIS && aTag >= 0) { // not an end marker ?
388 TDF_Label aLab = theLabel.FindChild (aTag, Standard_True);
391 Standard_Integer nbSubRead = ReadSubTree(theIS, aLab);
397 // read the tag of the next child
398 theIS.read ((char*) &aTag, sizeof(Standard_Integer));
400 aTag = InverseInt (aTag);
403 if (aTag != BinLDrivers_ENDLABEL) {
404 // invalid end label marker
405 WriteMessage (aMethStr + "error: invalid end label marker");
406 myReaderStatus = PCDM_RS_UnrecognizedFileFormat;
413 //=======================================================================
414 //function : AttributeDrivers
416 //=======================================================================
418 Handle(BinMDF_ADriverTable) BinLDrivers_DocumentRetrievalDriver::AttributeDrivers
419 (const Handle(CDM_MessageDriver)& theMessageDriver)
421 return BinLDrivers::AttributeDrivers (theMessageDriver);
424 //=======================================================================
425 //function : ReadInfoSection
426 //purpose : Read the info section of theFile, return a file
427 // position corresponding to the info section end
428 //=======================================================================
430 Storage_Position BinLDrivers_DocumentRetrievalDriver::ReadInfoSection
431 (const TCollection_AsciiString& theFileName,
432 Handle(Storage_HeaderData)& theData)
434 TCollection_ExtendedString aMsg
435 ( "BinLDrivers_DocumentRetrievalDriver: error: ");
437 FSD_BinaryFile aFileDriver;
438 Storage_Position aPos = 0;
439 if (aFileDriver.Open( theFileName, Storage_VSRead ) == Storage_VSOk)
441 Storage_Schema aSchema;
442 theData = aSchema.ReadHeaderSection( aFileDriver );
444 if (theData->ErrorStatus() == Storage_VSOk)
445 aPos = aFileDriver.Tell();
447 WriteMessage( aMsg + theData->ErrorStatusExtension() );
450 WriteMessage( aMsg + "can not open file " + theFileName);
457 //=======================================================================
458 //function : WriteMessage
459 //purpose : write theMessage to the MessageDriver of
461 //=======================================================================
463 void BinLDrivers_DocumentRetrievalDriver::WriteMessage
464 (const TCollection_ExtendedString& theMsg)
466 if (!myMsgDriver.IsNull())
467 myMsgDriver->Write (theMsg.ToExtString());
470 //=======================================================================
471 //function : ReadSection
473 //=======================================================================
475 void BinLDrivers_DocumentRetrievalDriver::ReadSection
476 (BinLDrivers_DocumentSection& /*theSection*/,
477 const Handle(CDM_Document)& /*theDocument*/,
478 Standard_IStream& /*theIS*/)
480 // empty; should be redefined in subclasses
483 //=======================================================================
484 //function : ReadShapeSection
486 //=======================================================================
488 void BinLDrivers_DocumentRetrievalDriver::ReadShapeSection
489 (BinLDrivers_DocumentSection& theSection,
490 Standard_IStream& /*theIS*/,
491 const Standard_Boolean isMess)
494 if(isMess && theSection.Length()) {
495 const TCollection_ExtendedString aMethStr ("BinLDrivers_DocumentRetrievalDriver: ");
496 WriteMessage (aMethStr + "warning: Geometry is not supported by Lite schema. ");
500 //=======================================================================
501 //function : CheckShapeSection
503 //=======================================================================
504 void BinLDrivers_DocumentRetrievalDriver::CheckShapeSection(
505 const Storage_Position& ShapeSectionPos,
506 Standard_IStream& IS)
510 const std::streamoff endPos = IS.rdbuf()->pubseekoff(0L, std::ios_base::end, std::ios_base::in);
512 cout << "endPos = " << endPos <<endl;
514 if(ShapeSectionPos != endPos) {
515 const TCollection_ExtendedString aMethStr ("BinLDrivers_DocumentRetrievalDriver: ");
516 WriteMessage (aMethStr + "warning: Geometry is not supported by Lite schema. ");
521 //=======================================================================
522 //function : PropagateDocumentVersion
524 //=======================================================================
525 void BinLDrivers_DocumentRetrievalDriver::PropagateDocumentVersion(const Standard_Integer theDocVersion )
527 BinMDataStd::SetDocumentVersion(theDocVersion);
530 //=======================================================================
531 //function : CheckDocumentVersion
533 //=======================================================================
534 Standard_Boolean BinLDrivers_DocumentRetrievalDriver::CheckDocumentVersion(
535 const Standard_Integer theFileVersion,
536 const Standard_Integer theCurVersion)
538 if (theFileVersion < 2 || theFileVersion > theCurVersion) {
539 // file was written with another version
540 return Standard_False;
542 return Standard_True;