1 // Created on: 2002-10-29
2 // Created by: Michael SAZONOV
3 // Copyright (c) 2002-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
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
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.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
17 #include <BinLDrivers.hxx>
18 #include <BinLDrivers_DocumentSection.hxx>
19 #include <BinLDrivers_DocumentStorageDriver.hxx>
20 #include <BinLDrivers_Marker.hxx>
21 #include <BinMDF_ADriver.hxx>
22 #include <BinMDF_ADriverTable.hxx>
23 #include <BinObjMgt_Persistent.hxx>
24 #include <CDM_Application.hxx>
25 #include <CDM_Document.hxx>
26 #include <CDM_MessageDriver.hxx>
27 #include <FSD_BinaryFile.hxx>
28 #include <FSD_FileHeader.hxx>
29 #include <OSD_OpenFile.hxx>
30 #include <PCDM_ReadWriter.hxx>
31 #include <Standard_ErrorHandler.hxx>
32 #include <Standard_Type.hxx>
33 #include <Storage_Schema.hxx>
34 #include <TCollection_AsciiString.hxx>
35 #include <TCollection_ExtendedString.hxx>
36 #include <TColStd_Array1OfInteger.hxx>
37 #include <TColStd_ListIteratorOfListOfInteger.hxx>
38 #include <TColStd_ListOfInteger.hxx>
39 #include <TDF_AttributeIterator.hxx>
40 #include <TDF_ChildIterator.hxx>
41 #include <TDF_Data.hxx>
42 #include <TDF_Label.hxx>
43 #include <TDF_Tool.hxx>
44 #include <TDocStd_Document.hxx>
46 IMPLEMENT_STANDARD_RTTIEXT(BinLDrivers_DocumentStorageDriver,PCDM_StorageDriver)
48 #define SHAPESECTION_POS (Standard_CString)"SHAPE_SECTION_POS:"
50 //=======================================================================
51 //function : BinLDrivers_DocumentStorageDriver
52 //purpose : Constructor
53 //=======================================================================
55 BinLDrivers_DocumentStorageDriver::BinLDrivers_DocumentStorageDriver ()
59 //=======================================================================
62 //=======================================================================
64 void BinLDrivers_DocumentStorageDriver::Write
65 (const Handle(CDM_Document)& theDocument,
66 const TCollection_ExtendedString& theFileName)
68 SetIsError(Standard_False);
69 SetStoreStatus(PCDM_SS_OK);
71 myFileName = theFileName;
73 std::ofstream aFileStream;
74 OSD_OpenStream (aFileStream, theFileName, std::ios::out | std::ios::binary);
76 if (aFileStream.is_open() && aFileStream.good())
78 Write (theDocument, aFileStream);
82 SetIsError (Standard_True);
83 SetStoreStatus(PCDM_SS_WriteFailure);
87 //=======================================================================
90 //=======================================================================
92 void BinLDrivers_DocumentStorageDriver::Write (const Handle(CDM_Document)& theDoc, Standard_OStream& theOStream)
94 myMsgDriver = theDoc->Application()->MessageDriver();
95 myMapUnsupported.Clear();
97 Handle(TDocStd_Document) aDoc =
98 Handle(TDocStd_Document)::DownCast(theDoc);
100 SetIsError(Standard_True);
101 SetStoreStatus(PCDM_SS_Doc_IsNull);
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 if(aDoc->EmptyLabelsSavingMode())
110 myEmptyLabels.Clear(); //
112 // 1. Write info section (including types table)
113 WriteInfoSection (aDoc, theOStream);
118 SetStoreStatus(PCDM_SS_Info_Section_Error);
124 // 2. Write the Table of Contents of Sections
125 BinLDrivers_VectorOfDocumentSection::Iterator anIterS (mySections);
126 for (; anIterS.More(); anIterS.Next())
127 anIterS.ChangeValue().WriteTOC (theOStream);
129 // Shapes Section is the last one, it indicates the end of the table.
130 BinLDrivers_DocumentSection aShapesSection (SHAPESECTION_POS,
132 aShapesSection.WriteTOC (theOStream);
134 // 3. Write document contents
135 // (Storage data to the stream)
136 myRelocTable.Clear();
139 // Write Doc structure
140 WriteSubTree (aData->Root(), theOStream); // Doc is written
142 // 4. Write Shapes section
143 WriteShapeSection (aShapesSection, theOStream);
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);
153 // End of processing: close structures and check the status
154 myPAtt.Destroy(); // free buffer
155 myEmptyLabels.Clear();
156 myMapUnsupported.Clear();
158 if (!myRelocTable.Extent()) {
159 // No objects written
161 WriteMessage ("BinLDrivers_DocumentStorageDriver, no objects written");
163 SetIsError(Standard_True);
164 SetStoreStatus(PCDM_SS_No_Obj);
166 myRelocTable.Clear();
169 // A problem with the stream
171 TCollection_ExtendedString anErrorStr ("Error: ");
172 WriteMessage (anErrorStr + "BinLDrivers_DocumentStorageDriver, Problem with the file stream, rdstate="
173 + (Standard_Integer )theOStream.rdstate());
175 SetIsError(Standard_True);
176 SetStoreStatus(PCDM_SS_WriteFailure);
182 //=======================================================================
183 //function : UnsupportedAttrMsg
185 //=======================================================================
187 void BinLDrivers_DocumentStorageDriver::UnsupportedAttrMsg
188 (const Handle(Standard_Type)& theType)
191 static TCollection_ExtendedString aMsg
192 ("BinDrivers_DocumentStorageDriver: warning: attribute driver for type ");
194 if (!myMapUnsupported.Contains(theType)) {
195 myMapUnsupported.Add(theType);
197 WriteMessage (aMsg + theType->Name() + " not found");
202 //=======================================================================
203 //function : WriteSubTree
205 //=======================================================================
207 void BinLDrivers_DocumentStorageDriver::WriteSubTree
208 (const TDF_Label& theLabel,
209 Standard_OStream& theOS)
212 if (!myEmptyLabels.IsEmpty() && myEmptyLabels.First() == theLabel) {
213 myEmptyLabels.RemoveFirst();
217 // Write label header: tag
218 Standard_Integer aTag = theLabel.Tag();
220 aTag = InverseInt (aTag);
222 theOS.write ((char*)&aTag, sizeof(Standard_Integer));
225 TDF_AttributeIterator itAtt (theLabel);
226 for ( ; itAtt.More() && theOS; itAtt.Next()) {
227 const Handle(TDF_Attribute)& tAtt = itAtt.Value();
228 const Handle(Standard_Type)& aType = tAtt->DynamicType();
229 // Get type ID and driver
230 Handle(BinMDF_ADriver) aDriver;
231 const Standard_Integer aTypeId = myDrivers->GetDriver (aType,aDriver);
233 // Add source to relocation table
234 const Standard_Integer anId = myRelocTable.Add (tAtt);
236 // Create and fill data item
237 myPAtt.SetTypeId (aTypeId);
239 aDriver->Paste (tAtt, myPAtt, myRelocTable);
241 // Write data to the stream -->!!!
246 UnsupportedAttrMsg (aType);
250 // Problem with the stream
254 // Write the end attributes list marker
255 BinLDrivers_Marker anEndAttr = BinLDrivers_ENDATTRLIST;
257 anEndAttr = (BinLDrivers_Marker) InverseInt (anEndAttr);
259 theOS.write ((char*)&anEndAttr, sizeof(anEndAttr));
261 // Process sub-labels
262 TDF_ChildIterator itChld (theLabel);
263 for ( ; itChld.More(); itChld.Next())
265 const TDF_Label& aChildLab = itChld.Value();
266 WriteSubTree (aChildLab, theOS);
269 // Write the end label marker
270 BinLDrivers_Marker anEndLabel = BinLDrivers_ENDLABEL;
272 anEndLabel = (BinLDrivers_Marker) InverseInt (anEndLabel);
274 theOS.write ((char*)&anEndLabel, sizeof(anEndLabel));
278 //=======================================================================
279 //function : AttributeDrivers
281 //=======================================================================
283 Handle(BinMDF_ADriverTable) BinLDrivers_DocumentStorageDriver::AttributeDrivers
284 (const Handle(CDM_MessageDriver)& theMessageDriver)
286 return BinLDrivers::AttributeDrivers (theMessageDriver);
289 //=======================================================================
290 //function : FirstPassSubTree
292 //=======================================================================
294 Standard_Boolean BinLDrivers_DocumentStorageDriver::FirstPassSubTree
296 TDF_LabelList& ListOfEmptyL)
298 // are there writable attributes on L ?
299 Standard_Boolean hasAttr = Standard_False;
300 TDF_AttributeIterator itAtt (L);
301 for ( ; itAtt.More(); itAtt.Next()) {
302 const Handle(Standard_Type)& aType = itAtt.Value()->DynamicType();
303 Handle(BinMDF_ADriver) aDriver;
304 // do not rely on a value returned by GetDriver here, because
305 // the IDs have not yet been assigned to the types
306 myDrivers->GetDriver (aType, aDriver);
307 if (!aDriver.IsNull()) {
308 hasAttr = Standard_True;
309 myTypesMap.Add (aType);
313 UnsupportedAttrMsg (aType);
317 // are there writable attributes on sub-labels ?
318 Standard_Boolean hasChildAttr = Standard_False;
319 TDF_LabelList emptyChildrenList;
320 TDF_ChildIterator itChld (L);
321 for ( ; itChld.More(); itChld.Next())
323 if (FirstPassSubTree (itChld.Value(), emptyChildrenList))
324 emptyChildrenList.Append( itChld.Value() );
326 hasChildAttr = Standard_True;
329 Standard_Boolean isEmpty = !(hasAttr || hasChildAttr);
332 ListOfEmptyL.Append( emptyChildrenList );
337 //=======================================================================
338 //function : FirstPass
340 //=======================================================================
342 void BinLDrivers_DocumentStorageDriver::FirstPass
343 (const TDF_Label& theRoot)
346 myEmptyLabels.Clear();
348 if (FirstPassSubTree( theRoot, myEmptyLabels))
349 myEmptyLabels.Append( theRoot );
351 myDrivers->AssignIds (myTypesMap);
354 //=======================================================================
355 //function : WriteInfoSection
356 //purpose : Write info secton using FSD_BinaryFile driver
357 //=======================================================================
359 #define START_TYPES "START_TYPES"
360 #define END_TYPES "END_TYPES"
362 void BinLDrivers_DocumentStorageDriver::WriteInfoSection
363 (const Handle(CDM_Document)& theDoc,
364 Standard_OStream& theOStream)
367 theOStream.write (FSD_BinaryFile::MagicNumber(), strlen(FSD_BinaryFile::MagicNumber()));
369 FSD_FileHeader aHeader;
372 aHeader.testindian = -1;
375 aHeader.bcomment = -1;
376 aHeader.ecomment = -1;
387 // aHeader.testindian
391 Standard_Integer aResult;
394 aWrapUnion.ti2[0] = 1;
395 aWrapUnion.ti2[1] = 2;
396 aWrapUnion.ti2[2] = 3;
397 aWrapUnion.ti2[3] = 4;
399 aHeader.testindian = aWrapUnion.aResult;
403 aHeader.binfo = (Standard_Integer)theOStream.tellp();
406 aHeader.einfo = aHeader.binfo + FSD_BinaryFile::WriteHeader (theOStream, aHeader, Standard_True);
409 Handle(Storage_Data) theData = new Storage_Data;
410 PCDM_ReadWriter::WriteFileFormat (theData, theDoc);
411 PCDM_ReadWriter::Writer()->WriteReferenceCounter (theData, theDoc);
412 PCDM_ReadWriter::Writer()->WriteReferences (theData, theDoc, myFileName);
413 PCDM_ReadWriter::Writer()->WriteExtensions (theData, theDoc);
414 PCDM_ReadWriter::Writer()->WriteVersion (theData, theDoc);
416 // add the types table
417 theData->AddToUserInfo(START_TYPES);
418 for (Standard_Integer i = 1; i <= myTypesMap.Extent(); i++)
420 Handle(BinMDF_ADriver) aDriver = myDrivers->GetDriver(i);
421 if (!aDriver.IsNull())
423 const TCollection_AsciiString& aTypeName = aDriver->TypeName();
424 theData->AddToUserInfo (aTypeName);
427 theData->AddToUserInfo(END_TYPES);
429 Standard_Integer aObjNb = 1;
430 Standard_Integer aShemaVer = 1;
432 aHeader.einfo += FSD_BinaryFile::WriteInfo (theOStream,
434 BinLDrivers::StorageVersion(),
435 Storage_Schema::ICreationDate(),
438 theData->ApplicationName(),
439 theData->ApplicationVersion(),
442 Standard_True); // only count the size of the section
444 // calculate comment section
445 TColStd_SequenceOfExtendedString aComments;
446 theDoc->Comments(aComments);
447 for (Standard_Integer i = 1; i <= aComments.Length(); i++)
449 theData->AddToComments (aComments(i));
452 aHeader.bcomment = aHeader.einfo;
453 aHeader.ecomment = aHeader.bcomment + FSD_BinaryFile::WriteComment(theOStream, theData->Comments(), Standard_True);
455 aHeader.edata = aHeader.ecomment;
457 // write header information
458 FSD_BinaryFile::WriteHeader (theOStream, aHeader);
460 // write info section
461 FSD_BinaryFile::WriteInfo (theOStream,
463 BinLDrivers::StorageVersion(),
464 Storage_Schema::ICreationDate(),
467 theData->ApplicationName(),
468 theData->ApplicationVersion(),
470 theData->UserInfo());
472 // write the comments
473 FSD_BinaryFile::WriteComment(theOStream, theData->Comments());
477 //=======================================================================
478 //function : WriteMessage
479 //purpose : write theMessage to the MessageDriver of the
481 //=======================================================================
483 void BinLDrivers_DocumentStorageDriver::WriteMessage
484 (const TCollection_ExtendedString& theMsg)
486 if (!myMsgDriver.IsNull())
487 myMsgDriver->Write (theMsg.ToExtString());
490 //=======================================================================
491 //function : AddSection
493 //=======================================================================
495 void BinLDrivers_DocumentStorageDriver::AddSection
496 (const TCollection_AsciiString& theName,
497 const Standard_Boolean isPostRead)
499 mySections.Append (BinLDrivers_DocumentSection (theName, isPostRead));
502 //=======================================================================
503 //function : WriteSection
505 //=======================================================================
507 void BinLDrivers_DocumentStorageDriver::WriteSection
508 (const TCollection_AsciiString& /*theName*/,
509 const Handle(CDM_Document)& /*theDocument*/,
510 Standard_OStream& /*theOS*/)
512 // empty; should be redefined in subclasses
515 //=======================================================================
516 //function : WriteShapeSection
517 //purpose : defines WriteShapeSection
518 //=======================================================================
519 void BinLDrivers_DocumentStorageDriver::WriteShapeSection
520 (BinLDrivers_DocumentSection& theSection,
521 Standard_OStream& theOS)
523 const Standard_Size aShapesSectionOffset = (Standard_Size) theOS.tellp();
524 theSection.Write (theOS, aShapesSectionOffset);