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