Commit | Line | Data |
---|---|---|
b311480e | 1 | // Created on: 2002-10-29 |
2 | // Created by: Michael SAZONOV | |
973c2be1 | 3 | // Copyright (c) 2002-2014 OPEN CASCADE SAS |
b311480e | 4 | // |
973c2be1 | 5 | // This file is part of Open CASCADE Technology software library. |
b311480e | 6 | // |
d5f74e42 | 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 | |
973c2be1 | 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. | |
b311480e | 12 | // |
973c2be1 | 13 | // Alternatively, this file may be used under the terms of Open CASCADE |
14 | // commercial license or contractual agreement. | |
7fd59977 | 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 | { | |
15e8b082 M |
68 | SetIsError(Standard_False); |
69 | SetStoreStatus(PCDM_SS_OK); | |
70 | ||
7fd59977 | 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()) { | |
15e8b082 M |
84 | SetIsError(Standard_True); |
85 | SetStoreStatus(PCDM_SS_Doc_IsNull); | |
7fd59977 | 86 | } |
87 | else { | |
88 | // Open the file | |
d9ff84e8 | 89 | TCollection_AsciiString aFileName (theFileName); |
7fd59977 | 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(); | |
15e8b082 M |
100 | if (IsError()) |
101 | { | |
102 | SetStoreStatus(PCDM_SS_Info_Section_Error); | |
103 | return; | |
104 | } | |
7fd59977 | 105 | |
d9ff84e8 | 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 | |
7fd59977 | 109 | ofstream anOS (aFileName.ToCString(), ios::in | ios::binary | ios::ate); |
110 | #else | |
111 | ofstream anOS (aFileName.ToCString(), ios::ate); | |
9293178b | 112 | //ofstream anOS (aFileName.ToCString(), ios::out| ios::binary | ios::ate); |
7fd59977 | 113 | #endif |
63c629aa | 114 | #ifdef BINLDRIVERS_DEB |
9293178b | 115 | const Standard_Integer aP = (Standard_Integer) anOS.tellp(); |
7fd59977 | 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 | ||
9293178b | 127 | // Shapes Section is the last one, it indicates the end of the table. |
7fd59977 | 128 | BinLDrivers_DocumentSection aShapesSection (SHAPESECTION_POS, |
129 | Standard_False); | |
9293178b | 130 | aShapesSection.WriteTOC (anOS); |
7fd59977 | 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 | ||
9293178b | 151 | // End of processing: close structures and check the status |
7fd59977 | 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 | |
15e8b082 M |
161 | SetIsError(Standard_True); |
162 | SetStoreStatus(PCDM_SS_No_Obj); | |
163 | ||
7fd59977 | 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=" | |
9293178b | 173 | + (Standard_Integer )anOS.rdstate()); |
7fd59977 | 174 | #else |
175 | TCollection_ExtendedString aStr = | |
176 | anErrorStr + aMethStr + "Problem writing the file "; | |
177 | WriteMessage (aStr + theFileName); | |
178 | #endif | |
15e8b082 | 179 | SetIsError(Standard_True); |
566f8441 | 180 | SetStoreStatus(PCDM_SS_WriteFailure); |
7fd59977 | 181 | } |
182 | ||
183 | } | |
184 | } | |
185 | ||
186 | //======================================================================= | |
187 | //function : UnsupportedAttrMsg | |
9293178b | 188 | //purpose : |
7fd59977 | 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 | ||
7fd59977 | 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 | |
15e8b082 | 378 | SetIsError(Standard_True); |
7fd59977 | 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 | |
9293178b | 412 | (1, // nbObj |
7fd59977 | 413 | BinLDrivers::StorageVersion(), |
414 | Storage_Schema::ICreationDate(), | |
415 | TCollection_AsciiString(SchemaName(),'?'), | |
9293178b | 416 | 1, // schemaVersion |
7fd59977 | 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 | |
15e8b082 | 438 | SetIsError(Standard_True); |
7fd59977 | 439 | } |
63c629aa | 440 | #ifdef BINLDRIVERS_DEB |
9293178b | 441 | const Standard_Integer aP = (Standard_Integer) aFileDriver.Tell(); |
7fd59977 | 442 | cout << "POS = " << aP <<endl; |
9293178b | 443 | #endif |
7fd59977 | 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 | |
9293178b | 462 | //purpose : |
7fd59977 | 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 | |
9293178b | 474 | //purpose : |
7fd59977 | 475 | //======================================================================= |
476 | ||
477 | void BinLDrivers_DocumentStorageDriver::WriteSection | |
478 | (const TCollection_AsciiString& /*theName*/, | |
857ffd5e | 479 | const Handle(CDM_Document)& /*theDocument*/, |
7fd59977 | 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 | } |