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