d93e00d1c5e59082bf46e06ca8d92f74d2ce2f6d
[occt.git] / src / StdLDrivers / StdLDrivers_DocumentRetrievalDriver.cxx
1 // Copyright (c) 2015 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 #include <StdLDrivers_DocumentRetrievalDriver.hxx>
15 #include <StdLDrivers.hxx>
16 #include <StdLPersistent_PDocStd_Document.hxx>
17
18 #include <StdObjMgt_MapOfInstantiators.hxx>
19 #include <StdObjMgt_ReadData.hxx>
20
21 #include <Storage_HeaderData.hxx>
22 #include <Storage_TypeData.hxx>
23 #include <Storage_RootData.hxx>
24 #include <Storage_BaseDriver.hxx>
25 #include <Storage_StreamTypeMismatchError.hxx>
26 #include <Storage_StreamFormatError.hxx>
27 #include <Storage_StreamReadError.hxx>
28
29 #include <PCDM.hxx>
30 #include <PCDM_ReadWriter.hxx>
31
32 #include <Standard_ErrorHandler.hxx>
33 #include <NCollection_Array1.hxx>
34 #include <TDocStd_Document.hxx>
35
36 IMPLEMENT_STANDARD_RTTIEXT (StdLDrivers_DocumentRetrievalDriver, PCDM_RetrievalDriver)
37
38 //=======================================================================
39 //function : CreateDocument
40 //purpose  : Create an empty TDocStd_Document
41 //=======================================================================
42 Handle(CDM_Document) StdLDrivers_DocumentRetrievalDriver::CreateDocument()
43 {
44   return new TDocStd_Document (PCDM_RetrievalDriver::GetFormat());
45 }
46
47 //=======================================================================
48 //function : Read
49 //purpose  : Retrieve the content of a file into a new document
50 //=======================================================================
51 void StdLDrivers_DocumentRetrievalDriver::Read (const TCollection_ExtendedString& theFileName,
52                                                 const Handle(CDM_Document)&       theNewDocument,
53                                                 const Handle(CDM_Application)&)
54 {
55   Standard_Integer i;
56
57   // Create a driver appropriate for the given file
58   PCDM_BaseDriverPointer aFileDriver;
59   if (PCDM::FileDriverType (TCollection_AsciiString (theFileName), aFileDriver) == PCDM_TOFD_Unknown)
60   {
61     myReaderStatus = PCDM_RS_UnknownFileDriver;
62     return;
63   }
64
65   // Try to open the file
66   {
67     Standard_SStream aMsg;
68     try
69     {
70       OCC_CATCH_SIGNALS
71       PCDM_ReadWriter::Open (*aFileDriver, theFileName, Storage_VSRead);
72       myReaderStatus = PCDM_RS_OK;
73     } 
74     catch (Standard_Failure)
75     {
76       aMsg << Standard_Failure::Caught() << endl;
77       myReaderStatus = PCDM_RS_OpenError;
78     }
79
80     if (myReaderStatus != PCDM_RS_OK)
81     {
82       Standard_Failure::Raise (aMsg);
83       return;
84     }
85   }
86   
87   // Read header section
88   Storage_HeaderData hData;
89   if (!hData.Read (*aFileDriver))
90   {
91     RaiseOnStorageError (hData.ErrorStatus());
92     return;
93   }
94
95   // Read type section
96   Storage_TypeData tData;
97   if (!tData.Read (*aFileDriver))
98   {
99     RaiseOnStorageError (tData.ErrorStatus());
100     return;
101   }
102
103   // Read root section
104   Storage_RootData rData;
105   if (!rData.Read (*aFileDriver))
106   {
107     RaiseOnStorageError (rData.ErrorStatus());
108     return;
109   }
110
111   if (rData.NumberOfRoots() < 1)
112   {
113     myReaderStatus = PCDM_RS_NoDocument;
114
115     Standard_SStream aMsg;
116     aMsg << "could not find any document in this file" << endl;
117     Standard_Failure::Raise (aMsg);
118
119     return;
120   }
121
122   // Select instantiators for the used types
123   NCollection_Array1<StdObjMgt_Persistent::Instantiator>
124     anInstantiators (1, tData.NumberOfTypes());
125   {
126     StdObjMgt_MapOfInstantiators aMapOfInstantiators;
127     BindTypes (aMapOfInstantiators);
128
129     TColStd_SequenceOfAsciiString anUnknownTypes;
130     Standard_Integer        aCurTypeNum;
131     TCollection_AsciiString aCurTypeName;
132
133     for (i = 1; i <= tData.NumberOfTypes(); i++)
134     {
135       aCurTypeName = tData.Type (i);
136       aCurTypeNum  = tData.Type (aCurTypeName);
137
138       StdObjMgt_Persistent::Instantiator anInstantiator;
139       if (aMapOfInstantiators.Find (aCurTypeName, anInstantiator))
140         anInstantiators (aCurTypeNum) = anInstantiator;
141       else
142         anUnknownTypes.Append (aCurTypeName);
143     }
144
145     if (!anUnknownTypes.IsEmpty())
146     {
147       myReaderStatus = PCDM_RS_TypeNotFoundInSchema;
148
149       Standard_SStream aMsg;
150       aMsg << "cannot read: `" << theFileName
151             << "' because it contains the following unknown types: ";
152       for (i = 1; i <= anUnknownTypes.Length(); i++)
153       {
154         aMsg << anUnknownTypes(i);
155         if (i < anUnknownTypes.Length()) aMsg << ",";
156         else                             aMsg << endl;
157       }
158
159       Standard_Failure::Raise (aMsg);
160       return;
161     }
162   }
163
164   // Read and parse reference section
165   StdObjMgt_ReadData aReadData (*aFileDriver, hData.NumberOfObjects());
166
167   if (RaiseOnStorageError (aFileDriver->BeginReadRefSection()))
168     return;
169
170   Standard_Integer len = aFileDriver->RefSectionSize();
171   for (i = 1; i <= len; i++)
172   {
173     Standard_Integer aRef = 0, aType = 0;
174     Storage_Error anError;
175     try
176     {
177       OCC_CATCH_SIGNALS
178       aFileDriver->ReadReferenceType (aRef, aType);
179       anError = Storage_VSOk;
180     }
181     catch (Storage_StreamTypeMismatchError)
182     {
183       anError = Storage_VSTypeMismatch;
184     }
185
186     if (RaiseOnStorageError (anError))
187       return;
188
189     aReadData.CreateObject (aRef, anInstantiators (aType));
190   }
191
192   if (RaiseOnStorageError (aFileDriver->EndReadRefSection()))
193     return;
194
195   // Read and parse data section
196   if (RaiseOnStorageError (aFileDriver->BeginReadDataSection()))
197     return;
198
199   for (i = 1; i <= hData.NumberOfObjects(); i++)
200   {
201     Handle(StdObjMgt_Persistent) aPersistent = aReadData.Object (i);
202     if (!aPersistent.IsNull())
203     {
204       Standard_Integer aRef = 0, aType = 0;
205       Storage_Error anError;
206       try
207       {
208         OCC_CATCH_SIGNALS
209         aFileDriver->ReadPersistentObjectHeader (aRef, aType);
210         aFileDriver->BeginReadPersistentObjectData();
211         aPersistent->Read (aReadData);
212         aFileDriver->EndReadPersistentObjectData();
213         anError = Storage_VSOk;
214       }
215       catch (Storage_StreamTypeMismatchError) { anError = Storage_VSTypeMismatch; }
216       catch (Storage_StreamFormatError      ) { anError = Storage_VSFormatError;  }
217       catch (Storage_StreamReadError        ) { anError = Storage_VSFormatError;  }
218
219       if (RaiseOnStorageError (anError))
220         return;
221     }
222   }
223
224   if (RaiseOnStorageError (aFileDriver->EndReadDataSection()))
225     return;
226
227   // Close the file
228   aFileDriver->Close();
229   delete aFileDriver;
230
231   // Initialize transient document using the root object and comments
232   Handle(Storage_HSeqOfRoot) aRoots = rData.Roots();
233
234   Handle(Storage_Root) aFirstRoot = aRoots->First();
235
236   Handle(StdObjMgt_Persistent) aFirstRootObject =
237     aReadData.Object (aFirstRoot->Reference());
238
239   Handle(StdLPersistent_PDocStd_Document) aPDocument =
240     Handle(StdLPersistent_PDocStd_Document)::DownCast (aFirstRootObject);
241
242   if (!aPDocument.IsNull())
243     aPDocument->Import (theNewDocument);
244
245   theNewDocument->SetComments (hData.Comments());
246 }
247
248 //=======================================================================
249 //function : RaiseOnStorageError
250 //purpose  : Update the reader status and raise an exception
251 //           appropriate for the given storage error
252 //=======================================================================
253 Standard_Boolean StdLDrivers_DocumentRetrievalDriver::RaiseOnStorageError (Storage_Error theError)
254 {
255   Standard_SStream aMsg;
256
257   switch (theError)
258   {
259   case Storage_VSOk:
260     return Standard_False;
261
262   case Storage_VSOpenError:
263   case Storage_VSNotOpen:
264   case Storage_VSAlreadyOpen:
265     myReaderStatus = PCDM_RS_OpenError;
266     aMsg << "Stream Open Error" << endl;
267     break;
268
269   case Storage_VSModeError:
270     myReaderStatus = PCDM_RS_WrongStreamMode;
271     aMsg << "Stream is opened with a wrong mode for operation" << endl;
272     break;
273
274   case Storage_VSSectionNotFound:
275     myReaderStatus = PCDM_RS_FormatFailure;
276     aMsg << "Section is not found" << endl;
277     break;
278
279   case Storage_VSFormatError:
280     myReaderStatus = PCDM_RS_FormatFailure;
281     aMsg << "Wrong format error" << endl;
282     break;
283
284   case Storage_VSUnknownType:
285     myReaderStatus = PCDM_RS_TypeFailure;
286     aMsg << "Try to read an unknown type" << endl;
287     break;
288
289   case Storage_VSTypeMismatch:
290     myReaderStatus = PCDM_RS_TypeFailure;
291     aMsg << "Try to read a wrong primitive type" << endl;
292     break;
293
294   default:
295     myReaderStatus = PCDM_RS_DriverFailure;
296     aMsg << "Retrieval Driver Failure" << endl;
297   }
298
299   Standard_Failure::Raise (aMsg);
300   return Standard_True;
301 }
302
303 //=======================================================================
304 //function : BindTypes
305 //purpose  : Register types
306 //=======================================================================
307 void StdLDrivers_DocumentRetrievalDriver::BindTypes (StdObjMgt_MapOfInstantiators& theMap)
308 {
309   StdLDrivers::BindTypes (theMap);
310 }