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