0031353: TDocStd_Application does not have api to set progress indicator
[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>
6d8f9f4a 45#include <Message_ProgressSentry.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,
68 const Handle(Message_ProgressIndicator)& theProgress)
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 {
6d8f9f4a 80 Write(theDocument, aFileStream, theProgress);
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
6d8f9f4a 94void BinLDrivers_DocumentStorageDriver::Write (const Handle(CDM_Document)& theDoc,
95 Standard_OStream& theOStream,
96 const Handle(Message_ProgressIndicator)& theProgress)
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
7fd59977 127
128// 2. Write the Table of Contents of Sections
4ff92abe 129 BinLDrivers_VectorOfDocumentSection::Iterator anIterS (mySections);
130 for (; anIterS.More(); anIterS.Next())
131 anIterS.ChangeValue().WriteTOC (theOStream);
7fd59977 132
4ff92abe 133 // Shapes Section is the last one, it indicates the end of the table.
134 BinLDrivers_DocumentSection aShapesSection (SHAPESECTION_POS,
135 Standard_False);
136 aShapesSection.WriteTOC (theOStream);
7fd59977 137
138// 3. Write document contents
4ff92abe 139 // (Storage data to the stream)
140 myRelocTable.Clear();
141 myPAtt.Init();
7fd59977 142
6d8f9f4a 143 Message_ProgressSentry aPS(theProgress, "Writing document", 0, 3, 1);
7fd59977 144
6d8f9f4a 145// Write Doc structure
146 WriteSubTree (aData->Root(), theOStream, theProgress); // Doc is written
147 if (!aPS.More())
148 {
149 SetIsError(Standard_True);
150 SetStoreStatus(PCDM_SS_UserBreak);
151 return;
152 }
153 aPS.Next();
7fd59977 154// 4. Write Shapes section
6d8f9f4a 155 WriteShapeSection (aShapesSection, theOStream, theProgress);
156 if (!aPS.More())
157 {
158 SetIsError(Standard_True);
159 SetStoreStatus(PCDM_SS_UserBreak);
160 return;
161 }
162 aPS.Next();
4ff92abe 163 // Write application-defined sections
164 for (anIterS.Init (mySections); anIterS.More(); anIterS.Next()) {
165 BinLDrivers_DocumentSection& aSection = anIterS.ChangeValue();
166 const Standard_Size aSectionOffset = (Standard_Size) theOStream.tellp();
167 WriteSection (aSection.Name(), aDoc, theOStream);
168 aSection.Write (theOStream, aSectionOffset);
169 }
170
171 // End of processing: close structures and check the status
172 myPAtt.Destroy(); // free buffer
173 myEmptyLabels.Clear();
174 myMapUnsupported.Clear();
175
176 if (!myRelocTable.Extent()) {
177 // No objects written
0797d9d3 178#ifdef OCCT_DEBUG
83ae3591 179 myMsgDriver->Send ("BinLDrivers_DocumentStorageDriver, no objects written", Message_Info);
7fd59977 180#endif
4ff92abe 181 SetIsError(Standard_True);
182 SetStoreStatus(PCDM_SS_No_Obj);
7fd59977 183 }
4ff92abe 184 myRelocTable.Clear();
6d8f9f4a 185 if (!aPS.More())
186 {
187 SetIsError(Standard_True);
188 SetStoreStatus(PCDM_SS_UserBreak);
189 return;
190 }
191 aPS.Next();
4ff92abe 192 if (!theOStream) {
7fd59977 193 // A problem with the stream
0797d9d3 194#ifdef OCCT_DEBUG
83ae3591 195 TCollection_ExtendedString anErrorStr ("BinLDrivers_DocumentStorageDriver, Problem with the file stream, rdstate = ");
196 myMsgDriver->Send (anErrorStr + (Standard_Integer )theOStream.rdstate(), Message_Info);
7fd59977 197#endif
15e8b082 198 SetIsError(Standard_True);
566f8441 199 SetStoreStatus(PCDM_SS_WriteFailure);
7fd59977 200 }
201
202 }
203}
204
205//=======================================================================
206//function : UnsupportedAttrMsg
9293178b 207//purpose :
7fd59977 208//=======================================================================
209
210void BinLDrivers_DocumentStorageDriver::UnsupportedAttrMsg
211 (const Handle(Standard_Type)& theType)
212{
0797d9d3 213#ifdef OCCT_DEBUG
b34d86cb 214 TCollection_ExtendedString aMsg
7fd59977 215 ("BinDrivers_DocumentStorageDriver: warning: attribute driver for type ");
216#endif
217 if (!myMapUnsupported.Contains(theType)) {
218 myMapUnsupported.Add(theType);
0797d9d3 219#ifdef OCCT_DEBUG
83ae3591 220 myMsgDriver->Send (aMsg + theType->Name() + " not found", Message_Info);
7fd59977 221#endif
222 }
223}
224
225//=======================================================================
226//function : WriteSubTree
227//purpose :
228//=======================================================================
229
230void BinLDrivers_DocumentStorageDriver::WriteSubTree
231 (const TDF_Label& theLabel,
6d8f9f4a 232 Standard_OStream& theOS,
233 const Handle(Message_ProgressIndicator)& theProgress)
7fd59977 234{
235 // Skip empty labels
236 if (!myEmptyLabels.IsEmpty() && myEmptyLabels.First() == theLabel) {
237 myEmptyLabels.RemoveFirst();
238 return;
239 }
6d8f9f4a 240 Message_ProgressSentry aPS(theProgress, "Writing sub tree", 0, 2, 1, 1);
7fd59977 241 // Write label header: tag
242 Standard_Integer aTag = theLabel.Tag();
243#if DO_INVERSE
244 aTag = InverseInt (aTag);
245#endif
246 theOS.write ((char*)&aTag, sizeof(Standard_Integer));
247
248 // Write attributes
249 TDF_AttributeIterator itAtt (theLabel);
6d8f9f4a 250 for ( ; itAtt.More() && theOS && aPS.More(); itAtt.Next()) {
1bd04b5a 251 const Handle(TDF_Attribute) tAtt = itAtt.Value();
7fd59977 252 const Handle(Standard_Type)& aType = tAtt->DynamicType();
253 // Get type ID and driver
254 Handle(BinMDF_ADriver) aDriver;
255 const Standard_Integer aTypeId = myDrivers->GetDriver (aType,aDriver);
256 if (aTypeId > 0) {
257 // Add source to relocation table
258 const Standard_Integer anId = myRelocTable.Add (tAtt);
259
260 // Create and fill data item
261 myPAtt.SetTypeId (aTypeId);
262 myPAtt.SetId (anId);
263 aDriver->Paste (tAtt, myPAtt, myRelocTable);
264
265 // Write data to the stream -->!!!
266 theOS << myPAtt;
267 }
0797d9d3 268#ifdef OCCT_DEBUG
7fd59977 269 else
270 UnsupportedAttrMsg (aType);
271#endif
272 }
273 if (!theOS) {
274 // Problem with the stream
275 return;
276 }
6d8f9f4a 277 if (!aPS.More())
278 {
279 SetIsError(Standard_True);
280 SetStoreStatus(PCDM_SS_UserBreak);
281 return;
282 }
7fd59977 283 // Write the end attributes list marker
284 BinLDrivers_Marker anEndAttr = BinLDrivers_ENDATTRLIST;
285#if DO_INVERSE
286 anEndAttr = (BinLDrivers_Marker) InverseInt (anEndAttr);
287#endif
288 theOS.write ((char*)&anEndAttr, sizeof(anEndAttr));
289
290 // Process sub-labels
291 TDF_ChildIterator itChld (theLabel);
292 for ( ; itChld.More(); itChld.Next())
293 {
294 const TDF_Label& aChildLab = itChld.Value();
6d8f9f4a 295 if (!aPS.More())
296 {
297 SetIsError(Standard_True);
298 SetStoreStatus(PCDM_SS_UserBreak);
299 return;
300 }
301 aPS.Next();
302 WriteSubTree (aChildLab, theOS, theProgress);
7fd59977 303 }
304
305 // Write the end label marker
306 BinLDrivers_Marker anEndLabel = BinLDrivers_ENDLABEL;
307#if DO_INVERSE
308 anEndLabel = (BinLDrivers_Marker) InverseInt (anEndLabel);
309#endif
310 theOS.write ((char*)&anEndLabel, sizeof(anEndLabel));
311
312}
313
7fd59977 314//=======================================================================
315//function : AttributeDrivers
316//purpose :
317//=======================================================================
318
319Handle(BinMDF_ADriverTable) BinLDrivers_DocumentStorageDriver::AttributeDrivers
83ae3591 320 (const Handle(Message_Messenger)& theMessageDriver)
7fd59977 321{
322 return BinLDrivers::AttributeDrivers (theMessageDriver);
323}
324
325//=======================================================================
326//function : FirstPassSubTree
327//purpose :
328//=======================================================================
329
330Standard_Boolean BinLDrivers_DocumentStorageDriver::FirstPassSubTree
331 (const TDF_Label& L,
332 TDF_LabelList& ListOfEmptyL)
333{
334 // are there writable attributes on L ?
335 Standard_Boolean hasAttr = Standard_False;
336 TDF_AttributeIterator itAtt (L);
337 for ( ; itAtt.More(); itAtt.Next()) {
338 const Handle(Standard_Type)& aType = itAtt.Value()->DynamicType();
339 Handle(BinMDF_ADriver) aDriver;
340 // do not rely on a value returned by GetDriver here, because
341 // the IDs have not yet been assigned to the types
342 myDrivers->GetDriver (aType, aDriver);
343 if (!aDriver.IsNull()) {
344 hasAttr = Standard_True;
345 myTypesMap.Add (aType);
346 }
0797d9d3 347#ifdef OCCT_DEBUG
7fd59977 348 else
349 UnsupportedAttrMsg (aType);
350#endif
351 }
352
353 // are there writable attributes on sub-labels ?
354 Standard_Boolean hasChildAttr = Standard_False;
355 TDF_LabelList emptyChildrenList;
356 TDF_ChildIterator itChld (L);
357 for ( ; itChld.More(); itChld.Next())
358 {
359 if (FirstPassSubTree (itChld.Value(), emptyChildrenList))
360 emptyChildrenList.Append( itChld.Value() );
361 else
362 hasChildAttr = Standard_True;
363 }
364
365 Standard_Boolean isEmpty = !(hasAttr || hasChildAttr);
366
367 if (!isEmpty)
368 ListOfEmptyL.Append( emptyChildrenList );
369
370 return isEmpty;
371}
372
373//=======================================================================
374//function : FirstPass
375//purpose :
376//=======================================================================
377
378void BinLDrivers_DocumentStorageDriver::FirstPass
379 (const TDF_Label& theRoot)
380{
381 myTypesMap.Clear();
382 myEmptyLabels.Clear();
383
384 if (FirstPassSubTree( theRoot, myEmptyLabels))
385 myEmptyLabels.Append( theRoot );
386
387 myDrivers->AssignIds (myTypesMap);
388}
389
390//=======================================================================
391//function : WriteInfoSection
392//purpose : Write info secton using FSD_BinaryFile driver
393//=======================================================================
394
395#define START_TYPES "START_TYPES"
396#define END_TYPES "END_TYPES"
397
4ff92abe 398void BinLDrivers_DocumentStorageDriver::WriteInfoSection
399 (const Handle(CDM_Document)& theDoc,
400 Standard_OStream& theOStream)
7fd59977 401{
4ff92abe 402 // Magic number
403 theOStream.write (FSD_BinaryFile::MagicNumber(), strlen(FSD_BinaryFile::MagicNumber()));
404
405 FSD_FileHeader aHeader;
406
407 {
408 aHeader.testindian = -1;
409 aHeader.binfo = -1;
410 aHeader.einfo = -1;
411 aHeader.bcomment = -1;
412 aHeader.ecomment = -1;
413 aHeader.btype = -1;
414 aHeader.etype = -1;
415 aHeader.broot = -1;
416 aHeader.eroot = -1;
417 aHeader.bref = -1;
418 aHeader.eref = -1;
419 aHeader.bdata = -1;
420 aHeader.edata = -1;
421 }
422
423 // aHeader.testindian
424 {
425 union {
426 char ti2[4];
427 Standard_Integer aResult;
428 } aWrapUnion;
429
430 aWrapUnion.ti2[0] = 1;
431 aWrapUnion.ti2[1] = 2;
432 aWrapUnion.ti2[2] = 3;
433 aWrapUnion.ti2[3] = 4;
434
435 aHeader.testindian = aWrapUnion.aResult;
7fd59977 436 }
437
4ff92abe 438 // info section
439 aHeader.binfo = (Standard_Integer)theOStream.tellp();
440
441 // header section
442 aHeader.einfo = aHeader.binfo + FSD_BinaryFile::WriteHeader (theOStream, aHeader, Standard_True);
443
444 // add format
445 Handle(Storage_Data) theData = new Storage_Data;
446 PCDM_ReadWriter::WriteFileFormat (theData, theDoc);
447 PCDM_ReadWriter::Writer()->WriteReferenceCounter (theData, theDoc);
448 PCDM_ReadWriter::Writer()->WriteReferences (theData, theDoc, myFileName);
449 PCDM_ReadWriter::Writer()->WriteExtensions (theData, theDoc);
450 PCDM_ReadWriter::Writer()->WriteVersion (theData, theDoc);
451
452 // add the types table
453 theData->AddToUserInfo(START_TYPES);
454 for (Standard_Integer i = 1; i <= myTypesMap.Extent(); i++)
7fd59977 455 {
4ff92abe 456 Handle(BinMDF_ADriver) aDriver = myDrivers->GetDriver(i);
457 if (!aDriver.IsNull())
458 {
459 const TCollection_AsciiString& aTypeName = aDriver->TypeName();
460 theData->AddToUserInfo (aTypeName);
7fd59977 461 }
7fd59977 462 }
4ff92abe 463 theData->AddToUserInfo(END_TYPES);
464
465 Standard_Integer aObjNb = 1;
466 Standard_Integer aShemaVer = 1;
467
fe21f796
BB
468 // Store the name and version of the application that has created the
469 // document.
470 theData->SetApplicationVersion(theDoc->Application()->Version());
471 theData->SetApplicationName(theDoc->Application()->Name());
472
4ff92abe 473 aHeader.einfo += FSD_BinaryFile::WriteInfo (theOStream,
474 aObjNb,
475 BinLDrivers::StorageVersion(),
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,
504 BinLDrivers::StorageVersion(),
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,
550 const Handle(Message_ProgressIndicator)& /*theProgress*/)
7fd59977 551{
552 const Standard_Size aShapesSectionOffset = (Standard_Size) theOS.tellp();
553 theSection.Write (theOS, aShapesSectionOffset);
554}