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