// Created on: 2002-10-31 // Created by: Michael SAZONOV // Copyright (c) 2002-2014 OPEN CASCADE SAS // // This file is part of Open CASCADE Technology software library. // // This library is free software; you can redistribute it and/or modify it under // the terms of the GNU Lesser General Public License version 2.1 as published // by the Free Software Foundation, with special exception defined in the file // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT // distribution for complete text of the license and disclaimer of any warranty. // // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include IMPLEMENT_STANDARD_RTTIEXT(BinLDrivers_DocumentRetrievalDriver,PCDM_RetrievalDriver) #define SHAPESECTION_POS "SHAPE_SECTION_POS:" #define SIZEOFSHAPELABEL 18 #define DATATYPE_MIGRATION //#define DATATYPE_MIGRATION_DEB //======================================================================= //function : BinLDrivers_DocumentRetrievalDriver //purpose : Constructor //======================================================================= BinLDrivers_DocumentRetrievalDriver::BinLDrivers_DocumentRetrievalDriver () { myReaderStatus = PCDM_RS_OK; } //======================================================================= //function : CreateDocument //purpose : pure virtual method definition //======================================================================= Handle(CDM_Document) BinLDrivers_DocumentRetrievalDriver::CreateDocument() { return new TDocStd_Document(PCDM_RetrievalDriver::GetFormat()); } //======================================================================= //function : Read //purpose : //======================================================================= void BinLDrivers_DocumentRetrievalDriver::Read (const TCollection_ExtendedString& theFileName, const Handle(CDM_Document)& theNewDocument, const Handle(CDM_Application)& theApplication, const Handle(Message_ProgressIndicator)& theProgress) { std::ifstream aFileStream; OSD_OpenStream (aFileStream, theFileName, std::ios::in | std::ios::binary); if (aFileStream.is_open() && aFileStream.good()) { Handle(Storage_Data) dData; TCollection_ExtendedString aFormat = PCDM_ReadWriter::FileFormat (aFileStream, dData); Read(aFileStream, dData, theNewDocument, theApplication, theProgress); if (theProgress->UserBreak()) { myReaderStatus = PCDM_RS_UserBreak; return; } } else { myReaderStatus = PCDM_RS_OpenError; } } #define MODIFICATION_COUNTER "MODIFICATION_COUNTER: " #define REFERENCE_COUNTER "REFERENCE_COUNTER: " #define START_TYPES "START_TYPES" #define END_TYPES "END_TYPES" //======================================================================= //function : Read //purpose : //======================================================================= void BinLDrivers_DocumentRetrievalDriver::Read (Standard_IStream& theIStream, const Handle(Storage_Data)& theStorageData, const Handle(CDM_Document)& theDoc, const Handle(CDM_Application)& theApplication, const Handle(Message_ProgressIndicator)& theProgress) { myReaderStatus = PCDM_RS_DriverFailure; myMsgDriver = theApplication -> MessageDriver(); const TCollection_ExtendedString aMethStr ("BinLDrivers_DocumentRetrievalDriver: "); Handle(TDocStd_Document) aDoc = Handle(TDocStd_Document)::DownCast(theDoc); if (aDoc.IsNull()) { #ifdef OCCT_DEBUG myMsgDriver->Send (aMethStr + "error: null document", Message_Fail); #endif myReaderStatus = PCDM_RS_NoDocument; return; } // 1. the information section Handle(Storage_HeaderData) aHeaderData; if (!theStorageData.IsNull()) { aHeaderData = theStorageData->HeaderData(); } if (!aHeaderData.IsNull()) { for (Standard_Integer i = 1; i <= aHeaderData->UserInfo().Length(); i++) { const TCollection_AsciiString& aLine = aHeaderData->UserInfo().Value(i); if(aLine.Search(REFERENCE_COUNTER) != -1) { theDoc->SetReferenceCounter (aLine.Token(" ", 2).IntegerValue()); } else if(aLine.Search(MODIFICATION_COUNTER) != -1) { theDoc->SetModifications (aLine.Token(" ", 2).IntegerValue()); } } } // 1.a Version of writer if (!aHeaderData->StorageVersion().IsIntegerValue()) { // file has no format version myMsgDriver->Send (aMethStr + "error: file has no format version", Message_Fail); myReaderStatus = PCDM_RS_FormatFailure; return; } Standard_Integer aFileVer = aHeaderData->StorageVersion().IntegerValue(); Standard_Integer aCurrVer = BinLDrivers::StorageVersion().IntegerValue(); // maintain one-way compatibility starting from version 2+ if (!CheckDocumentVersion(aFileVer, aCurrVer)) { myReaderStatus = PCDM_RS_NoVersion; // file was written with another version myMsgDriver->Send (aMethStr + "error: wrong file version: " + aHeaderData->StorageVersion() + " while current is " + BinLDrivers::StorageVersion(), Message_Fail); return; } // 1.b Retrieve the Types table TColStd_SequenceOfAsciiString aTypeNames; //Sequence of types in file const TColStd_SequenceOfAsciiString& aUserInfo = aHeaderData->UserInfo(); Standard_Boolean begin = Standard_False; Standard_Integer i; for (i=1; i <= aUserInfo.Length(); i++) { //const TCollection_AsciiString& aStr = aUserInfo(i); TCollection_AsciiString aStr = aUserInfo(i); if (aStr == START_TYPES) begin = Standard_True; else if (aStr == END_TYPES) break; else if (begin) { if ( aFileVer < 8 ) { #ifdef DATATYPE_MIGRATION TCollection_AsciiString newName; if(Storage_Schema::CheckTypeMigration(aStr, newName)) { #ifdef OCCT_DEBUG std::cout << "CheckTypeMigration:OldType = " <Send (aTypeNames(i), Message_Warning); } // 2. Read document contents // 2a. Retrieve data from the stream: myRelocTable.Clear(); myRelocTable.SetHeaderData(aHeaderData); mySections.Clear(); myPAtt.Init(); Handle(TDF_Data) aData = new TDF_Data(); std::streampos aDocumentPos = -1; Message_ProgressSentry aPS(theProgress, "Reading data", 0, 3, 1); // 2b. Read the TOC of Sections if (aFileVer >= 3) { BinLDrivers_DocumentSection aSection; do { BinLDrivers_DocumentSection::ReadTOC (aSection, theIStream, aFileVer); mySections.Append(aSection); } while(!aSection.Name().IsEqual((Standard_CString)SHAPESECTION_POS) && !theIStream.eof()); if (theIStream.eof()) { // There is no shape section in the file. myMsgDriver->Send (aMethStr + "error: shape section is not found", Message_Fail); myReaderStatus = PCDM_RS_ReaderException; return; } aDocumentPos = theIStream.tellg(); // position of root label BinLDrivers_VectorOfDocumentSection::Iterator anIterS (mySections); for (; anIterS.More(); anIterS.Next()) { BinLDrivers_DocumentSection& aCurSection = anIterS.ChangeValue(); if (aCurSection.IsPostRead() == Standard_False) { theIStream.seekg ((std::streampos) aCurSection.Offset()); if (aCurSection.Name().IsEqual ((Standard_CString)SHAPESECTION_POS)) { ReadShapeSection (aCurSection, theIStream, false, theProgress); if (!aPS.More()) { myReaderStatus = PCDM_RS_UserBreak; return; } aPS.Next(); } else ReadSection (aCurSection, theDoc, theIStream); } } } else { //aFileVer < 3 aDocumentPos = theIStream.tellg(); // position of root label // retrieve SHAPESECTION_POS string char aShapeSecLabel[SIZEOFSHAPELABEL + 1]; aShapeSecLabel[SIZEOFSHAPELABEL] = 0x00; theIStream.read ((char*)&aShapeSecLabel, SIZEOFSHAPELABEL);// SHAPESECTION_POS TCollection_AsciiString aShapeLabel(aShapeSecLabel); // detect if a file was written in old fashion (version 2 without shapes) // and if so then skip reading ShapeSection if (aShapeLabel.Length() > 0) { // version 2+(with shapes) and higher goes here if(aShapeLabel.Length() <= 0 || aShapeLabel != SHAPESECTION_POS) { myMsgDriver->Send (aMethStr + "error: Format failure", Message_Fail); myReaderStatus = PCDM_RS_FormatFailure; return; } // retrieve ShapeSection Position Standard_Integer aShapeSectionPos; // go to ShapeSection theIStream.read ((char*)&aShapeSectionPos, sizeof(Standard_Integer)); #if DO_INVERSE aShapeSectionPos = InverseInt (aShapeSectionPos); #endif #ifdef OCCT_DEBUG std::cout <<"aShapeSectionPos = " <Root(), theProgress); if (!aPS.More()) { myReaderStatus = PCDM_RS_UserBreak; return; } aPS.Next(); Clear(); if (!aPS.More()) { myReaderStatus = PCDM_RS_UserBreak; return; } aPS.Next(); if (nbRead > 0) { // attach data to the document aDoc->SetData (aData); TDocStd_Owner::SetDocument (aData, aDoc); aDoc->SetComments(aHeaderData->Comments()); myReaderStatus = PCDM_RS_OK; } // Read Sections (post-reading type) if (aFileVer >= 3) { BinLDrivers_VectorOfDocumentSection::Iterator aSectIter (mySections); for (; aSectIter.More(); aSectIter.Next()) { BinLDrivers_DocumentSection& aCurSection = aSectIter.ChangeValue(); if (aCurSection.IsPostRead()) { theIStream.seekg ((std::streampos) aCurSection.Offset()); ReadSection (aCurSection, theDoc, theIStream); } } } } //======================================================================= //function : ReadSubTree //purpose : //======================================================================= Standard_Integer BinLDrivers_DocumentRetrievalDriver::ReadSubTree (Standard_IStream& theIS, const TDF_Label& theLabel, const Handle(Message_ProgressIndicator)& theProgress) { Standard_Integer nbRead = 0; TCollection_ExtendedString aMethStr ("BinLDrivers_DocumentRetrievalDriver: "); Message_ProgressSentry aPS(theProgress, "Reading sub tree", 0, 2, 1, true); // Read attributes: theIS >> myPAtt; while (theIS && myPAtt.TypeId() > 0 && // not an end marker ? myPAtt.Id() > 0 && // not a garbage ? !theIS.eof()) { if (!aPS.More()) { myReaderStatus = PCDM_RS_UserBreak; return -1; } // get a driver according to TypeId Handle(BinMDF_ADriver) aDriver = myDrivers->GetDriver (myPAtt.TypeId()); if (!aDriver.IsNull()) { // create transient attribute nbRead++; Standard_Integer anID = myPAtt.Id(); Handle(TDF_Attribute) tAtt; Standard_Boolean isBound = myRelocTable.IsBound(anID); if (isBound) tAtt = Handle(TDF_Attribute)::DownCast(myRelocTable.Find(anID)); else tAtt = aDriver->NewEmpty(); if (tAtt->Label().IsNull()) { try { theLabel.AddAttribute (tAtt); } catch (const Standard_DomainError&) { // For attributes that can have arbitrary GUID (e.g. TDataStd_Integer), exception // will be raised in valid case if attribute of that type with default GUID is already // present on the same label; the reason is that actual GUID will be read later. // To avoid this, set invalid (null) GUID to the newly added attribute (see #29669) static const Standard_GUID fbidGuid; tAtt->SetID (fbidGuid); theLabel.AddAttribute (tAtt); } } else myMsgDriver->Send (aMethStr + "warning: attempt to attach attribute " + aDriver->TypeName() + " to a second label", Message_Warning); Standard_Boolean ok = aDriver->Paste (myPAtt, tAtt, myRelocTable); if (!ok) { // error converting persistent to transient myMsgDriver->Send (aMethStr + "warning: failure reading attribute " + aDriver->TypeName(), Message_Warning); } else if (!isBound) myRelocTable.Bind (anID, tAtt); } else if (!myMapUnsupported.Contains(myPAtt.TypeId())) myMsgDriver->Send (aMethStr + "warning: type ID not registered in header: " + myPAtt.TypeId(), Message_Warning); // read next attribute theIS >> myPAtt; } if (!theIS || myPAtt.TypeId() != BinLDrivers_ENDATTRLIST) { // unexpected EOF or garbage data myMsgDriver->Send (aMethStr + "error: unexpected EOF or garbage data", Message_Fail); myReaderStatus = PCDM_RS_UnrecognizedFileFormat; return -1; } // Read children: // read the tag of a child label Standard_Integer aTag = BinLDrivers_ENDLABEL; theIS.read ((char*) &aTag, sizeof(Standard_Integer)); #if DO_INVERSE aTag = InverseInt (aTag); #endif while (theIS && aTag >= 0 && !theIS.eof()) { // not an end marker ? // create sub-label TDF_Label aLab = theLabel.FindChild (aTag, Standard_True); if (!aPS.More()) { myReaderStatus = PCDM_RS_UserBreak; return -1; } aPS.Next(); // read sub-tree Standard_Integer nbSubRead = ReadSubTree (theIS, aLab, theProgress); // check for error if (nbSubRead == -1) return -1; nbRead += nbSubRead; // read the tag of the next child theIS.read ((char*) &aTag, sizeof(Standard_Integer)); #if DO_INVERSE aTag = InverseInt (aTag); #endif } if (aTag != BinLDrivers_ENDLABEL) { // invalid end label marker myMsgDriver->Send (aMethStr + "error: invalid end label marker", Message_Fail); myReaderStatus = PCDM_RS_UnrecognizedFileFormat; return -1; } return nbRead; } //======================================================================= //function : AttributeDrivers //purpose : //======================================================================= Handle(BinMDF_ADriverTable) BinLDrivers_DocumentRetrievalDriver::AttributeDrivers (const Handle(Message_Messenger)& theMessageDriver) { return BinLDrivers::AttributeDrivers (theMessageDriver); } //======================================================================= //function : ReadSection //purpose : //======================================================================= void BinLDrivers_DocumentRetrievalDriver::ReadSection (BinLDrivers_DocumentSection& /*theSection*/, const Handle(CDM_Document)& /*theDocument*/, Standard_IStream& /*theIS*/) { // empty; should be redefined in subclasses } //======================================================================= //function : ReadShapeSection //purpose : //======================================================================= void BinLDrivers_DocumentRetrievalDriver::ReadShapeSection (BinLDrivers_DocumentSection& theSection, Standard_IStream& /*theIS*/, const Standard_Boolean isMess, const Handle(Message_ProgressIndicator) &/*theProgress*/) { if(isMess && theSection.Length()) { const TCollection_ExtendedString aMethStr ("BinLDrivers_DocumentRetrievalDriver: "); myMsgDriver->Send (aMethStr + "warning: Geometry is not supported by Lite schema. ", Message_Warning); } } //======================================================================= //function : CheckShapeSection //purpose : //======================================================================= void BinLDrivers_DocumentRetrievalDriver::CheckShapeSection( const Storage_Position& ShapeSectionPos, Standard_IStream& IS) { if (!IS.eof()) { const std::streamoff endPos = IS.rdbuf()->pubseekoff(0L, std::ios_base::end, std::ios_base::in); #ifdef OCCT_DEBUG std::cout << "endPos = " << endPos <Send (aMethStr + "warning: Geometry is not supported by Lite schema. ", Message_Warning); } } } //======================================================================= //function : Clear //purpose : //======================================================================= void BinLDrivers_DocumentRetrievalDriver::Clear() { myPAtt.Destroy(); // free buffer myRelocTable.Clear(); myMapUnsupported.Clear(); } //======================================================================= //function : CheckDocumentVersion //purpose : //======================================================================= Standard_Boolean BinLDrivers_DocumentRetrievalDriver::CheckDocumentVersion( const Standard_Integer theFileVersion, const Standard_Integer theCurVersion) { if (theFileVersion < 2 || theFileVersion > theCurVersion) { // file was written with another version return Standard_False; } return Standard_True; }