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