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)
209 if (aBucketManager) {
210 myBucket = aBucketManager;
211 myCurrentBucket = myBucket->myBuckets[0];
212 myBucketNumber = aBucketManager->myNumberOfBucket;
213 myCurrentBucketIndex = 0;
215 myMoreObject = Standard_True;
217 else myMoreObject = Standard_False;
220 //=======================================================================
223 //=======================================================================
225 void Storage_BucketIterator::Reset()
228 myCurrentBucket = myBucket->myBuckets[0];
229 myBucketNumber = myBucket->myNumberOfBucket;
231 myCurrentBucketIndex = 0;
232 myMoreObject = Standard_True;
234 else myMoreObject = Standard_False;
237 //=======================================================================
240 //=======================================================================
242 void Storage_BucketIterator::Init(Storage_BucketOfPersistent* aBucketManager)
244 if (aBucketManager) {
245 myBucket = aBucketManager;
246 myCurrentBucket = myBucket->myBuckets[0];
247 myBucketNumber = aBucketManager->myNumberOfBucket;
249 myCurrentBucketIndex = 0;
250 myMoreObject = Standard_True;
252 else myMoreObject = Standard_False;
255 //=======================================================================
258 //=======================================================================
260 void Storage_BucketIterator::Next()
262 if (!myMoreObject) return;
264 if (myCurrentIndex < myCurrentBucket->myCurrentSpace) {
269 myCurrentBucketIndex++;
270 if (myCurrentBucketIndex < myBucketNumber) {
271 myCurrentBucket = myBucket->myBuckets[myCurrentBucketIndex];
274 myMoreObject = Standard_False;
279 //=======================================================================
280 //function : Storage_Schema
281 //purpose : USER API -- --------------------------------------------------------------
282 // IMPLEMENTATION BucketOfPersistent
283 //=======================================================================
285 Storage_Schema::Storage_Schema()
288 ResetDefaultCallBack();
289 myCallBackState = Standard_False;
292 //=======================================================================
293 //function : SetVersion
294 //purpose : returns version of the schema
295 //=======================================================================
297 void Storage_Schema::SetVersion(const TCollection_AsciiString& aVersion)
299 myVersion = aVersion;
302 //=======================================================================
304 //purpose : returns the version of the schema
305 //=======================================================================
307 TCollection_AsciiString Storage_Schema::Version() const
312 //=======================================================================
314 //purpose : set the schema's name
315 //=======================================================================
317 void Storage_Schema::SetName(const TCollection_AsciiString& aSchemaName)
319 myName = aSchemaName;
322 //=======================================================================
324 //purpose : returns the schema's name
325 //=======================================================================
327 TCollection_AsciiString Storage_Schema::Name() const
332 //=======================================================================
336 // s: driver to write
337 // raises if the stream is not opened in VSWrite or
339 //=======================================================================
341 void Storage_Schema::Write
342 (Storage_BaseDriver& f,
343 const Handle(Storage_Data)& aData) const
345 if (aData.IsNull()) return;
347 // add all the persistent to write...
349 Standard_Integer posfrom,posto;
350 Handle(Standard_Persistent) p;
351 Handle(Storage_HSeqOfRoot) plist;
352 TCollection_AsciiString errorContext("AddPersistent");
353 Storage_Schema::ISetCurrentData(aData);
355 Handle(Storage_InternalData) iData = aData->InternalData();
358 aData->ClearErrorStatus();
360 plist = aData->Roots();
362 for (posto = 1; posto <= plist->Length(); posto++) {
363 PersistentToAdd(plist->Value(posto)->Object());
366 for (posto = 1; posto <= plist->Length(); posto++) {
367 // AddTypeSelection(plist->Value(posto)->Object());
370 for (posfrom = plist->Length() + 1; posfrom <= iData->myPtoA.Length(); posfrom++) {
371 // AddTypeSelection(iData->myPtoA.Value(posfrom));
374 // ...and now we write
379 aData->HeaderData()->SetCreationDate(ICreationDate());
380 aData->HeaderData()->SetStorageVersion(Storage::Version());
381 aData->HeaderData()->SetNumberOfObjects(iData->myPtoA.Length());
382 aData->HeaderData()->SetSchemaName(myName);
383 aData->HeaderData()->SetSchemaVersion(myVersion);
385 if ((f.OpenMode() == Storage_VSWrite) || (f.OpenMode() == Storage_VSReadWrite)) {
388 errorContext = "BeginWriteInfoSection";
389 f.BeginWriteInfoSection();
390 errorContext = "WriteInfo";
391 f.WriteInfo(aData->NumberOfObjects(),
392 aData->StorageVersion(),
393 aData->CreationDate(),
395 aData->SchemaVersion(),
396 aData->ApplicationName(),
397 aData->ApplicationVersion(),
400 errorContext = "EndWriteInfoSection";
401 f.EndWriteInfoSection();
403 errorContext = "BeginWriteCommentSection";
404 f.BeginWriteCommentSection();
405 errorContext = "WriteComment";
406 f.WriteComment(aData->Comments());
407 errorContext = "EndWriteCommentSection";
408 f.EndWriteCommentSection();
410 Handle(TColStd_HSequenceOfAsciiString) tlist;
412 tlist = aData->Types();
414 errorContext = "BeginWriteTypeSection";
415 f.BeginWriteTypeSection();
416 len = aData->NumberOfTypes();
418 Handle(Storage_HArrayOfCallBack) WFunc = new Storage_HArrayOfCallBack(1,len);
420 f.SetTypeSectionSize(len);
422 Storage_DataMapIteratorOfMapOfCallBack cbit(iData->myTypeBinding);
423 Handle(Storage_TypedCallBack) atcallBack;
425 for (; cbit.More(); cbit.Next()) {
426 atcallBack = cbit.Value();
427 WFunc->SetValue(atcallBack->Index(),atcallBack->CallBack());
430 errorContext = "WriteTypeInformations";
431 for (i = 1; i <= len; i++) {
432 f.WriteTypeInformations(i,tlist->Value(i).ToCString());
435 errorContext = "EndWriteTypeSection";
436 f.EndWriteTypeSection();
438 errorContext = "BeginWriteRootSection";
439 f.BeginWriteRootSection();
440 f.SetRootSectionSize(plist->Length());
442 errorContext = "WriteRoot";
443 for (i = 1; i <= plist->Length(); i++) {
444 f.WriteRoot(plist->Value(i)->Name(),i,"PDocStd_Document");
447 errorContext = "EndWriteRootSection";
448 f.EndWriteRootSection();
450 errorContext = "BeginWriteRefSection";
451 f.BeginWriteRefSection();
452 f.SetRefSectionSize(iData->myObjId - 1);
453 errorContext = "WriteReferenceType";
455 Storage_BucketIterator bit(&iData->myPtoA);
459 if (!p.IsNull()) f.WriteReferenceType(p->_refnum,p->_typenum);
463 errorContext = "EndWriteRefSection";
464 f.EndWriteRefSection();
466 errorContext = "BeginWriteDataSection";
467 f.BeginWriteDataSection();
469 Handle(Storage_Schema) me = this;
471 errorContext = "Write";
478 WFunc->Value(p->_typenum)->Write(p,f,me);
484 errorContext = "EndWriteDataSection";
485 f.EndWriteDataSection();
487 catch(Storage_StreamWriteError const&) {
488 aData->SetErrorStatus(Storage_VSWriteError);
489 aData->SetErrorStatusExtension(errorContext);
493 aData->SetErrorStatus(Storage_VSModeError);
494 aData->SetErrorStatusExtension("OpenMode");
501 //=======================================================================
502 //function : AddReadUnknownTypeCallBack
503 //purpose : add two functions to the callback list
504 //=======================================================================
506 void Storage_Schema::AddReadUnknownTypeCallBack
507 (const TCollection_AsciiString& aTypeName,
508 const Handle(Storage_CallBack)& aCallBack)
510 if (!aCallBack.IsNull()) {
511 Handle(Storage_TypedCallBack) aTCallBack = new Storage_TypedCallBack(aTypeName,aCallBack);
513 myCallBack.Bind(aTypeName,aTCallBack);
517 //=======================================================================
518 //function : RemoveReadUnknownTypeCallBack
519 //purpose : remove a callback for a type
520 //=======================================================================
522 void Storage_Schema::RemoveReadUnknownTypeCallBack
523 (const TCollection_AsciiString& aTypeName)
525 if (myCallBack.IsBound(aTypeName)) {
526 myCallBack.UnBind(aTypeName);
530 //=======================================================================
531 //function : InstalledCallBackList
532 //purpose : returns a list of type name with installed
534 //=======================================================================
536 Handle(TColStd_HSequenceOfAsciiString) Storage_Schema::
537 InstalledCallBackList() const
539 Storage_DataMapIteratorOfMapOfCallBack it(myCallBack);
540 Handle(TColStd_HSequenceOfAsciiString) result = new TColStd_HSequenceOfAsciiString;
542 for (; it.More(); it.Next()) {
543 result->Append(it.Key());
549 //=======================================================================
550 //function : ClearCallBackList
551 //purpose : clear all callback from schema instance.
552 //=======================================================================
554 void Storage_Schema::ClearCallBackList()
559 //=======================================================================
560 //function : UseDefaultCallBack
561 //purpose : install a callback for all unknown type. the
562 // objects with unknown types will be skipped. (look
563 // SkipObject method in BaseDriver)
564 //=======================================================================
566 void Storage_Schema::UseDefaultCallBack()
568 myCallBackState = Standard_True;
571 //=======================================================================
572 //function : DontUseDefaultCallBack
573 //purpose : tells schema to uninstall the default callback.
574 //=======================================================================
576 void Storage_Schema::DontUseDefaultCallBack()
578 myCallBackState = Standard_False;
581 //=======================================================================
582 //function : IsUsingDefaultCallBack
583 //purpose : ask if the schema is using the default callback.
584 //=======================================================================
586 Standard_Boolean Storage_Schema::IsUsingDefaultCallBack() const
588 return myCallBackState;
591 //=======================================================================
592 //function : SetDefaultCallBack
593 //purpose : overload the default function for build.(use to
594 // set an error message or skip an object while
595 // reading an unknown type).
596 //=======================================================================
598 void Storage_Schema::SetDefaultCallBack(const Handle(Storage_CallBack)& f)
600 myDefaultCallBack = f;
603 //=======================================================================
604 //function : ResetDefaultCallBack
605 //purpose : reset the default function defined by Storage
607 //=======================================================================
609 void Storage_Schema::ResetDefaultCallBack()
611 myDefaultCallBack = new Storage_DefaultCallBack;
614 //=======================================================================
615 //function : DefaultCallBack
616 //purpose : returns the read function used when the
617 // UseDefaultCallBack() is set.
618 //=======================================================================
620 Handle(Storage_CallBack) Storage_Schema::DefaultCallBack() const
622 return myDefaultCallBack;
625 //=======================================================================
626 //function : BindType
628 //=======================================================================
630 void Storage_Schema::BindType
631 (const TCollection_AsciiString& aTypeName,
632 const Handle(Storage_CallBack)& aCallBack) const
634 if (!HasTypeBinding(aTypeName)) {
635 Handle(Storage_InternalData) iData = Storage_Schema::ICurrentData()->InternalData();
636 Handle(Storage_TypeData) tData = Storage_Schema::ICurrentData()->TypeData();
637 Handle(Storage_TypedCallBack) c = new Storage_TypedCallBack(aTypeName,aCallBack);
639 tData->AddType(aTypeName,iData->myTypeId);
640 c->SetIndex(iData->myTypeId++);
641 iData->myTypeBinding.Bind(aTypeName,c);
645 //=======================================================================
646 //function : TypeBinding
648 //=======================================================================
650 Handle(Storage_CallBack) Storage_Schema::TypeBinding
651 (const TCollection_AsciiString& aTypeName) const
653 Handle(Storage_CallBack) result;
655 if (HasTypeBinding(aTypeName)) {
656 Handle(Storage_InternalData) iData = Storage_Schema::ICurrentData()->InternalData();
658 result = iData->myTypeBinding.Find(aTypeName)->CallBack();
664 //=======================================================================
665 //function : AddPersistent
667 //=======================================================================
669 Standard_Boolean Storage_Schema::AddPersistent
670 (const Handle(Standard_Persistent)& sp,
671 const Standard_CString tName) const
673 Standard_Boolean result = Standard_False;
676 Handle(Storage_InternalData) iData = Storage_Schema::ICurrentData()->InternalData();
678 if (sp->_typenum == 0) {
679 Standard_Integer aTypenum;
680 static TCollection_AsciiString aTypeName;
682 Handle(Storage_TypeData) tData = Storage_Schema::ICurrentData()->TypeData();
684 aTypenum = iData->myTypeBinding.Find(aTypeName)->Index();
686 sp->_typenum = aTypenum;
687 sp->_refnum = iData->myObjId++;
689 result = Standard_True;
696 //=======================================================================
697 //function : PersistentToAdd
699 //=======================================================================
701 Standard_Boolean Storage_Schema::PersistentToAdd
702 (const Handle(Standard_Persistent)& sp) const
704 Standard_Boolean result = Standard_False;
707 Handle(Storage_InternalData) di = Storage_Schema::ICurrentData()->InternalData();
709 if (sp->_typenum == 0 && sp->_refnum != -1) {
710 result = Standard_True;
712 di->myPtoA.Append(sp);
719 //=======================================================================
722 //=======================================================================
724 void Storage_Schema::Clear() const
726 Storage_Schema::ICurrentData().Nullify();
729 #ifdef DATATYPE_MIGRATION
730 //=======================================================================
731 // environment variable CSF_MIGRATION_TYPES should define full path of a file
732 // containing migration types table: oldtype - newtype
733 //=======================================================================
734 Standard_Boolean Storage_Schema::CheckTypeMigration(
735 const TCollection_AsciiString& oldName,
736 TCollection_AsciiString& newName)
738 static Standard_Boolean isChecked(Standard_False);
739 static DataMapOfAStringAString aDMap;
740 Standard_Boolean aMigration(Standard_False);
743 isChecked = Standard_True;
744 // TCollection_AsciiString aFileName = getenv("CSF_MIGRATION_TYPES");
745 OSD_Environment csf(TCollection_AsciiString("CSF_MIGRATION_TYPES"));
746 TCollection_AsciiString aFileName = csf.Value();
747 if(aFileName.Length() > 0) {
748 OSD_Path aPath(aFileName,OSD_Default);
750 aFile.SetPath(aPath);
752 OSD_Protection aProt(OSD_R,OSD_R,OSD_R,OSD_R);
753 aFile.Open(OSD_ReadOnly, aProt);
754 if(aFile.IsOpen() && aFile.IsReadable()) {
755 TCollection_AsciiString aLine;
756 Standard_Integer aNbReaded(0);
758 aFile.ReadLine(aLine, 80, aNbReaded);
759 if(aFile.IsAtEnd() || !aNbReaded) {
764 cout << "Storage_Sheme:: Line: = " << aLine <<endl;
766 TCollection_AsciiString aKey, aValue;
767 aKey = aLine.Token();
768 aValue = aLine.Token(" \t\n\r", 2);
769 aDMap.Bind(aKey, aValue);
775 // hard-code migration table for known types
776 aDMap.Bind("TDataStd_Shape", "TDataXtd_Shape");
777 aDMap.Bind("TDataStd_Constraint", "TDataXtd_Constraint");
778 aDMap.Bind("TDataStd_Geometry", "TDataXtd_Geometry");
779 aDMap.Bind("TDataStd_Axis", "TDataXtd_Axis");
780 aDMap.Bind("TDataStd_Point", "TDataXtd_Point");
781 aDMap.Bind("TDataStd_Plane", "TDataXtd_Plane");
782 aDMap.Bind("TDataStd_Position", "TDataXtd_Position");
783 aDMap.Bind("TDataStd_Placement", "TDataXtd_Placement");
784 aDMap.Bind("TDataStd_PatternStd", "TDataXtd_PatternStd");
785 aDMap.Bind("TPrsStd_AISPresentation", "TDataXtd_Presentation");
788 cout << "Storage_Sheme:: aDataMap.Size = " << aDMap.Extent() << endl;
794 if(aDMap.IsBound(oldName)) {
796 newName = aDMap.Find(oldName);
797 aMigration = Standard_True;
799 cout << " newName = " << newName << endl;
807 //=======================================================================
808 //function : ISetCurrentData
810 //=======================================================================
812 void Storage_Schema::ISetCurrentData(const Handle(Storage_Data)& dData)
814 Storage_Schema::ICurrentData() = dData;
817 //=======================================================================
818 //function : ICurrentData
820 //=======================================================================
822 Handle(Storage_Data)& Storage_Schema::ICurrentData()
824 static Handle(Storage_Data) _Storage_CData;
825 return _Storage_CData;
830 //=======================================================================
831 //function : ICreationDate
833 //=======================================================================
835 TCollection_AsciiString Storage_Schema::ICreationDate()
837 char nowstr[SLENGTH];
839 struct tm *nowstruct;
840 if (time(&nowbin) == (time_t)-1)
843 cerr << "Storage ERROR : Could not get time of day from time()" << endl;
847 nowstruct = localtime(&nowbin);
849 if (strftime(nowstr, SLENGTH, "%m/%d/%Y", nowstruct) == (size_t) 0)
852 cerr << "Storage ERROR : Could not get string from strftime()" << endl;
856 TCollection_AsciiString t(nowstr);