0032402: Coding Rules - eliminate msvc warning C4668 (symbol is not defined as a...
[occt.git] / src / BinLDrivers / BinLDrivers_DocumentStorageDriver.cxx
1 // Created on: 2002-10-29
2 // Created by: Michael SAZONOV
3 // Copyright (c) 2002-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
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.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16
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>
46
47 IMPLEMENT_STANDARD_RTTIEXT(BinLDrivers_DocumentStorageDriver,PCDM_StorageDriver)
48
49 #define SHAPESECTION_POS (Standard_CString)"SHAPE_SECTION_POS:"
50
51 //=======================================================================
52 //function : BinLDrivers_DocumentStorageDriver
53 //purpose  : Constructor
54 //=======================================================================
55
56 BinLDrivers_DocumentStorageDriver::BinLDrivers_DocumentStorageDriver ()
57 {
58 }
59
60 //=======================================================================
61 //function : Write
62 //purpose  :
63 //=======================================================================
64
65 void BinLDrivers_DocumentStorageDriver::Write
66                           (const Handle(CDM_Document)&       theDocument,
67                            const TCollection_ExtendedString& theFileName,
68                            const Message_ProgressRange&      theRange)
69 {
70   SetIsError(Standard_False);
71   SetStoreStatus(PCDM_SS_OK);
72
73   myFileName = theFileName;
74
75   std::ofstream aFileStream;
76   OSD_OpenStream (aFileStream, theFileName, std::ios::out | std::ios::binary);
77
78   if (aFileStream.is_open() && aFileStream.good())
79   {
80     Write(theDocument, aFileStream, theRange);
81   }
82   else
83   {
84     SetIsError (Standard_True);
85     SetStoreStatus(PCDM_SS_WriteFailure);
86   }
87 }
88
89 //=======================================================================
90 //function : Write
91 //purpose  :
92 //=======================================================================
93
94 void BinLDrivers_DocumentStorageDriver::Write (const Handle(CDM_Document)&  theDoc, 
95                                                Standard_OStream&            theOStream,
96                                                const Message_ProgressRange& theRange)
97 {
98   myMsgDriver = theDoc->Application()->MessageDriver();
99   myMapUnsupported.Clear();
100
101   Handle(TDocStd_Document) aDoc =
102     Handle(TDocStd_Document)::DownCast(theDoc);
103   if (aDoc.IsNull()) {
104     SetIsError(Standard_True);
105     SetStoreStatus(PCDM_SS_Doc_IsNull);
106   }
107   else {
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(); // 
115
116 //  1. Write info section (including types table)
117     WriteInfoSection (aDoc, theOStream);
118
119     myTypesMap.Clear();
120     if (IsError())
121     {
122         SetStoreStatus(PCDM_SS_Info_Section_Error);
123         return;
124     }
125
126 //  2. Write the Table of Contents of Sections
127     const TDocStd_FormatVersion aDocVer = aDoc->StorageFormatVersion();
128     BinLDrivers_VectorOfDocumentSection::Iterator anIterS (mySections);
129     for (; anIterS.More(); anIterS.Next())
130       anIterS.ChangeValue().WriteTOC (theOStream, aDocVer);
131
132     // Shapes Section is the last one, it indicates the end of the table.
133     BinLDrivers_DocumentSection aShapesSection (SHAPESECTION_POS,
134                                                 Standard_False);
135     aShapesSection.WriteTOC (theOStream, aDocVer);
136
137 //  3. Write document contents
138     // (Storage data to the stream)
139     myRelocTable.Clear();
140     myPAtt.Init();
141
142     Message_ProgressScope aPS(theRange, "Writing document", 3);
143
144 //  Write Doc structure
145     WriteSubTree (aData->Root(), theOStream, aPS.Next()); // Doc is written
146     if (!aPS.More())
147     {
148       SetIsError(Standard_True);
149       SetStoreStatus(PCDM_SS_UserBreak);
150       return;
151     }
152
153 //  4. Write Shapes section
154     WriteShapeSection (aShapesSection, theOStream, aDocVer, aPS.Next());
155     if (!aPS.More())
156     {
157        SetIsError(Standard_True);
158        SetStoreStatus(PCDM_SS_UserBreak);
159        return;
160     }
161
162     // Write application-defined sections
163     for (anIterS.Init (mySections); anIterS.More(); anIterS.Next()) {
164       BinLDrivers_DocumentSection& aSection = anIterS.ChangeValue();
165       const Standard_Size aSectionOffset = (Standard_Size) theOStream.tellp();
166       WriteSection (aSection.Name(), aDoc, theOStream);
167       aSection.Write (theOStream, aSectionOffset, aDocVer);
168     }
169
170     // End of processing: close structures and check the status
171     myPAtt.Destroy();   // free buffer
172     myEmptyLabels.Clear();
173     myMapUnsupported.Clear();
174
175     if (!myRelocTable.Extent()) {
176       // No objects written
177 #ifdef OCCT_DEBUG
178       myMsgDriver->Send ("BinLDrivers_DocumentStorageDriver, no objects written", Message_Info);
179 #endif
180       SetIsError(Standard_True);
181       SetStoreStatus(PCDM_SS_No_Obj);
182     }
183     myRelocTable.Clear();
184     if (!aPS.More())
185     {
186       SetIsError(Standard_True);
187       SetStoreStatus(PCDM_SS_UserBreak);
188       return;
189     }
190     aPS.Next();
191     if (!theOStream) {
192       // A problem with the stream
193 #ifdef OCCT_DEBUG
194       TCollection_ExtendedString anErrorStr ("BinLDrivers_DocumentStorageDriver, Problem with the file stream, rdstate = ");
195       myMsgDriver->Send (anErrorStr + (Standard_Integer )theOStream.rdstate(), Message_Info);
196 #endif
197       SetIsError(Standard_True);
198       SetStoreStatus(PCDM_SS_WriteFailure);
199     }
200
201   }
202 }
203
204 //=======================================================================
205 //function : UnsupportedAttrMsg
206 //purpose  :
207 //=======================================================================
208
209 void BinLDrivers_DocumentStorageDriver::UnsupportedAttrMsg
210                         (const Handle(Standard_Type)& theType)
211 {
212 #ifdef OCCT_DEBUG
213   TCollection_ExtendedString aMsg
214     ("BinDrivers_DocumentStorageDriver: warning: attribute driver for type ");
215 #endif
216   if (!myMapUnsupported.Contains(theType)) {
217     myMapUnsupported.Add(theType);
218 #ifdef OCCT_DEBUG
219     myMsgDriver->Send (aMsg + theType->Name() + " not found", Message_Info);
220 #endif
221   }
222 }
223
224 //=======================================================================
225 //function : WriteSubTree
226 //purpose  :
227 //=======================================================================
228
229 void BinLDrivers_DocumentStorageDriver::WriteSubTree
230                         (const TDF_Label&             theLabel,
231                          Standard_OStream&            theOS,
232                          const Message_ProgressRange& theRange)
233 {
234   // Skip empty labels
235   if (!myEmptyLabels.IsEmpty() && myEmptyLabels.First() == theLabel) {
236     myEmptyLabels.RemoveFirst();
237     return;
238   }
239   Message_ProgressScope aPS(theRange, "Writing sub tree", 2, true);
240   // Write label header: tag
241   Standard_Integer aTag = theLabel.Tag();
242 #ifdef DO_INVERSE
243   aTag = InverseInt (aTag);
244 #endif
245   theOS.write ((char*)&aTag, sizeof(Standard_Integer));
246
247   // Write attributes
248   TDF_AttributeIterator itAtt (theLabel);
249   for ( ; itAtt.More() && theOS && aPS.More(); itAtt.Next()) {
250     const Handle(TDF_Attribute) tAtt = itAtt.Value();
251     const Handle(Standard_Type)& aType = tAtt->DynamicType();
252     // Get type ID and driver
253     Handle(BinMDF_ADriver) aDriver;
254     const Standard_Integer aTypeId = myDrivers->GetDriver (aType,aDriver);
255     if (aTypeId > 0) {
256       // Add source to relocation table
257       const Standard_Integer anId = myRelocTable.Add (tAtt);
258
259       // Create and fill data item
260       myPAtt.SetTypeId (aTypeId);
261       myPAtt.SetId (anId);
262       aDriver->Paste (tAtt, myPAtt, myRelocTable);
263
264       // Write data to the stream -->!!!
265       theOS << myPAtt;
266     }
267 #ifdef OCCT_DEBUG
268     else
269       UnsupportedAttrMsg (aType);
270 #endif
271   }
272   if (!theOS) {
273     // Problem with the stream
274     return;
275   }
276   if (!aPS.More())
277   {
278     SetIsError(Standard_True);
279     SetStoreStatus(PCDM_SS_UserBreak);
280     return;
281   }
282   // Write the end attributes list marker
283   BinLDrivers_Marker anEndAttr = BinLDrivers_ENDATTRLIST;
284 #ifdef DO_INVERSE
285   anEndAttr = (BinLDrivers_Marker) InverseInt (anEndAttr);
286 #endif
287   theOS.write ((char*)&anEndAttr, sizeof(anEndAttr));
288
289   // Process sub-labels
290   TDF_ChildIterator itChld (theLabel);
291   for ( ; itChld.More(); itChld.Next())
292   {
293     const TDF_Label& aChildLab = itChld.Value();
294     if (!aPS.More())
295     {
296       SetIsError(Standard_True);
297       SetStoreStatus(PCDM_SS_UserBreak);
298       return;
299     }
300     WriteSubTree (aChildLab, theOS, aPS.Next());
301   }
302
303   // Write the end label marker
304   BinLDrivers_Marker anEndLabel = BinLDrivers_ENDLABEL;
305 #ifdef DO_INVERSE
306   anEndLabel = (BinLDrivers_Marker) InverseInt (anEndLabel);
307 #endif
308   theOS.write ((char*)&anEndLabel, sizeof(anEndLabel));
309
310 }
311
312 //=======================================================================
313 //function : AttributeDrivers
314 //purpose  :
315 //=======================================================================
316
317 Handle(BinMDF_ADriverTable) BinLDrivers_DocumentStorageDriver::AttributeDrivers
318        (const Handle(Message_Messenger)& theMessageDriver)
319 {
320   return BinLDrivers::AttributeDrivers (theMessageDriver);
321 }
322
323 //=======================================================================
324 //function : FirstPassSubTree
325 //purpose  :
326 //=======================================================================
327
328 Standard_Boolean BinLDrivers_DocumentStorageDriver::FirstPassSubTree
329                          (const TDF_Label&                   L,
330                           TDF_LabelList&                     ListOfEmptyL)
331 {
332   // are there writable attributes on L ?
333   Standard_Boolean hasAttr = Standard_False;
334   TDF_AttributeIterator itAtt (L);
335   for ( ; itAtt.More(); itAtt.Next()) {
336     const Handle(Standard_Type)& aType = itAtt.Value()->DynamicType();
337     Handle(BinMDF_ADriver) aDriver;
338     // do not rely on a value returned by GetDriver here, because
339     // the IDs have not yet been assigned to the types
340     myDrivers->GetDriver (aType, aDriver);
341     if (!aDriver.IsNull()) {
342       hasAttr = Standard_True;
343       myTypesMap.Add (aType);
344     }
345 #ifdef OCCT_DEBUG
346     else
347       UnsupportedAttrMsg (aType);
348 #endif
349   }
350
351   // are there writable attributes on sub-labels ?
352   Standard_Boolean hasChildAttr = Standard_False;
353   TDF_LabelList emptyChildrenList;
354   TDF_ChildIterator itChld (L);
355   for ( ; itChld.More(); itChld.Next())
356   {
357     if (FirstPassSubTree (itChld.Value(), emptyChildrenList))
358       emptyChildrenList.Append( itChld.Value() );
359     else
360       hasChildAttr = Standard_True;
361   }
362
363   Standard_Boolean isEmpty = !(hasAttr || hasChildAttr);
364
365   if (!isEmpty)
366     ListOfEmptyL.Append( emptyChildrenList );
367
368   return isEmpty;
369 }
370
371 //=======================================================================
372 //function : FirstPass
373 //purpose  :
374 //=======================================================================
375
376 void BinLDrivers_DocumentStorageDriver::FirstPass
377                          (const TDF_Label& theRoot)
378 {
379   myTypesMap.Clear();
380   myEmptyLabels.Clear();
381
382   if (FirstPassSubTree( theRoot, myEmptyLabels))
383     myEmptyLabels.Append( theRoot );
384
385   myDrivers->AssignIds (myTypesMap);
386 }
387
388 //=======================================================================
389 //function : WriteInfoSection
390 //purpose  : Write info section using FSD_BinaryFile driver
391 //=======================================================================
392
393 #define START_TYPES "START_TYPES"
394 #define END_TYPES "END_TYPES"
395
396 void BinLDrivers_DocumentStorageDriver::WriteInfoSection 
397                          (const Handle(CDM_Document)&    theDoc,
398                           Standard_OStream&              theOStream)
399 {
400   // Magic number
401   theOStream.write (FSD_BinaryFile::MagicNumber(), strlen(FSD_BinaryFile::MagicNumber()));
402
403   FSD_FileHeader aHeader;
404
405   {
406     aHeader.testindian  = -1;
407     aHeader.binfo       = -1;
408     aHeader.einfo       = -1;
409     aHeader.bcomment    = -1;
410     aHeader.ecomment    = -1;
411     aHeader.btype       = -1;
412     aHeader.etype       = -1;
413     aHeader.broot       = -1;
414     aHeader.eroot       = -1;
415     aHeader.bref        = -1;
416     aHeader.eref        = -1;
417     aHeader.bdata       = -1;
418     aHeader.edata       = -1;
419   }
420
421   // aHeader.testindian
422   {
423     union {
424       char ti2[4];
425       Standard_Integer aResult;
426     } aWrapUnion;
427
428     aWrapUnion.ti2[0] = 1;
429     aWrapUnion.ti2[1] = 2;
430     aWrapUnion.ti2[2] = 3;
431     aWrapUnion.ti2[3] = 4;
432
433     aHeader.testindian = aWrapUnion.aResult;
434   }
435
436   // info section
437   aHeader.binfo = (Standard_Integer)theOStream.tellp();
438
439   // header section
440   aHeader.einfo = aHeader.binfo + FSD_BinaryFile::WriteHeader (theOStream, aHeader, Standard_True);
441   
442   // add format
443   Handle(Storage_Data) theData = new Storage_Data;
444   PCDM_ReadWriter::WriteFileFormat (theData, theDoc);
445   PCDM_ReadWriter::Writer()->WriteReferenceCounter (theData, theDoc);
446   PCDM_ReadWriter::Writer()->WriteReferences       (theData, theDoc, myFileName);
447   PCDM_ReadWriter::Writer()->WriteExtensions       (theData, theDoc);
448   PCDM_ReadWriter::Writer()->WriteVersion          (theData, theDoc);
449
450   // add the types table
451   theData->AddToUserInfo(START_TYPES);
452   for (Standard_Integer i = 1; i <= myTypesMap.Extent(); i++)
453   {
454     Handle(BinMDF_ADriver) aDriver = myDrivers->GetDriver(i);
455     if (!aDriver.IsNull())
456     {
457       const TCollection_AsciiString& aTypeName = aDriver->TypeName();
458       theData->AddToUserInfo (aTypeName);
459     }
460   }
461   theData->AddToUserInfo(END_TYPES);
462
463   Standard_Integer aObjNb = 1;
464   Standard_Integer aShemaVer = 1;
465
466   // Store the name and version of the application that has created the
467   // document.
468   theData->SetApplicationVersion(theDoc->Application()->Version());
469   theData->SetApplicationName(theDoc->Application()->Name());
470
471   Handle(TDocStd_Document) aDoc = Handle(TDocStd_Document)::DownCast(theDoc);
472   const Standard_Integer aDocVer = aDoc->StorageFormatVersion();
473   aHeader.einfo += FSD_BinaryFile::WriteInfo (theOStream,
474                                               aObjNb,
475                                               aDocVer,
476                                               Storage_Schema::ICreationDate(),
477                                               "", // schema name
478                                               aShemaVer,
479                                               theData->ApplicationName(),
480                                               theData->ApplicationVersion(),
481                                               theData->DataType(),
482                                               theData->UserInfo(),
483                                               Standard_True); // only count the size of the section
484
485   // calculate comment section
486   TColStd_SequenceOfExtendedString aComments;
487   theDoc->Comments(aComments);
488   for (Standard_Integer i = 1; i <= aComments.Length(); i++)
489   {
490     theData->AddToComments (aComments(i));
491   }
492
493   aHeader.bcomment = aHeader.einfo;
494   aHeader.ecomment = aHeader.bcomment + FSD_BinaryFile::WriteComment(theOStream, theData->Comments(), Standard_True);
495
496   aHeader.edata = aHeader.ecomment;
497
498   // write header information
499   FSD_BinaryFile::WriteHeader (theOStream, aHeader);
500
501   // write info section
502   FSD_BinaryFile::WriteInfo (theOStream,
503                              aObjNb,
504                              aDocVer,
505                              Storage_Schema::ICreationDate(),
506                              "", // schema name
507                              aShemaVer,
508                              theData->ApplicationName(),
509                              theData->ApplicationVersion(),
510                              theData->DataType(),
511                              theData->UserInfo());
512
513   // write the comments
514   FSD_BinaryFile::WriteComment(theOStream, theData->Comments());
515   
516 }
517
518 //=======================================================================
519 //function : AddSection
520 //purpose  :
521 //=======================================================================
522
523 void BinLDrivers_DocumentStorageDriver::AddSection
524                                 (const TCollection_AsciiString& theName,
525                                  const Standard_Boolean         isPostRead)
526 {
527   mySections.Append (BinLDrivers_DocumentSection (theName, isPostRead));
528 }
529
530 //=======================================================================
531 //function : WriteSection
532 //purpose  :
533 //=======================================================================
534
535 void BinLDrivers_DocumentStorageDriver::WriteSection
536                                 (const TCollection_AsciiString& /*theName*/,
537                                  const Handle(CDM_Document)&     /*theDocument*/,
538                                  Standard_OStream&              /*theOS*/)
539 {
540   // empty; should be redefined in subclasses
541 }
542
543 //=======================================================================
544 //function : WriteShapeSection
545 //purpose  : defines WriteShapeSection
546 //=======================================================================
547 void BinLDrivers_DocumentStorageDriver::WriteShapeSection
548                                 (BinLDrivers_DocumentSection&   theSection,
549                                  Standard_OStream&              theOS,
550                                  const TDocStd_FormatVersion    theDocVer,
551                                  const Message_ProgressRange& /*theRange*/)
552 {
553   const Standard_Size aShapesSectionOffset = (Standard_Size) theOS.tellp();
554   theSection.Write (theOS, aShapesSectionOffset, theDocVer);
555 }