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