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