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