0025812: Replace dynamic loading mechanism of OCAF persistence with dynamic-link one
[occt.git] / src / BinLDrivers / BinLDrivers_DocumentStorageDriver.cxx
CommitLineData
b311480e 1// Created on: 2002-10-29
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_DocumentSection.hxx>
19#include <BinLDrivers_DocumentStorageDriver.hxx>
7fd59977 20#include <BinLDrivers_Marker.hxx>
21#include <BinMDF_ADriver.hxx>
42cf5bc1 22#include <BinMDF_ADriverTable.hxx>
7fd59977 23#include <BinObjMgt_Persistent.hxx>
24#include <CDM_Application.hxx>
42cf5bc1 25#include <CDM_Document.hxx>
26#include <CDM_MessageDriver.hxx>
7fd59977 27#include <FSD_BinaryFile.hxx>
28#include <FSD_FileHeader.hxx>
4ff92abe 29#include <OSD_OpenFile.hxx>
7fd59977 30#include <PCDM_ReadWriter.hxx>
31#include <Standard_ErrorHandler.hxx>
42cf5bc1 32#include <Standard_Type.hxx>
7fd59977 33#include <Storage_Schema.hxx>
42cf5bc1 34#include <TCollection_AsciiString.hxx>
35#include <TCollection_ExtendedString.hxx>
7fd59977 36#include <TColStd_Array1OfInteger.hxx>
37#include <TColStd_ListIteratorOfListOfInteger.hxx>
38#include <TColStd_ListOfInteger.hxx>
7fd59977 39#include <TDF_AttributeIterator.hxx>
40#include <TDF_ChildIterator.hxx>
41#include <TDF_Data.hxx>
42cf5bc1 42#include <TDF_Label.hxx>
7fd59977 43#include <TDF_Tool.hxx>
44#include <TDocStd_Document.hxx>
45
92efcf78 46IMPLEMENT_STANDARD_RTTIEXT(BinLDrivers_DocumentStorageDriver,PCDM_StorageDriver)
47
7fd59977 48#define SHAPESECTION_POS (Standard_CString)"SHAPE_SECTION_POS:"
49
50//=======================================================================
51//function : BinLDrivers_DocumentStorageDriver
52//purpose : Constructor
53//=======================================================================
54
55BinLDrivers_DocumentStorageDriver::BinLDrivers_DocumentStorageDriver ()
56{
57}
58
7fd59977 59//=======================================================================
60//function : Write
61//purpose :
62//=======================================================================
63
64void BinLDrivers_DocumentStorageDriver::Write
65 (const Handle(CDM_Document)& theDocument,
66 const TCollection_ExtendedString& theFileName)
67{
15e8b082
M
68 SetIsError(Standard_False);
69 SetStoreStatus(PCDM_SS_OK);
70
4ff92abe 71 myFileName = theFileName;
72
73 std::ofstream aFileStream;
74 OSD_OpenStream (aFileStream, theFileName, std::ios::out | std::ios::binary);
75
76 if (aFileStream.is_open() && aFileStream.good())
77 {
78 Write (theDocument, aFileStream);
79 }
80 else
81 {
82 SetIsError (Standard_True);
83 SetStoreStatus(PCDM_SS_WriteFailure);
84 }
85}
86
87//=======================================================================
88//function : Write
89//purpose :
90//=======================================================================
91
92void BinLDrivers_DocumentStorageDriver::Write (const Handle(CDM_Document)& theDoc, Standard_OStream& theOStream)
93{
94 myMsgDriver = theDoc->Application()->MessageDriver();
7fd59977 95 myMapUnsupported.Clear();
96
7fd59977 97 Handle(TDocStd_Document) aDoc =
4ff92abe 98 Handle(TDocStd_Document)::DownCast(theDoc);
7fd59977 99 if (aDoc.IsNull()) {
15e8b082
M
100 SetIsError(Standard_True);
101 SetStoreStatus(PCDM_SS_Doc_IsNull);
7fd59977 102 }
103 else {
7fd59977 104 // First pass: collect empty labels, assign IDs to the types
105 if (myDrivers.IsNull())
106 myDrivers = AttributeDrivers (myMsgDriver);
107 Handle(TDF_Data) aData = aDoc->GetData();
108 FirstPass (aData->Root());
109
110// 1. Write info section (including types table)
4ff92abe 111 WriteInfoSection (aDoc, theOStream);
112
7fd59977 113 myTypesMap.Clear();
15e8b082
M
114 if (IsError())
115 {
116 SetStoreStatus(PCDM_SS_Info_Section_Error);
117 return;
118 }
7fd59977 119
7fd59977 120
7fd59977 121
122// 2. Write the Table of Contents of Sections
4ff92abe 123 BinLDrivers_VectorOfDocumentSection::Iterator anIterS (mySections);
124 for (; anIterS.More(); anIterS.Next())
125 anIterS.ChangeValue().WriteTOC (theOStream);
7fd59977 126
4ff92abe 127 // Shapes Section is the last one, it indicates the end of the table.
128 BinLDrivers_DocumentSection aShapesSection (SHAPESECTION_POS,
129 Standard_False);
130 aShapesSection.WriteTOC (theOStream);
7fd59977 131
132// 3. Write document contents
4ff92abe 133 // (Storage data to the stream)
134 myRelocTable.Clear();
135 myPAtt.Init();
7fd59977 136
4ff92abe 137// Write Doc structure
138 WriteSubTree (aData->Root(), theOStream); // Doc is written
7fd59977 139
140// 4. Write Shapes section
4ff92abe 141 WriteShapeSection (aShapesSection, theOStream);
142
143 // Write application-defined sections
144 for (anIterS.Init (mySections); anIterS.More(); anIterS.Next()) {
145 BinLDrivers_DocumentSection& aSection = anIterS.ChangeValue();
146 const Standard_Size aSectionOffset = (Standard_Size) theOStream.tellp();
147 WriteSection (aSection.Name(), aDoc, theOStream);
148 aSection.Write (theOStream, aSectionOffset);
149 }
150
151 // End of processing: close structures and check the status
152 myPAtt.Destroy(); // free buffer
153 myEmptyLabels.Clear();
154 myMapUnsupported.Clear();
155
156 if (!myRelocTable.Extent()) {
157 // No objects written
0797d9d3 158#ifdef OCCT_DEBUG
4ff92abe 159 WriteMessage ("BinLDrivers_DocumentStorageDriver, no objects written");
7fd59977 160#endif
4ff92abe 161 SetIsError(Standard_True);
162 SetStoreStatus(PCDM_SS_No_Obj);
7fd59977 163 }
4ff92abe 164 myRelocTable.Clear();
7fd59977 165
4ff92abe 166 if (!theOStream) {
7fd59977 167 // A problem with the stream
0797d9d3 168#ifdef OCCT_DEBUG
169 TCollection_ExtendedString anErrorStr ("Error: ");
170 WriteMessage (anErrorStr + "BinLDrivers_DocumentStorageDriver, Problem with the file stream, rdstate="
4ff92abe 171 + (Standard_Integer )theOStream.rdstate());
7fd59977 172#endif
15e8b082 173 SetIsError(Standard_True);
566f8441 174 SetStoreStatus(PCDM_SS_WriteFailure);
7fd59977 175 }
176
177 }
178}
179
180//=======================================================================
181//function : UnsupportedAttrMsg
9293178b 182//purpose :
7fd59977 183//=======================================================================
184
185void BinLDrivers_DocumentStorageDriver::UnsupportedAttrMsg
186 (const Handle(Standard_Type)& theType)
187{
0797d9d3 188#ifdef OCCT_DEBUG
7fd59977 189 static TCollection_ExtendedString aMsg
190 ("BinDrivers_DocumentStorageDriver: warning: attribute driver for type ");
191#endif
192 if (!myMapUnsupported.Contains(theType)) {
193 myMapUnsupported.Add(theType);
0797d9d3 194#ifdef OCCT_DEBUG
7fd59977 195 WriteMessage (aMsg + theType->Name() + " not found");
196#endif
197 }
198}
199
200//=======================================================================
201//function : WriteSubTree
202//purpose :
203//=======================================================================
204
205void BinLDrivers_DocumentStorageDriver::WriteSubTree
206 (const TDF_Label& theLabel,
207 Standard_OStream& theOS)
208{
209 // Skip empty labels
210 if (!myEmptyLabels.IsEmpty() && myEmptyLabels.First() == theLabel) {
211 myEmptyLabels.RemoveFirst();
212 return;
213 }
214
215 // Write label header: tag
216 Standard_Integer aTag = theLabel.Tag();
217#if DO_INVERSE
218 aTag = InverseInt (aTag);
219#endif
220 theOS.write ((char*)&aTag, sizeof(Standard_Integer));
221
222 // Write attributes
223 TDF_AttributeIterator itAtt (theLabel);
224 for ( ; itAtt.More() && theOS; itAtt.Next()) {
225 const Handle(TDF_Attribute)& tAtt = itAtt.Value();
226 const Handle(Standard_Type)& aType = tAtt->DynamicType();
227 // Get type ID and driver
228 Handle(BinMDF_ADriver) aDriver;
229 const Standard_Integer aTypeId = myDrivers->GetDriver (aType,aDriver);
230 if (aTypeId > 0) {
231 // Add source to relocation table
232 const Standard_Integer anId = myRelocTable.Add (tAtt);
233
234 // Create and fill data item
235 myPAtt.SetTypeId (aTypeId);
236 myPAtt.SetId (anId);
237 aDriver->Paste (tAtt, myPAtt, myRelocTable);
238
239 // Write data to the stream -->!!!
240 theOS << myPAtt;
241 }
0797d9d3 242#ifdef OCCT_DEBUG
7fd59977 243 else
244 UnsupportedAttrMsg (aType);
245#endif
246 }
247 if (!theOS) {
248 // Problem with the stream
249 return;
250 }
251
252 // Write the end attributes list marker
253 BinLDrivers_Marker anEndAttr = BinLDrivers_ENDATTRLIST;
254#if DO_INVERSE
255 anEndAttr = (BinLDrivers_Marker) InverseInt (anEndAttr);
256#endif
257 theOS.write ((char*)&anEndAttr, sizeof(anEndAttr));
258
259 // Process sub-labels
260 TDF_ChildIterator itChld (theLabel);
261 for ( ; itChld.More(); itChld.Next())
262 {
263 const TDF_Label& aChildLab = itChld.Value();
264 WriteSubTree (aChildLab, theOS);
265 }
266
267 // Write the end label marker
268 BinLDrivers_Marker anEndLabel = BinLDrivers_ENDLABEL;
269#if DO_INVERSE
270 anEndLabel = (BinLDrivers_Marker) InverseInt (anEndLabel);
271#endif
272 theOS.write ((char*)&anEndLabel, sizeof(anEndLabel));
273
274}
275
7fd59977 276//=======================================================================
277//function : AttributeDrivers
278//purpose :
279//=======================================================================
280
281Handle(BinMDF_ADriverTable) BinLDrivers_DocumentStorageDriver::AttributeDrivers
282 (const Handle(CDM_MessageDriver)& theMessageDriver)
283{
284 return BinLDrivers::AttributeDrivers (theMessageDriver);
285}
286
287//=======================================================================
288//function : FirstPassSubTree
289//purpose :
290//=======================================================================
291
292Standard_Boolean BinLDrivers_DocumentStorageDriver::FirstPassSubTree
293 (const TDF_Label& L,
294 TDF_LabelList& ListOfEmptyL)
295{
296 // are there writable attributes on L ?
297 Standard_Boolean hasAttr = Standard_False;
298 TDF_AttributeIterator itAtt (L);
299 for ( ; itAtt.More(); itAtt.Next()) {
300 const Handle(Standard_Type)& aType = itAtt.Value()->DynamicType();
301 Handle(BinMDF_ADriver) aDriver;
302 // do not rely on a value returned by GetDriver here, because
303 // the IDs have not yet been assigned to the types
304 myDrivers->GetDriver (aType, aDriver);
305 if (!aDriver.IsNull()) {
306 hasAttr = Standard_True;
307 myTypesMap.Add (aType);
308 }
0797d9d3 309#ifdef OCCT_DEBUG
7fd59977 310 else
311 UnsupportedAttrMsg (aType);
312#endif
313 }
314
315 // are there writable attributes on sub-labels ?
316 Standard_Boolean hasChildAttr = Standard_False;
317 TDF_LabelList emptyChildrenList;
318 TDF_ChildIterator itChld (L);
319 for ( ; itChld.More(); itChld.Next())
320 {
321 if (FirstPassSubTree (itChld.Value(), emptyChildrenList))
322 emptyChildrenList.Append( itChld.Value() );
323 else
324 hasChildAttr = Standard_True;
325 }
326
327 Standard_Boolean isEmpty = !(hasAttr || hasChildAttr);
328
329 if (!isEmpty)
330 ListOfEmptyL.Append( emptyChildrenList );
331
332 return isEmpty;
333}
334
335//=======================================================================
336//function : FirstPass
337//purpose :
338//=======================================================================
339
340void BinLDrivers_DocumentStorageDriver::FirstPass
341 (const TDF_Label& theRoot)
342{
343 myTypesMap.Clear();
344 myEmptyLabels.Clear();
345
346 if (FirstPassSubTree( theRoot, myEmptyLabels))
347 myEmptyLabels.Append( theRoot );
348
349 myDrivers->AssignIds (myTypesMap);
350}
351
352//=======================================================================
353//function : WriteInfoSection
354//purpose : Write info secton using FSD_BinaryFile driver
355//=======================================================================
356
357#define START_TYPES "START_TYPES"
358#define END_TYPES "END_TYPES"
359
4ff92abe 360void BinLDrivers_DocumentStorageDriver::WriteInfoSection
361 (const Handle(CDM_Document)& theDoc,
362 Standard_OStream& theOStream)
7fd59977 363{
4ff92abe 364 // Magic number
365 theOStream.write (FSD_BinaryFile::MagicNumber(), strlen(FSD_BinaryFile::MagicNumber()));
366
367 FSD_FileHeader aHeader;
368
369 {
370 aHeader.testindian = -1;
371 aHeader.binfo = -1;
372 aHeader.einfo = -1;
373 aHeader.bcomment = -1;
374 aHeader.ecomment = -1;
375 aHeader.btype = -1;
376 aHeader.etype = -1;
377 aHeader.broot = -1;
378 aHeader.eroot = -1;
379 aHeader.bref = -1;
380 aHeader.eref = -1;
381 aHeader.bdata = -1;
382 aHeader.edata = -1;
383 }
384
385 // aHeader.testindian
386 {
387 union {
388 char ti2[4];
389 Standard_Integer aResult;
390 } aWrapUnion;
391
392 aWrapUnion.ti2[0] = 1;
393 aWrapUnion.ti2[1] = 2;
394 aWrapUnion.ti2[2] = 3;
395 aWrapUnion.ti2[3] = 4;
396
397 aHeader.testindian = aWrapUnion.aResult;
7fd59977 398 }
399
4ff92abe 400 // info section
401 aHeader.binfo = (Standard_Integer)theOStream.tellp();
402
403 // header section
404 aHeader.einfo = aHeader.binfo + FSD_BinaryFile::WriteHeader (theOStream, aHeader, Standard_True);
405
406 // add format
407 Handle(Storage_Data) theData = new Storage_Data;
408 PCDM_ReadWriter::WriteFileFormat (theData, theDoc);
409 PCDM_ReadWriter::Writer()->WriteReferenceCounter (theData, theDoc);
410 PCDM_ReadWriter::Writer()->WriteReferences (theData, theDoc, myFileName);
411 PCDM_ReadWriter::Writer()->WriteExtensions (theData, theDoc);
412 PCDM_ReadWriter::Writer()->WriteVersion (theData, theDoc);
413
414 // add the types table
415 theData->AddToUserInfo(START_TYPES);
416 for (Standard_Integer i = 1; i <= myTypesMap.Extent(); i++)
7fd59977 417 {
4ff92abe 418 Handle(BinMDF_ADriver) aDriver = myDrivers->GetDriver(i);
419 if (!aDriver.IsNull())
420 {
421 const TCollection_AsciiString& aTypeName = aDriver->TypeName();
422 theData->AddToUserInfo (aTypeName);
7fd59977 423 }
7fd59977 424 }
4ff92abe 425 theData->AddToUserInfo(END_TYPES);
426
427 Standard_Integer aObjNb = 1;
428 Standard_Integer aShemaVer = 1;
429
430 aHeader.einfo += FSD_BinaryFile::WriteInfo (theOStream,
431 aObjNb,
432 BinLDrivers::StorageVersion(),
433 Storage_Schema::ICreationDate(),
6fe96f84 434 "", // schema name
4ff92abe 435 aShemaVer,
436 theData->ApplicationName(),
437 theData->ApplicationVersion(),
438 theData->DataType(),
439 theData->UserInfo(),
440 Standard_True); // only count the size of the section
441
442 // calculate comment section
443 TColStd_SequenceOfExtendedString aComments;
444 theDoc->Comments(aComments);
445 for (Standard_Integer i = 1; i <= aComments.Length(); i++)
446 {
447 theData->AddToComments (aComments(i));
7fd59977 448 }
4ff92abe 449
450 aHeader.bcomment = aHeader.einfo;
451 aHeader.ecomment = aHeader.bcomment + FSD_BinaryFile::WriteComment(theOStream, theData->Comments(), Standard_True);
452
453 aHeader.edata = aHeader.ecomment;
454
455 // write header information
456 FSD_BinaryFile::WriteHeader (theOStream, aHeader);
457
458 // write info section
459 FSD_BinaryFile::WriteInfo (theOStream,
460 aObjNb,
461 BinLDrivers::StorageVersion(),
462 Storage_Schema::ICreationDate(),
6fe96f84 463 "", // schema name
4ff92abe 464 aShemaVer,
465 theData->ApplicationName(),
466 theData->ApplicationVersion(),
467 theData->DataType(),
468 theData->UserInfo());
469
470 // write the comments
471 FSD_BinaryFile::WriteComment(theOStream, theData->Comments());
472
7fd59977 473}
474
475//=======================================================================
476//function : WriteMessage
477//purpose : write theMessage to the MessageDriver of the
478// Application
479//=======================================================================
480
481void BinLDrivers_DocumentStorageDriver::WriteMessage
482 (const TCollection_ExtendedString& theMsg)
483{
484 if (!myMsgDriver.IsNull())
485 myMsgDriver->Write (theMsg.ToExtString());
486}
487
488//=======================================================================
489//function : AddSection
9293178b 490//purpose :
7fd59977 491//=======================================================================
492
493void BinLDrivers_DocumentStorageDriver::AddSection
494 (const TCollection_AsciiString& theName,
495 const Standard_Boolean isPostRead)
496{
497 mySections.Append (BinLDrivers_DocumentSection (theName, isPostRead));
498}
499
500//=======================================================================
501//function : WriteSection
9293178b 502//purpose :
7fd59977 503//=======================================================================
504
505void BinLDrivers_DocumentStorageDriver::WriteSection
506 (const TCollection_AsciiString& /*theName*/,
857ffd5e 507 const Handle(CDM_Document)& /*theDocument*/,
7fd59977 508 Standard_OStream& /*theOS*/)
509{
510 // empty; should be redefined in subclasses
511}
512
513//=======================================================================
514//function : WriteShapeSection
515//purpose : defines WriteShapeSection
516//=======================================================================
517void BinLDrivers_DocumentStorageDriver::WriteShapeSection
518 (BinLDrivers_DocumentSection& theSection,
519 Standard_OStream& theOS)
520{
521 const Standard_Size aShapesSectionOffset = (Standard_Size) theOS.tellp();
522 theSection.Write (theOS, aShapesSectionOffset);
523}