1 // Copyright (c) 1998-1999 Matra Datavision
2 // Copyright (c) 1999-2014 OPEN CASCADE SAS
4 // This file is part of Open CASCADE Technology software library.
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
16 #include <Standard_ErrorHandler.hxx>
17 #include <Standard_Persistent.hxx>
18 #include <Standard_Type.hxx>
19 #include <Storage.hxx>
20 #include <Storage_BaseDriver.hxx>
21 #include <Storage_BucketOfPersistent.hxx>
22 #include <Storage_CallBack.hxx>
23 #include <Storage_Data.hxx>
24 #include <Storage_DataMapIteratorOfMapOfCallBack.hxx>
25 #include <Storage_DefaultCallBack.hxx>
26 #include <Storage_HArrayOfCallBack.hxx>
27 #include <Storage_HeaderData.hxx>
28 #include <Storage_HPArray.hxx>
29 #include <Storage_HSeqOfRoot.hxx>
30 #include <Storage_InternalData.hxx>
31 #include <Storage_Root.hxx>
32 #include <Storage_RootData.hxx>
33 #include <Storage_Schema.hxx>
34 #include <Storage_StreamExtCharParityError.hxx>
35 #include <Storage_StreamFormatError.hxx>
36 #include <Storage_StreamModeError.hxx>
37 #include <Storage_StreamReadError.hxx>
38 #include <Storage_StreamTypeMismatchError.hxx>
39 #include <Storage_StreamUnknownTypeError.hxx>
40 #include <Storage_StreamWriteError.hxx>
41 #include <Storage_TypeData.hxx>
42 #include <Storage_TypedCallBack.hxx>
43 #include <TCollection_AsciiString.hxx>
44 #include <TColStd_HSequenceOfAsciiString.hxx>
45 #include <TColStd_MapOfAsciiString.hxx>
49 IMPLEMENT_STANDARD_RTTIEXT(Storage_Schema,Standard_Transient)
51 #define DATATYPE_MIGRATION
53 #ifdef DATATYPE_MIGRATION
54 #include <NCollection_DataMap.hxx>
55 #include <OSD_File.hxx>
56 #include <OSD_Path.hxx>
57 #include <OSD_Protection.hxx>
58 #include <OSD_Environment.hxx>
60 typedef NCollection_DataMap <TCollection_AsciiString,
61 TCollection_AsciiString> DataMapOfAStringAString;
65 // IMPLEMENTATION BucketOfPersistent
67 Storage_Bucket::~Storage_Bucket()
69 Standard::Free (mySpace);
75 //=======================================================================
78 //=======================================================================
80 void Storage_Bucket::Clear()
85 //=======================================================================
88 //=======================================================================
90 void Storage_Bucket::Append(Standard_Persistent *sp)
93 mySpace[myCurrentSpace] = sp;
96 //=======================================================================
99 //=======================================================================
101 Standard_Persistent* Storage_Bucket::Value
102 (const Standard_Integer theIndex) const
104 return mySpace[theIndex];
107 //=======================================================================
108 //function : Storage_BucketOfPersistent
110 //=======================================================================
112 Storage_BucketOfPersistent::Storage_BucketOfPersistent
113 (const Standard_Integer theBucketSize,
114 const Standard_Integer theBucketNumber)
115 : myNumberOfBucket(1),myNumberOfBucketAllocated(theBucketNumber),myBucketSize
118 myBuckets = (Storage_Bucket**)Standard::Allocate
119 (sizeof(Storage_Bucket*) * theBucketNumber);
120 myBuckets[0] = new Storage_Bucket(myBucketSize);
121 myCurrentBucket = myBuckets[0];
123 myCurrentBucketNumber = 0;
126 //=======================================================================
129 //=======================================================================
131 void Storage_BucketOfPersistent::Clear()
136 for (i = 1; i < myNumberOfBucket; i++) delete myBuckets[i];
137 myNumberOfBucket = 1;
138 myCurrentBucket = myBuckets[0];
139 myCurrentBucket->Clear();
140 myCurrentBucketNumber = 0;
145 Storage_BucketOfPersistent::~Storage_BucketOfPersistent()
149 Standard::Free (myBuckets);
153 //=======================================================================
156 //=======================================================================
158 Standard_Persistent* Storage_BucketOfPersistent::Value
159 (const Standard_Integer theIndex)
161 Standard_Integer theInd,theCurrentBucketNumber,tecurrentind = theIndex - 1;
162 theCurrentBucketNumber = tecurrentind / myBucketSize;
163 theInd = tecurrentind - (myBucketSize * theCurrentBucketNumber);
165 return myBuckets[theCurrentBucketNumber]->mySpace[theInd];
169 //=======================================================================
172 //=======================================================================
174 void Storage_BucketOfPersistent::Append(const Handle(Standard_Persistent)& sp)
176 myCurrentBucket->myCurrentSpace++;
178 if (myCurrentBucket->myCurrentSpace != myBucketSize) {
180 myCurrentBucket->mySpace[myCurrentBucket->myCurrentSpace] = sp.get();
184 myCurrentBucket->myCurrentSpace--;
186 myCurrentBucketNumber++;
188 if (myNumberOfBucket > myNumberOfBucketAllocated) {
189 Standard_Size e = sizeof(Storage_Bucket*) * myNumberOfBucketAllocated;
190 myBuckets = (Storage_Bucket**)Standard::Reallocate(myBuckets, e * 2);
191 myNumberOfBucketAllocated *= 2;
194 myBuckets[myCurrentBucketNumber] = new Storage_Bucket(myBucketSize);
195 myCurrentBucket = myBuckets[myCurrentBucketNumber];
196 myCurrentBucket->myCurrentSpace++;
198 myCurrentBucket->mySpace[myCurrentBucket->myCurrentSpace] = sp.get();
201 //=======================================================================
202 //function : Storage_BucketIterator
204 //=======================================================================
206 Storage_BucketIterator::Storage_BucketIterator
207 (Storage_BucketOfPersistent* aBucketManager)
208 : myBucket(0), myCurrentBucket(0),
209 myCurrentBucketIndex(0), myCurrentIndex(0),
210 myBucketNumber(0), myMoreObject(Standard_False)
212 if (aBucketManager) {
213 myBucket = aBucketManager;
214 myCurrentBucket = myBucket->myBuckets[0];
215 myBucketNumber = aBucketManager->myNumberOfBucket;
216 myCurrentBucketIndex = 0;
218 myMoreObject = Standard_True;
222 //=======================================================================
225 //=======================================================================
227 void Storage_BucketIterator::Reset()
230 myCurrentBucket = myBucket->myBuckets[0];
231 myBucketNumber = myBucket->myNumberOfBucket;
233 myCurrentBucketIndex = 0;
234 myMoreObject = Standard_True;
236 else myMoreObject = Standard_False;
239 //=======================================================================
242 //=======================================================================
244 void Storage_BucketIterator::Init(Storage_BucketOfPersistent* aBucketManager)
246 if (aBucketManager) {
247 myBucket = aBucketManager;
248 myCurrentBucket = myBucket->myBuckets[0];
249 myBucketNumber = aBucketManager->myNumberOfBucket;
251 myCurrentBucketIndex = 0;
252 myMoreObject = Standard_True;
254 else myMoreObject = Standard_False;
257 //=======================================================================
260 //=======================================================================
262 void Storage_BucketIterator::Next()
264 if (!myMoreObject) return;
266 if (myCurrentIndex < myCurrentBucket->myCurrentSpace) {
271 myCurrentBucketIndex++;
272 if (myCurrentBucketIndex < myBucketNumber) {
273 myCurrentBucket = myBucket->myBuckets[myCurrentBucketIndex];
276 myMoreObject = Standard_False;
281 //=======================================================================
282 //function : Storage_Schema
283 //purpose : USER API -- --------------------------------------------------------------
284 // IMPLEMENTATION BucketOfPersistent
285 //=======================================================================
287 Storage_Schema::Storage_Schema()
290 ResetDefaultCallBack();
291 myCallBackState = Standard_False;
294 //=======================================================================
295 //function : SetVersion
296 //purpose : returns version of the schema
297 //=======================================================================
299 void Storage_Schema::SetVersion(const TCollection_AsciiString& aVersion)
301 myVersion = aVersion;
304 //=======================================================================
306 //purpose : returns the version of the schema
307 //=======================================================================
309 TCollection_AsciiString Storage_Schema::Version() const
314 //=======================================================================
316 //purpose : set the schema's name
317 //=======================================================================
319 void Storage_Schema::SetName(const TCollection_AsciiString& aSchemaName)
321 myName = aSchemaName;
324 //=======================================================================
326 //purpose : returns the schema's name
327 //=======================================================================
329 TCollection_AsciiString Storage_Schema::Name() const
334 //=======================================================================
338 // s: driver to write
339 // raises if the stream is not opened in VSWrite or
341 //=======================================================================
343 void Storage_Schema::Write (const Handle(Storage_BaseDriver)& theDriver,
344 const Handle(Storage_Data)& aData) const
346 if (aData.IsNull()) return;
348 // add all the persistent to write...
350 Standard_Integer posfrom,posto;
351 Handle(Standard_Persistent) p;
352 Handle(Storage_HSeqOfRoot) plist;
353 TCollection_AsciiString errorContext("AddPersistent");
354 Storage_Schema::ISetCurrentData(aData);
356 Handle(Storage_InternalData) iData = aData->InternalData();
359 aData->ClearErrorStatus();
361 plist = aData->Roots();
363 for (posto = 1; posto <= plist->Length(); posto++) {
364 PersistentToAdd(plist->Value(posto)->Object());
367 for (posto = 1; posto <= plist->Length(); posto++) {
368 // AddTypeSelection(plist->Value(posto)->Object());
371 for (posfrom = plist->Length() + 1; posfrom <= iData->myPtoA.Length(); posfrom++) {
372 // AddTypeSelection(iData->myPtoA.Value(posfrom));
375 // ...and now we write
380 aData->HeaderData()->SetCreationDate(ICreationDate());
381 aData->HeaderData()->SetStorageVersion(Storage::Version());
382 aData->HeaderData()->SetNumberOfObjects(iData->myPtoA.Length());
383 aData->HeaderData()->SetSchemaName(myName);
384 aData->HeaderData()->SetSchemaVersion(myVersion);
386 if ((theDriver->OpenMode() == Storage_VSWrite) || (theDriver->OpenMode() == Storage_VSReadWrite)) {
389 errorContext = "BeginWriteInfoSection";
390 theDriver->BeginWriteInfoSection();
391 errorContext = "WriteInfo";
392 theDriver->WriteInfo(aData->NumberOfObjects(),
393 aData->StorageVersion(),
394 aData->CreationDate(),
396 aData->SchemaVersion(),
397 aData->ApplicationName(),
398 aData->ApplicationVersion(),
401 errorContext = "EndWriteInfoSection";
402 theDriver->EndWriteInfoSection();
404 errorContext = "BeginWriteCommentSection";
405 theDriver->BeginWriteCommentSection();
406 errorContext = "WriteComment";
407 theDriver->WriteComment(aData->Comments());
408 errorContext = "EndWriteCommentSection";
409 theDriver->EndWriteCommentSection();
411 Handle(TColStd_HSequenceOfAsciiString) tlist;
413 tlist = aData->Types();
415 errorContext = "BeginWriteTypeSection";
416 theDriver->BeginWriteTypeSection();
417 len = aData->NumberOfTypes();
419 Handle(Storage_HArrayOfCallBack) WFunc = new Storage_HArrayOfCallBack(1,len);
421 theDriver->SetTypeSectionSize(len);
423 Storage_DataMapIteratorOfMapOfCallBack cbit(iData->myTypeBinding);
424 Handle(Storage_TypedCallBack) atcallBack;
426 for (; cbit.More(); cbit.Next()) {
427 atcallBack = cbit.Value();
428 WFunc->SetValue(atcallBack->Index(),atcallBack->CallBack());
431 errorContext = "WriteTypeInformations";
432 for (i = 1; i <= len; i++) {
433 theDriver->WriteTypeInformations(i,tlist->Value(i).ToCString());
436 errorContext = "EndWriteTypeSection";
437 theDriver->EndWriteTypeSection();
439 errorContext = "BeginWriteRootSection";
440 theDriver->BeginWriteRootSection();
441 theDriver->SetRootSectionSize(plist->Length());
443 errorContext = "WriteRoot";
444 for (i = 1; i <= plist->Length(); i++) {
445 theDriver->WriteRoot(plist->Value(i)->Name(),i,"PDocStd_Document");
448 errorContext = "EndWriteRootSection";
449 theDriver->EndWriteRootSection();
451 errorContext = "BeginWriteRefSection";
452 theDriver->BeginWriteRefSection();
453 theDriver->SetRefSectionSize(iData->myObjId - 1);
454 errorContext = "WriteReferenceType";
456 Storage_BucketIterator bit(&iData->myPtoA);
460 if (!p.IsNull()) theDriver->WriteReferenceType(p->_refnum,p->_typenum);
464 errorContext = "EndWriteRefSection";
465 theDriver->EndWriteRefSection();
467 errorContext = "BeginWriteDataSection";
468 theDriver->BeginWriteDataSection();
470 Handle(Storage_Schema) me = this;
472 errorContext = "Write";
479 WFunc->Value(p->_typenum)->Write(p, theDriver, me);
485 errorContext = "EndWriteDataSection";
486 theDriver->EndWriteDataSection();
488 catch(Storage_StreamWriteError const&) {
489 aData->SetErrorStatus(Storage_VSWriteError);
490 aData->SetErrorStatusExtension(errorContext);
494 aData->SetErrorStatus(Storage_VSModeError);
495 aData->SetErrorStatusExtension("OpenMode");
502 //=======================================================================
503 //function : AddReadUnknownTypeCallBack
504 //purpose : add two functions to the callback list
505 //=======================================================================
507 void Storage_Schema::AddReadUnknownTypeCallBack
508 (const TCollection_AsciiString& aTypeName,
509 const Handle(Storage_CallBack)& aCallBack)
511 if (!aCallBack.IsNull()) {
512 Handle(Storage_TypedCallBack) aTCallBack = new Storage_TypedCallBack(aTypeName,aCallBack);
514 myCallBack.Bind(aTypeName,aTCallBack);
518 //=======================================================================
519 //function : RemoveReadUnknownTypeCallBack
520 //purpose : remove a callback for a type
521 //=======================================================================
523 void Storage_Schema::RemoveReadUnknownTypeCallBack
524 (const TCollection_AsciiString& aTypeName)
526 if (myCallBack.IsBound(aTypeName)) {
527 myCallBack.UnBind(aTypeName);
531 //=======================================================================
532 //function : InstalledCallBackList
533 //purpose : returns a list of type name with installed
535 //=======================================================================
537 Handle(TColStd_HSequenceOfAsciiString) Storage_Schema::
538 InstalledCallBackList() const
540 Storage_DataMapIteratorOfMapOfCallBack it(myCallBack);
541 Handle(TColStd_HSequenceOfAsciiString) result = new TColStd_HSequenceOfAsciiString;
543 for (; it.More(); it.Next()) {
544 result->Append(it.Key());
550 //=======================================================================
551 //function : ClearCallBackList
552 //purpose : clear all callback from schema instance.
553 //=======================================================================
555 void Storage_Schema::ClearCallBackList()
560 //=======================================================================
561 //function : UseDefaultCallBack
562 //purpose : install a callback for all unknown type. the
563 // objects with unknown types will be skipped. (look
564 // SkipObject method in BaseDriver)
565 //=======================================================================
567 void Storage_Schema::UseDefaultCallBack()
569 myCallBackState = Standard_True;
572 //=======================================================================
573 //function : DontUseDefaultCallBack
574 //purpose : tells schema to uninstall the default callback.
575 //=======================================================================
577 void Storage_Schema::DontUseDefaultCallBack()
579 myCallBackState = Standard_False;
582 //=======================================================================
583 //function : IsUsingDefaultCallBack
584 //purpose : ask if the schema is using the default callback.
585 //=======================================================================
587 Standard_Boolean Storage_Schema::IsUsingDefaultCallBack() const
589 return myCallBackState;
592 //=======================================================================
593 //function : SetDefaultCallBack
594 //purpose : overload the default function for build.(use to
595 // set an error message or skip an object while
596 // reading an unknown type).
597 //=======================================================================
599 void Storage_Schema::SetDefaultCallBack(const Handle(Storage_CallBack)& f)
601 myDefaultCallBack = f;
604 //=======================================================================
605 //function : ResetDefaultCallBack
606 //purpose : reset the default function defined by Storage
608 //=======================================================================
610 void Storage_Schema::ResetDefaultCallBack()
612 myDefaultCallBack = new Storage_DefaultCallBack;
615 //=======================================================================
616 //function : DefaultCallBack
617 //purpose : returns the read function used when the
618 // UseDefaultCallBack() is set.
619 //=======================================================================
621 Handle(Storage_CallBack) Storage_Schema::DefaultCallBack() const
623 return myDefaultCallBack;
626 //=======================================================================
627 //function : BindType
629 //=======================================================================
631 void Storage_Schema::BindType
632 (const TCollection_AsciiString& aTypeName,
633 const Handle(Storage_CallBack)& aCallBack) const
635 if (!HasTypeBinding(aTypeName)) {
636 Handle(Storage_InternalData) iData = Storage_Schema::ICurrentData()->InternalData();
637 Handle(Storage_TypeData) tData = Storage_Schema::ICurrentData()->TypeData();
638 Handle(Storage_TypedCallBack) c = new Storage_TypedCallBack(aTypeName,aCallBack);
640 tData->AddType(aTypeName,iData->myTypeId);
641 c->SetIndex(iData->myTypeId++);
642 iData->myTypeBinding.Bind(aTypeName,c);
646 //=======================================================================
647 //function : TypeBinding
649 //=======================================================================
651 Handle(Storage_CallBack) Storage_Schema::TypeBinding
652 (const TCollection_AsciiString& aTypeName) const
654 Handle(Storage_CallBack) result;
656 if (HasTypeBinding(aTypeName)) {
657 Handle(Storage_InternalData) iData = Storage_Schema::ICurrentData()->InternalData();
659 result = iData->myTypeBinding.Find(aTypeName)->CallBack();
665 //=======================================================================
666 //function : AddPersistent
668 //=======================================================================
670 Standard_Boolean Storage_Schema::AddPersistent
671 (const Handle(Standard_Persistent)& sp,
672 const Standard_CString tName) const
674 Standard_Boolean result = Standard_False;
677 Handle(Storage_InternalData) iData = Storage_Schema::ICurrentData()->InternalData();
679 if (sp->_typenum == 0) {
680 Standard_Integer aTypenum;
681 static TCollection_AsciiString aTypeName;
683 Handle(Storage_TypeData) tData = Storage_Schema::ICurrentData()->TypeData();
685 aTypenum = iData->myTypeBinding.Find(aTypeName)->Index();
687 sp->_typenum = aTypenum;
688 sp->_refnum = iData->myObjId++;
690 result = Standard_True;
697 //=======================================================================
698 //function : PersistentToAdd
700 //=======================================================================
702 Standard_Boolean Storage_Schema::PersistentToAdd
703 (const Handle(Standard_Persistent)& sp) const
705 Standard_Boolean result = Standard_False;
708 Handle(Storage_InternalData) di = Storage_Schema::ICurrentData()->InternalData();
710 if (sp->_typenum == 0 && sp->_refnum != -1) {
711 result = Standard_True;
713 di->myPtoA.Append(sp);
720 //=======================================================================
723 //=======================================================================
725 void Storage_Schema::Clear() const
727 Storage_Schema::ICurrentData().Nullify();
730 #ifdef DATATYPE_MIGRATION
731 //=======================================================================
732 // environment variable CSF_MIGRATION_TYPES should define full path of a file
733 // containing migration types table: oldtype - newtype
734 //=======================================================================
735 Standard_Boolean Storage_Schema::CheckTypeMigration(
736 const TCollection_AsciiString& oldName,
737 TCollection_AsciiString& newName)
739 static Standard_Boolean isChecked(Standard_False);
740 static DataMapOfAStringAString aDMap;
741 Standard_Boolean aMigration(Standard_False);
744 isChecked = Standard_True;
745 // TCollection_AsciiString aFileName = getenv("CSF_MIGRATION_TYPES");
746 OSD_Environment csf(TCollection_AsciiString("CSF_MIGRATION_TYPES"));
747 TCollection_AsciiString aFileName = csf.Value();
748 if(aFileName.Length() > 0) {
749 OSD_Path aPath(aFileName,OSD_Default);
751 aFile.SetPath(aPath);
753 OSD_Protection aProt(OSD_R,OSD_R,OSD_R,OSD_R);
754 aFile.Open(OSD_ReadOnly, aProt);
755 if(aFile.IsOpen() && aFile.IsReadable()) {
756 TCollection_AsciiString aLine;
757 Standard_Integer aNbReaded(0);
759 aFile.ReadLine(aLine, 80, aNbReaded);
760 if(aFile.IsAtEnd() || !aNbReaded) {
765 std::cout << "Storage_Sheme:: Line: = " << aLine <<std::endl;
767 TCollection_AsciiString aKey, aValue;
768 aKey = aLine.Token();
769 aValue = aLine.Token(" \t\n\r", 2);
770 aDMap.Bind(aKey, aValue);
776 // hard-code migration table for known types
777 aDMap.Bind("TDataStd_Shape", "TDataXtd_Shape");
778 aDMap.Bind("TDataStd_Constraint", "TDataXtd_Constraint");
779 aDMap.Bind("TDataStd_Geometry", "TDataXtd_Geometry");
780 aDMap.Bind("TDataStd_Axis", "TDataXtd_Axis");
781 aDMap.Bind("TDataStd_Point", "TDataXtd_Point");
782 aDMap.Bind("TDataStd_Plane", "TDataXtd_Plane");
783 aDMap.Bind("TDataStd_Position", "TDataXtd_Position");
784 aDMap.Bind("TDataStd_Placement", "TDataXtd_Placement");
785 aDMap.Bind("TDataStd_PatternStd", "TDataXtd_PatternStd");
786 aDMap.Bind("TPrsStd_AISPresentation", "TDataXtd_Presentation");
789 std::cout << "Storage_Sheme:: aDataMap.Size = " << aDMap.Extent() << std::endl;
795 if(aDMap.IsBound(oldName)) {
797 newName = aDMap.Find(oldName);
798 aMigration = Standard_True;
800 std::cout << " newName = " << newName << std::endl;
808 //=======================================================================
809 //function : ISetCurrentData
811 //=======================================================================
813 void Storage_Schema::ISetCurrentData(const Handle(Storage_Data)& dData)
815 Storage_Schema::ICurrentData() = dData;
818 //=======================================================================
819 //function : ICurrentData
821 //=======================================================================
823 Handle(Storage_Data)& Storage_Schema::ICurrentData()
825 static Handle(Storage_Data) _Storage_CData;
826 return _Storage_CData;
831 //=======================================================================
832 //function : ICreationDate
834 //=======================================================================
836 TCollection_AsciiString Storage_Schema::ICreationDate()
838 char nowstr[SLENGTH];
840 struct tm *nowstruct;
841 if (time(&nowbin) == (time_t)-1)
844 std::cerr << "Storage ERROR : Could not get time of day from time()" << std::endl;
848 nowstruct = localtime(&nowbin);
850 if (strftime(nowstr, SLENGTH, "%m/%d/%Y", nowstruct) == (size_t) 0)
853 std::cerr << "Storage ERROR : Could not get string from strftime()" << std::endl;
857 TCollection_AsciiString t(nowstr);