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 <Message_Messenger.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>
45 #include <Message_ProgressScope.hxx>
47 IMPLEMENT_STANDARD_RTTIEXT(BinLDrivers_DocumentStorageDriver,PCDM_StorageDriver)
49 #define SHAPESECTION_POS (Standard_CString)"SHAPE_SECTION_POS:"
51 //=======================================================================
52 //function : BinLDrivers_DocumentStorageDriver
53 //purpose : Constructor
54 //=======================================================================
56 BinLDrivers_DocumentStorageDriver::BinLDrivers_DocumentStorageDriver ()
60 //=======================================================================
63 //=======================================================================
65 void BinLDrivers_DocumentStorageDriver::Write
66 (const Handle(CDM_Document)& theDocument,
67 const TCollection_ExtendedString& theFileName,
68 const Message_ProgressRange& theRange)
70 SetIsError(Standard_False);
71 SetStoreStatus(PCDM_SS_OK);
73 myFileName = theFileName;
75 std::ofstream aFileStream;
76 OSD_OpenStream (aFileStream, theFileName, std::ios::out | std::ios::binary);
78 if (aFileStream.is_open() && aFileStream.good())
80 Write(theDocument, aFileStream, theRange);
84 SetIsError (Standard_True);
85 SetStoreStatus(PCDM_SS_WriteFailure);
89 //=======================================================================
92 //=======================================================================
94 void BinLDrivers_DocumentStorageDriver::Write (const Handle(CDM_Document)& theDoc,
95 Standard_OStream& theOStream,
96 const Message_ProgressRange& theRange)
98 myMsgDriver = theDoc->Application()->MessageDriver();
99 myMapUnsupported.Clear();
101 Handle(TDocStd_Document) aDoc =
102 Handle(TDocStd_Document)::DownCast(theDoc);
104 SetIsError(Standard_True);
105 SetStoreStatus(PCDM_SS_Doc_IsNull);
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());
113 if(aDoc->EmptyLabelsSavingMode())
114 myEmptyLabels.Clear(); //
116 // 1. Write info section (including types table)
117 WriteInfoSection (aDoc, theOStream);
122 SetStoreStatus(PCDM_SS_Info_Section_Error);
128 // 2. Write the Table of Contents of Sections
129 BinLDrivers_VectorOfDocumentSection::Iterator anIterS (mySections);
130 for (; anIterS.More(); anIterS.Next())
131 anIterS.ChangeValue().WriteTOC (theOStream);
133 // Shapes Section is the last one, it indicates the end of the table.
134 BinLDrivers_DocumentSection aShapesSection (SHAPESECTION_POS,
136 aShapesSection.WriteTOC (theOStream);
138 // 3. Write document contents
139 // (Storage data to the stream)
140 myRelocTable.Clear();
143 Message_ProgressScope aPS(theRange, "Writing document", 3);
145 // Write Doc structure
146 WriteSubTree (aData->Root(), theOStream, aPS.Next()); // Doc is written
149 SetIsError(Standard_True);
150 SetStoreStatus(PCDM_SS_UserBreak);
154 // 4. Write Shapes section
155 WriteShapeSection (aShapesSection, theOStream, aPS.Next());
158 SetIsError(Standard_True);
159 SetStoreStatus(PCDM_SS_UserBreak);
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);
171 // End of processing: close structures and check the status
172 myPAtt.Destroy(); // free buffer
173 myEmptyLabels.Clear();
174 myMapUnsupported.Clear();
176 if (!myRelocTable.Extent()) {
177 // No objects written
179 myMsgDriver->Send ("BinLDrivers_DocumentStorageDriver, no objects written", Message_Info);
181 SetIsError(Standard_True);
182 SetStoreStatus(PCDM_SS_No_Obj);
184 myRelocTable.Clear();
187 SetIsError(Standard_True);
188 SetStoreStatus(PCDM_SS_UserBreak);
193 // A problem with the stream
195 TCollection_ExtendedString anErrorStr ("BinLDrivers_DocumentStorageDriver, Problem with the file stream, rdstate = ");
196 myMsgDriver->Send (anErrorStr + (Standard_Integer )theOStream.rdstate(), Message_Info);
198 SetIsError(Standard_True);
199 SetStoreStatus(PCDM_SS_WriteFailure);
205 //=======================================================================
206 //function : UnsupportedAttrMsg
208 //=======================================================================
210 void BinLDrivers_DocumentStorageDriver::UnsupportedAttrMsg
211 (const Handle(Standard_Type)& theType)
214 TCollection_ExtendedString aMsg
215 ("BinDrivers_DocumentStorageDriver: warning: attribute driver for type ");
217 if (!myMapUnsupported.Contains(theType)) {
218 myMapUnsupported.Add(theType);
220 myMsgDriver->Send (aMsg + theType->Name() + " not found", Message_Info);
225 //=======================================================================
226 //function : WriteSubTree
228 //=======================================================================
230 void BinLDrivers_DocumentStorageDriver::WriteSubTree
231 (const TDF_Label& theLabel,
232 Standard_OStream& theOS,
233 const Message_ProgressRange& theRange)
236 if (!myEmptyLabels.IsEmpty() && myEmptyLabels.First() == theLabel) {
237 myEmptyLabels.RemoveFirst();
240 Message_ProgressScope aPS(theRange, "Writing sub tree", 2, true);
241 // Write label header: tag
242 Standard_Integer aTag = theLabel.Tag();
244 aTag = InverseInt (aTag);
246 theOS.write ((char*)&aTag, sizeof(Standard_Integer));
249 TDF_AttributeIterator itAtt (theLabel);
250 for ( ; itAtt.More() && theOS && aPS.More(); itAtt.Next()) {
251 const Handle(TDF_Attribute) tAtt = itAtt.Value();
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);
257 // Add source to relocation table
258 const Standard_Integer anId = myRelocTable.Add (tAtt);
260 // Create and fill data item
261 myPAtt.SetTypeId (aTypeId);
263 aDriver->Paste (tAtt, myPAtt, myRelocTable);
265 // Write data to the stream -->!!!
270 UnsupportedAttrMsg (aType);
274 // Problem with the stream
279 SetIsError(Standard_True);
280 SetStoreStatus(PCDM_SS_UserBreak);
283 // Write the end attributes list marker
284 BinLDrivers_Marker anEndAttr = BinLDrivers_ENDATTRLIST;
286 anEndAttr = (BinLDrivers_Marker) InverseInt (anEndAttr);
288 theOS.write ((char*)&anEndAttr, sizeof(anEndAttr));
290 // Process sub-labels
291 TDF_ChildIterator itChld (theLabel);
292 for ( ; itChld.More(); itChld.Next())
294 const TDF_Label& aChildLab = itChld.Value();
297 SetIsError(Standard_True);
298 SetStoreStatus(PCDM_SS_UserBreak);
301 WriteSubTree (aChildLab, theOS, aPS.Next());
304 // Write the end label marker
305 BinLDrivers_Marker anEndLabel = BinLDrivers_ENDLABEL;
307 anEndLabel = (BinLDrivers_Marker) InverseInt (anEndLabel);
309 theOS.write ((char*)&anEndLabel, sizeof(anEndLabel));
313 //=======================================================================
314 //function : AttributeDrivers
316 //=======================================================================
318 Handle(BinMDF_ADriverTable) BinLDrivers_DocumentStorageDriver::AttributeDrivers
319 (const Handle(Message_Messenger)& theMessageDriver)
321 return BinLDrivers::AttributeDrivers (theMessageDriver);
324 //=======================================================================
325 //function : FirstPassSubTree
327 //=======================================================================
329 Standard_Boolean BinLDrivers_DocumentStorageDriver::FirstPassSubTree
331 TDF_LabelList& ListOfEmptyL)
333 // are there writable attributes on L ?
334 Standard_Boolean hasAttr = Standard_False;
335 TDF_AttributeIterator itAtt (L);
336 for ( ; itAtt.More(); itAtt.Next()) {
337 const Handle(Standard_Type)& aType = itAtt.Value()->DynamicType();
338 Handle(BinMDF_ADriver) aDriver;
339 // do not rely on a value returned by GetDriver here, because
340 // the IDs have not yet been assigned to the types
341 myDrivers->GetDriver (aType, aDriver);
342 if (!aDriver.IsNull()) {
343 hasAttr = Standard_True;
344 myTypesMap.Add (aType);
348 UnsupportedAttrMsg (aType);
352 // are there writable attributes on sub-labels ?
353 Standard_Boolean hasChildAttr = Standard_False;
354 TDF_LabelList emptyChildrenList;
355 TDF_ChildIterator itChld (L);
356 for ( ; itChld.More(); itChld.Next())
358 if (FirstPassSubTree (itChld.Value(), emptyChildrenList))
359 emptyChildrenList.Append( itChld.Value() );
361 hasChildAttr = Standard_True;
364 Standard_Boolean isEmpty = !(hasAttr || hasChildAttr);
367 ListOfEmptyL.Append( emptyChildrenList );
372 //=======================================================================
373 //function : FirstPass
375 //=======================================================================
377 void BinLDrivers_DocumentStorageDriver::FirstPass
378 (const TDF_Label& theRoot)
381 myEmptyLabels.Clear();
383 if (FirstPassSubTree( theRoot, myEmptyLabels))
384 myEmptyLabels.Append( theRoot );
386 myDrivers->AssignIds (myTypesMap);
389 //=======================================================================
390 //function : WriteInfoSection
391 //purpose : Write info secton using FSD_BinaryFile driver
392 //=======================================================================
394 #define START_TYPES "START_TYPES"
395 #define END_TYPES "END_TYPES"
397 void BinLDrivers_DocumentStorageDriver::WriteInfoSection
398 (const Handle(CDM_Document)& theDoc,
399 Standard_OStream& theOStream)
402 theOStream.write (FSD_BinaryFile::MagicNumber(), strlen(FSD_BinaryFile::MagicNumber()));
404 FSD_FileHeader aHeader;
407 aHeader.testindian = -1;
410 aHeader.bcomment = -1;
411 aHeader.ecomment = -1;
422 // aHeader.testindian
426 Standard_Integer aResult;
429 aWrapUnion.ti2[0] = 1;
430 aWrapUnion.ti2[1] = 2;
431 aWrapUnion.ti2[2] = 3;
432 aWrapUnion.ti2[3] = 4;
434 aHeader.testindian = aWrapUnion.aResult;
438 aHeader.binfo = (Standard_Integer)theOStream.tellp();
441 aHeader.einfo = aHeader.binfo + FSD_BinaryFile::WriteHeader (theOStream, aHeader, Standard_True);
444 Handle(Storage_Data) theData = new Storage_Data;
445 PCDM_ReadWriter::WriteFileFormat (theData, theDoc);
446 PCDM_ReadWriter::Writer()->WriteReferenceCounter (theData, theDoc);
447 PCDM_ReadWriter::Writer()->WriteReferences (theData, theDoc, myFileName);
448 PCDM_ReadWriter::Writer()->WriteExtensions (theData, theDoc);
449 PCDM_ReadWriter::Writer()->WriteVersion (theData, theDoc);
451 // add the types table
452 theData->AddToUserInfo(START_TYPES);
453 for (Standard_Integer i = 1; i <= myTypesMap.Extent(); i++)
455 Handle(BinMDF_ADriver) aDriver = myDrivers->GetDriver(i);
456 if (!aDriver.IsNull())
458 const TCollection_AsciiString& aTypeName = aDriver->TypeName();
459 theData->AddToUserInfo (aTypeName);
462 theData->AddToUserInfo(END_TYPES);
464 Standard_Integer aObjNb = 1;
465 Standard_Integer aShemaVer = 1;
467 // Store the name and version of the application that has created the
469 theData->SetApplicationVersion(theDoc->Application()->Version());
470 theData->SetApplicationName(theDoc->Application()->Name());
472 aHeader.einfo += FSD_BinaryFile::WriteInfo (theOStream,
474 BinLDrivers::StorageVersion(),
475 Storage_Schema::ICreationDate(),
478 theData->ApplicationName(),
479 theData->ApplicationVersion(),
482 Standard_True); // only count the size of the section
484 // calculate comment section
485 TColStd_SequenceOfExtendedString aComments;
486 theDoc->Comments(aComments);
487 for (Standard_Integer i = 1; i <= aComments.Length(); i++)
489 theData->AddToComments (aComments(i));
492 aHeader.bcomment = aHeader.einfo;
493 aHeader.ecomment = aHeader.bcomment + FSD_BinaryFile::WriteComment(theOStream, theData->Comments(), Standard_True);
495 aHeader.edata = aHeader.ecomment;
497 // write header information
498 FSD_BinaryFile::WriteHeader (theOStream, aHeader);
500 // write info section
501 FSD_BinaryFile::WriteInfo (theOStream,
503 BinLDrivers::StorageVersion(),
504 Storage_Schema::ICreationDate(),
507 theData->ApplicationName(),
508 theData->ApplicationVersion(),
510 theData->UserInfo());
512 // write the comments
513 FSD_BinaryFile::WriteComment(theOStream, theData->Comments());
517 //=======================================================================
518 //function : AddSection
520 //=======================================================================
522 void BinLDrivers_DocumentStorageDriver::AddSection
523 (const TCollection_AsciiString& theName,
524 const Standard_Boolean isPostRead)
526 mySections.Append (BinLDrivers_DocumentSection (theName, isPostRead));
529 //=======================================================================
530 //function : WriteSection
532 //=======================================================================
534 void BinLDrivers_DocumentStorageDriver::WriteSection
535 (const TCollection_AsciiString& /*theName*/,
536 const Handle(CDM_Document)& /*theDocument*/,
537 Standard_OStream& /*theOS*/)
539 // empty; should be redefined in subclasses
542 //=======================================================================
543 //function : WriteShapeSection
544 //purpose : defines WriteShapeSection
545 //=======================================================================
546 void BinLDrivers_DocumentStorageDriver::WriteShapeSection
547 (BinLDrivers_DocumentSection& theSection,
548 Standard_OStream& theOS,
549 const Message_ProgressRange& /*theRange*/)
551 const Standard_Size aShapesSectionOffset = (Standard_Size) theOS.tellp();
552 theSection.Write (theOS, aShapesSectionOffset);