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