01c9698d7c4cde43e7d066d7b0ddd3670fbcaef7
[occt.git] / src / BinLDrivers / BinLDrivers_DocumentStorageDriver.cxx
1 // File:      BinLDrivers_DocumentStorageDriver.cxx
2 // Created:   29.10.02 11:53:01
3 // Author:    Michael SAZONOV
4 // Copyright: Open CASCADE 2002
5
6 #include <BinLDrivers_DocumentStorageDriver.ixx>
7 #include <BinLDrivers.hxx>
8 #include <BinLDrivers_Marker.hxx>
9 #include <BinMDF_ADriver.hxx>
10 #include <BinObjMgt_Persistent.hxx>
11 #include <CDM_Application.hxx>
12 #include <FSD_BinaryFile.hxx>
13 #include <FSD_FileHeader.hxx>
14 #include <PCDM_ReadWriter.hxx>
15 #include <Standard_ErrorHandler.hxx>
16 #include <Storage_Schema.hxx>
17 #include <TColStd_Array1OfInteger.hxx>
18 #include <TColStd_ListIteratorOfListOfInteger.hxx>
19 #include <TColStd_ListOfInteger.hxx>
20 #include <TCollection_AsciiString.hxx>
21 #include <TDF_AttributeIterator.hxx>
22 #include <TDF_ChildIterator.hxx>
23 #include <TDF_Data.hxx>
24 #include <TDF_Tool.hxx>
25 #include <TDocStd_Document.hxx>
26
27 #define SHAPESECTION_POS (Standard_CString)"SHAPE_SECTION_POS:"
28
29 //=======================================================================
30 //function : BinLDrivers_DocumentStorageDriver
31 //purpose  : Constructor
32 //=======================================================================
33
34 BinLDrivers_DocumentStorageDriver::BinLDrivers_DocumentStorageDriver ()
35 {
36 }
37
38 //=======================================================================
39 //function : SchemaName
40 //purpose  :
41 //=======================================================================
42
43 TCollection_ExtendedString BinLDrivers_DocumentStorageDriver::SchemaName() const
44 {
45   TCollection_ExtendedString schemaname;
46   return schemaname;
47 }
48
49 //=======================================================================
50 //function : Write
51 //purpose  :
52 //=======================================================================
53
54 void BinLDrivers_DocumentStorageDriver::Write
55                           (const Handle(CDM_Document)&       theDocument,
56                            const TCollection_ExtendedString& theFileName)
57 {
58   myIsError   = Standard_False;
59   myMsgDriver = theDocument -> Application() -> MessageDriver();
60   myMapUnsupported.Clear();
61
62 #if defined(_DEBUG) || defined(DEB)
63   TCollection_ExtendedString aMethStr ("BinLDrivers_DocumentStorageDriver, ");
64 #else
65   TCollection_ExtendedString aMethStr;
66 #endif
67   TCollection_ExtendedString anErrorStr ("Error: ");
68
69   Handle(TDocStd_Document) aDoc =
70     Handle(TDocStd_Document)::DownCast(theDocument);
71   if (aDoc.IsNull()) {
72     myIsError = Standard_True;
73   }
74   else {
75     // Open the file
76     TCollection_AsciiString aFileName (theFileName,'?');
77
78     // First pass: collect empty labels, assign IDs to the types
79     if (myDrivers.IsNull())
80       myDrivers = AttributeDrivers (myMsgDriver);
81     Handle(TDF_Data) aData = aDoc->GetData();
82     FirstPass (aData->Root());
83
84 //  1. Write info section (including types table)
85     WriteInfoSection(theDocument, aFileName);
86     myTypesMap.Clear();
87     if (myIsError)
88       return;
89
90 #if !defined(IRIX) // 10.10.2005
91     ofstream anOS (aFileName.ToCString(), ios::in | ios::binary | ios::ate);
92 #else
93     ofstream anOS (aFileName.ToCString(), ios::ate);
94     //ofstream anOS (aFileName.ToCString(), ios::out| ios::binary | ios::ate);   
95 #endif
96 #ifdef DEB
97     const Standard_Integer aP = (Standard_Integer) anOS.tellp(); 
98     cout << "POS = " << aP <<endl;
99 #endif
100 //#endif
101
102     if (anOS) {
103
104 //  2. Write the Table of Contents of Sections
105       BinLDrivers_VectorOfDocumentSection::Iterator anIterS (mySections);
106       for (; anIterS.More(); anIterS.Next())
107         anIterS.ChangeValue().WriteTOC (anOS);
108
109       // Shapes Section is the last one, it indicates the end of the table. 
110       BinLDrivers_DocumentSection aShapesSection (SHAPESECTION_POS,
111                                                   Standard_False);
112       aShapesSection.WriteTOC (anOS); 
113
114 //  3. Write document contents
115       // (Storage data to the stream)
116       myRelocTable.Clear();
117       myPAtt.Init();
118
119 //    Write Doc structure
120       WriteSubTree (aData->Root(), anOS); // Doc is written
121
122 //  4. Write Shapes section
123       WriteShapeSection(aShapesSection, anOS);
124
125 // Write application-defined sections
126       for (anIterS.Init (mySections); anIterS.More(); anIterS.Next()) {
127         BinLDrivers_DocumentSection& aSection = anIterS.ChangeValue();
128         const Standard_Size aSectionOffset = (Standard_Size) anOS.tellp();
129         WriteSection (aSection.Name(), theDocument, anOS);
130         aSection.Write (anOS, aSectionOffset);
131       }
132
133 // End of processing: close structures and check the status 
134       myPAtt.Destroy();   // free buffer
135       myEmptyLabels.Clear();
136       myMapUnsupported.Clear();
137
138       if (!myRelocTable.Extent()) {
139         // No objects written
140 #ifdef DEB
141         WriteMessage (aMethStr + "no objects written");
142 #endif
143         myIsError = Standard_True;
144       }
145       myRelocTable.Clear();
146     }
147
148     if (!anOS) {
149       // A problem with the stream
150 #if defined(_DEBUG) || defined(DEB)
151       WriteMessage (anErrorStr + aMethStr +
152                     "Problem with the file stream, rdstate="
153                     + anOS.rdstate());
154 #else
155       TCollection_ExtendedString aStr =
156         anErrorStr + aMethStr + "Problem writing the file ";
157       WriteMessage (aStr + theFileName);
158 #endif
159       myIsError = Standard_True;
160     }
161
162   }
163 }
164
165 //=======================================================================
166 //function : UnsupportedAttrMsg
167 //purpose  : 
168 //=======================================================================
169
170 void BinLDrivers_DocumentStorageDriver::UnsupportedAttrMsg
171                         (const Handle(Standard_Type)& theType)
172 {
173 #ifdef DEB
174   static TCollection_ExtendedString aMsg
175     ("BinDrivers_DocumentStorageDriver: warning: attribute driver for type ");
176 #endif
177   if (!myMapUnsupported.Contains(theType)) {
178     myMapUnsupported.Add(theType);
179 #ifdef DEB
180     WriteMessage (aMsg + theType->Name() + " not found");
181 #endif
182   }
183 }
184
185 //=======================================================================
186 //function : WriteSubTree
187 //purpose  :
188 //=======================================================================
189
190 void BinLDrivers_DocumentStorageDriver::WriteSubTree
191                         (const TDF_Label&          theLabel,
192                          Standard_OStream&         theOS)
193 {
194   // Skip empty labels
195   if (!myEmptyLabels.IsEmpty() && myEmptyLabels.First() == theLabel) {
196     myEmptyLabels.RemoveFirst();
197     return;
198   }
199
200   // Write label header: tag
201   Standard_Integer aTag = theLabel.Tag();
202 #if DO_INVERSE
203   aTag = InverseInt (aTag);
204 #endif
205   theOS.write ((char*)&aTag, sizeof(Standard_Integer));
206
207   // Write attributes
208   TDF_AttributeIterator itAtt (theLabel);
209   for ( ; itAtt.More() && theOS; itAtt.Next()) {
210     const Handle(TDF_Attribute)& tAtt = itAtt.Value();
211     const Handle(Standard_Type)& aType = tAtt->DynamicType();
212     // Get type ID and driver
213     Handle(BinMDF_ADriver) aDriver;
214     const Standard_Integer aTypeId = myDrivers->GetDriver (aType,aDriver);
215     if (aTypeId > 0) {
216       // Add source to relocation table
217       const Standard_Integer anId = myRelocTable.Add (tAtt);
218
219       // Create and fill data item
220       myPAtt.SetTypeId (aTypeId);
221       myPAtt.SetId (anId);
222       aDriver->Paste (tAtt, myPAtt, myRelocTable);
223
224       // Write data to the stream -->!!!
225       theOS << myPAtt;
226     }
227 #ifdef DEB
228     else
229       UnsupportedAttrMsg (aType);
230 #endif
231   }
232   if (!theOS) {
233     // Problem with the stream
234     return;
235   }
236
237   // Write the end attributes list marker
238   BinLDrivers_Marker anEndAttr = BinLDrivers_ENDATTRLIST;
239 #if DO_INVERSE
240   anEndAttr = (BinLDrivers_Marker) InverseInt (anEndAttr);
241 #endif
242   theOS.write ((char*)&anEndAttr, sizeof(anEndAttr));
243
244   // Process sub-labels
245   TDF_ChildIterator itChld (theLabel);
246   for ( ; itChld.More(); itChld.Next())
247   {
248     const TDF_Label& aChildLab = itChld.Value();
249     WriteSubTree (aChildLab, theOS);
250   }
251
252   // Write the end label marker
253   BinLDrivers_Marker anEndLabel = BinLDrivers_ENDLABEL;
254 #if DO_INVERSE
255   anEndLabel = (BinLDrivers_Marker) InverseInt (anEndLabel);
256 #endif
257   theOS.write ((char*)&anEndLabel, sizeof(anEndLabel));
258
259 }
260
261 //=======================================================================
262 //function : IsError
263 //purpose  :
264 //=======================================================================
265
266 Standard_Boolean BinLDrivers_DocumentStorageDriver::IsError () const
267 {
268   return myIsError;
269 }
270
271 //=======================================================================
272 //function : AttributeDrivers
273 //purpose  :
274 //=======================================================================
275
276 Handle(BinMDF_ADriverTable) BinLDrivers_DocumentStorageDriver::AttributeDrivers
277        (const Handle(CDM_MessageDriver)& theMessageDriver)
278 {
279   return BinLDrivers::AttributeDrivers (theMessageDriver);
280 }
281
282 //=======================================================================
283 //function : FirstPassSubTree
284 //purpose  :
285 //=======================================================================
286
287 Standard_Boolean BinLDrivers_DocumentStorageDriver::FirstPassSubTree
288                          (const TDF_Label&                   L,
289                           TDF_LabelList&                     ListOfEmptyL)
290 {
291   // are there writable attributes on L ?
292   Standard_Boolean hasAttr = Standard_False;
293   TDF_AttributeIterator itAtt (L);
294   for ( ; itAtt.More(); itAtt.Next()) {
295     const Handle(Standard_Type)& aType = itAtt.Value()->DynamicType();
296     Handle(BinMDF_ADriver) aDriver;
297     // do not rely on a value returned by GetDriver here, because
298     // the IDs have not yet been assigned to the types
299     myDrivers->GetDriver (aType, aDriver);
300     if (!aDriver.IsNull()) {
301       hasAttr = Standard_True;
302       myTypesMap.Add (aType);
303     }
304 #ifdef DEB
305     else
306       UnsupportedAttrMsg (aType);
307 #endif
308   }
309
310   // are there writable attributes on sub-labels ?
311   Standard_Boolean hasChildAttr = Standard_False;
312   TDF_LabelList emptyChildrenList;
313   TDF_ChildIterator itChld (L);
314   for ( ; itChld.More(); itChld.Next())
315   {
316     if (FirstPassSubTree (itChld.Value(), emptyChildrenList))
317       emptyChildrenList.Append( itChld.Value() );
318     else
319       hasChildAttr = Standard_True;
320   }
321
322   Standard_Boolean isEmpty = !(hasAttr || hasChildAttr);
323
324   if (!isEmpty)
325     ListOfEmptyL.Append( emptyChildrenList );
326
327   return isEmpty;
328 }
329
330 //=======================================================================
331 //function : FirstPass
332 //purpose  :
333 //=======================================================================
334
335 void BinLDrivers_DocumentStorageDriver::FirstPass
336                          (const TDF_Label& theRoot)
337 {
338   myTypesMap.Clear();
339   myEmptyLabels.Clear();
340
341   if (FirstPassSubTree( theRoot, myEmptyLabels))
342     myEmptyLabels.Append( theRoot );
343
344   myDrivers->AssignIds (myTypesMap);
345 }
346
347 //=======================================================================
348 //function : WriteInfoSection
349 //purpose  : Write info secton using FSD_BinaryFile driver
350 //=======================================================================
351
352 #define START_TYPES "START_TYPES"
353 #define END_TYPES "END_TYPES"
354
355 void BinLDrivers_DocumentStorageDriver::WriteInfoSection
356                          (const Handle(CDM_Document)&    theDocument,
357                           const TCollection_AsciiString& theFileName)
358 {
359   FSD_BinaryFile aFileDriver;
360   if (aFileDriver.Open( theFileName, Storage_VSWrite ) != Storage_VSOk) {
361 #if defined(DEB) || defined(_DEBUG)
362     WriteMessage ("BinDrivers_DocumentStorageDriver: error opening file");
363 #else
364     WriteMessage (TCollection_ExtendedString("Error: Cannot open file ") +
365                   theFileName);
366 #endif
367     myIsError = Standard_True;
368     return;
369   }
370
371   if (aFileDriver.BeginWriteInfoSection() == Storage_VSOk)
372   {
373     // add format
374     Handle(Storage_Data) theData = new Storage_Data;
375     PCDM_ReadWriter::WriteFileFormat( theData, theDocument );
376     PCDM_ReadWriter::Writer()->WriteReferenceCounter(theData,theDocument);
377     PCDM_ReadWriter::Writer()->WriteReferences(theData,theDocument,theFileName);
378     PCDM_ReadWriter::Writer()->WriteExtensions(theData,theDocument);
379     PCDM_ReadWriter::Writer()->WriteVersion(theData,theDocument);
380
381     // add the types table
382     theData->AddToUserInfo(START_TYPES);
383     Standard_Integer i;
384     for (i = 1; i <= myTypesMap.Extent(); i++) {
385       Handle(BinMDF_ADriver) aDriver = myDrivers->GetDriver(i);
386       if (!aDriver.IsNull()) {
387         const TCollection_AsciiString& aTypeName = aDriver->TypeName();
388         theData->AddToUserInfo(aTypeName);
389       }
390     }
391     theData->AddToUserInfo(END_TYPES);
392
393     // add document comments
394     TColStd_SequenceOfExtendedString aComments;
395     theDocument->Comments(aComments);
396     for (i = 1; i <= aComments.Length(); i++)
397       theData->AddToComments(aComments(i));
398
399     // Info
400     aFileDriver.WriteInfo
401       (1,           //   nbObj         
402        BinLDrivers::StorageVersion(),
403        Storage_Schema::ICreationDate(),
404        TCollection_AsciiString(SchemaName(),'?'),
405        1,           //   schemaVersion 
406        theData->ApplicationName(),
407        theData->ApplicationVersion(),
408        theData->DataType(),
409        theData->UserInfo()
410        );
411
412     // we write a complete header section: info and comments
413     aFileDriver.EndWriteInfoSection();
414     aFileDriver.BeginWriteCommentSection();
415     aFileDriver.WriteComment(theData->Comments());// <=== !!! szy - it was missed
416     aFileDriver.EndWriteCommentSection();
417     // here the location of info and comment sections is written
418     aFileDriver.EndWriteDataSection();
419   }
420   else {
421 #if defined(DEB) || defined(_DEBUG)
422     WriteMessage("BinDrivers_DocumentStorageDriver: error writing header");
423 #else
424     WriteMessage(TCollection_ExtendedString("Error: Problem writing header "
425                                             "into file ") + theFileName);
426 #endif
427     myIsError = Standard_True;
428   }
429 #ifdef DEB
430     const Standard_Integer aP = (Standard_Integer) aFileDriver.Tell(); 
431     cout << "POS = " << aP <<endl;
432 #endif  
433   aFileDriver.Close();
434 }
435
436 //=======================================================================
437 //function : WriteMessage
438 //purpose  : write  theMessage  to  the  MessageDriver  of  the
439 //           Application
440 //=======================================================================
441
442 void BinLDrivers_DocumentStorageDriver::WriteMessage
443                          (const TCollection_ExtendedString& theMsg)
444 {
445   if (!myMsgDriver.IsNull())
446     myMsgDriver->Write (theMsg.ToExtString());
447 }
448
449 //=======================================================================
450 //function : AddSection
451 //purpose  : 
452 //=======================================================================
453
454 void BinLDrivers_DocumentStorageDriver::AddSection
455                                 (const TCollection_AsciiString& theName,
456                                  const Standard_Boolean         isPostRead)
457 {
458   mySections.Append (BinLDrivers_DocumentSection (theName, isPostRead));
459 }
460
461 //=======================================================================
462 //function : WriteSection
463 //purpose  : 
464 //=======================================================================
465
466 void BinLDrivers_DocumentStorageDriver::WriteSection
467                                 (const TCollection_AsciiString& /*theName*/,
468                                  const Handle_CDM_Document&     /*theDocument*/,
469                                  Standard_OStream&              /*theOS*/)
470 {
471   // empty; should be redefined in subclasses
472 }
473
474 //=======================================================================
475 //function : WriteShapeSection
476 //purpose  : defines WriteShapeSection
477 //=======================================================================
478 void BinLDrivers_DocumentStorageDriver::WriteShapeSection
479                                 (BinLDrivers_DocumentSection&   theSection,
480                                  Standard_OStream&              theOS)
481 {
482   const Standard_Size aShapesSectionOffset = (Standard_Size) theOS.tellp();
483   theSection.Write (theOS, aShapesSectionOffset);
484 }