0024400: Wrong result obtained by Section
[occt.git] / src / BinLDrivers / BinLDrivers_DocumentStorageDriver.cxx
CommitLineData
b311480e 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
7fd59977 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
49BinLDrivers_DocumentStorageDriver::BinLDrivers_DocumentStorageDriver ()
50{
51}
52
53//=======================================================================
54//function : SchemaName
55//purpose :
56//=======================================================================
57
58TCollection_ExtendedString BinLDrivers_DocumentStorageDriver::SchemaName() const
59{
60 TCollection_ExtendedString schemaname;
61 return schemaname;
62}
63
64//=======================================================================
65//function : Write
66//purpose :
67//=======================================================================
68
69void BinLDrivers_DocumentStorageDriver::Write
70 (const Handle(CDM_Document)& theDocument,
71 const TCollection_ExtendedString& theFileName)
72{
15e8b082
M
73 SetIsError(Standard_False);
74 SetStoreStatus(PCDM_SS_OK);
75
7fd59977 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()) {
15e8b082
M
89 SetIsError(Standard_True);
90 SetStoreStatus(PCDM_SS_Doc_IsNull);
7fd59977 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();
15e8b082
M
105 if (IsError())
106 {
107 SetStoreStatus(PCDM_SS_Info_Section_Error);
108 return;
109 }
7fd59977 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);
9293178b 115 //ofstream anOS (aFileName.ToCString(), ios::out| ios::binary | ios::ate);
7fd59977 116#endif
117#ifdef DEB
9293178b 118 const Standard_Integer aP = (Standard_Integer) anOS.tellp();
7fd59977 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
9293178b 130 // Shapes Section is the last one, it indicates the end of the table.
7fd59977 131 BinLDrivers_DocumentSection aShapesSection (SHAPESECTION_POS,
132 Standard_False);
9293178b 133 aShapesSection.WriteTOC (anOS);
7fd59977 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
9293178b 154// End of processing: close structures and check the status
7fd59977 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
15e8b082
M
164 SetIsError(Standard_True);
165 SetStoreStatus(PCDM_SS_No_Obj);
166
7fd59977 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="
9293178b 176 + (Standard_Integer )anOS.rdstate());
7fd59977 177#else
178 TCollection_ExtendedString aStr =
179 anErrorStr + aMethStr + "Problem writing the file ";
180 WriteMessage (aStr + theFileName);
181#endif
15e8b082
M
182 SetIsError(Standard_True);
183 SetStoreStatus(PCDM_SS_DiskWritingFailure);
7fd59977 184 }
185
186 }
187}
188
189//=======================================================================
190//function : UnsupportedAttrMsg
9293178b 191//purpose :
7fd59977 192//=======================================================================
193
194void 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
214void 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
7fd59977 285//=======================================================================
286//function : AttributeDrivers
287//purpose :
288//=======================================================================
289
290Handle(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
301Standard_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
349void 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
369void 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
15e8b082 381 SetIsError(Standard_True);
7fd59977 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
9293178b 415 (1, // nbObj
7fd59977 416 BinLDrivers::StorageVersion(),
417 Storage_Schema::ICreationDate(),
418 TCollection_AsciiString(SchemaName(),'?'),
9293178b 419 1, // schemaVersion
7fd59977 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
15e8b082 441 SetIsError(Standard_True);
7fd59977 442 }
443#ifdef DEB
9293178b 444 const Standard_Integer aP = (Standard_Integer) aFileDriver.Tell();
7fd59977 445 cout << "POS = " << aP <<endl;
9293178b 446#endif
7fd59977 447 aFileDriver.Close();
448}
449
450//=======================================================================
451//function : WriteMessage
452//purpose : write theMessage to the MessageDriver of the
453// Application
454//=======================================================================
455
456void BinLDrivers_DocumentStorageDriver::WriteMessage
457 (const TCollection_ExtendedString& theMsg)
458{
459 if (!myMsgDriver.IsNull())
460 myMsgDriver->Write (theMsg.ToExtString());
461}
462
463//=======================================================================
464//function : AddSection
9293178b 465//purpose :
7fd59977 466//=======================================================================
467
468void 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
9293178b 477//purpose :
7fd59977 478//=======================================================================
479
480void 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//=======================================================================
492void 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}