Commit | Line | Data |
---|---|---|
b311480e | 1 | // Created on: 2001-07-09 |
2 | // Created by: Julia DOROVSKIKH | |
973c2be1 | 3 | // Copyright (c) 2001-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 <XmlLDrivers_DocumentStorageDriver.ixx> | |
17 | ||
18 | #include <XmlLDrivers.hxx> | |
19 | #include <XmlLDrivers_NamespaceDef.hxx> | |
20 | #include <XmlMDF.hxx> | |
21 | #include <XmlMDF_ADriverTable.hxx> | |
22 | ||
23 | #include <XmlObjMgt.hxx> | |
24 | #include <XmlObjMgt_SRelocationTable.hxx> | |
25 | ||
26 | #include <LDOM_XmlWriter.hxx> | |
27 | #include <LDOM_LDOMImplementation.hxx> | |
28 | #include <LDOM_DocumentType.hxx> | |
29 | #include <XmlObjMgt_Document.hxx> | |
30 | ||
31 | #include <Storage_Data.hxx> | |
32 | #include <PCDM.hxx> | |
33 | #include <PCDM_ReadWriter.hxx> | |
34 | #include <CDM_NullMessageDriver.hxx> | |
35 | #include <CDM_Document.hxx> | |
36 | #include <CDM_Application.hxx> | |
37 | #include <TDocStd_Document.hxx> | |
38 | #include <TColStd_SequenceOfAsciiString.hxx> | |
39 | ||
40 | #include <locale.h> | |
41 | #include <Standard_Failure.hxx> | |
42 | #include <Standard_ErrorHandler.hxx> | |
43 | ||
44 | #include <OSD_File.hxx> | |
45 | #include <OSD_Environment.hxx> | |
46 | ||
47 | #define STORAGE_VERSION "STORAGE_VERSION: " | |
48 | #define REFERENCE_COUNTER "REFERENCE_COUNTER: " | |
49 | #define MODIFICATION_COUNTER "MODIFICATION_COUNTER: " | |
50 | #define START_REF "START_REF" | |
51 | #define END_REF "END_REF" | |
52 | ||
53 | #define FAILSTR "Failed to write xsi:schemaLocation : " | |
54 | ||
55 | //#define TAKE_TIMES | |
56 | static void take_time (const Standard_Integer, const char *, | |
57 | const Handle(CDM_MessageDriver)&) | |
58 | #ifdef TAKE_TIMES | |
59 | ; | |
60 | #else | |
61 | {} | |
62 | #endif | |
63 | ||
64 | //======================================================================= | |
65 | //function : XmlLDrivers_DocumentStorageDriver | |
66 | //purpose : Constructor | |
67 | //======================================================================= | |
68 | XmlLDrivers_DocumentStorageDriver::XmlLDrivers_DocumentStorageDriver | |
69 | (const TCollection_ExtendedString& theCopyright) | |
70 | : myCopyright (theCopyright) | |
71 | { | |
72 | } | |
73 | ||
74 | //======================================================================= | |
75 | //function : SchemaName | |
76 | //purpose : | |
77 | //======================================================================= | |
78 | TCollection_ExtendedString XmlLDrivers_DocumentStorageDriver::SchemaName() const | |
79 | { | |
80 | TCollection_ExtendedString schemaname; | |
81 | return schemaname; | |
82 | } | |
83 | ||
84 | //======================================================================= | |
85 | //function : AddNamespace | |
86 | //purpose : | |
87 | //======================================================================= | |
88 | ||
89 | void XmlLDrivers_DocumentStorageDriver::AddNamespace | |
90 | (const TCollection_AsciiString& thePrefix, | |
91 | const TCollection_AsciiString& theURI) | |
92 | { | |
93 | for (Standard_Integer i = 1; i <= mySeqOfNS.Length(); i++) | |
94 | if (thePrefix == mySeqOfNS(i).Prefix()) return; | |
95 | mySeqOfNS.Append (XmlLDrivers_NamespaceDef(thePrefix, theURI)); | |
96 | } | |
97 | ||
98 | //======================================================================= | |
99 | //function : Write | |
100 | //purpose : | |
101 | //======================================================================= | |
102 | void XmlLDrivers_DocumentStorageDriver::Write | |
103 | (const Handle(CDM_Document)& theDocument, | |
104 | const TCollection_ExtendedString& theFileName) | |
105 | { | |
7fd59977 | 106 | Handle(CDM_MessageDriver) aMessageDriver = |
107 | theDocument -> Application() -> MessageDriver(); | |
108 | ::take_time (~0, " +++++ Start STORAGE procedures ++++++", aMessageDriver); | |
109 | ||
110 | // Create new DOM_Document | |
111 | XmlObjMgt_Document aDOMDoc = XmlObjMgt_Document::createDocument ("document"); | |
112 | ||
113 | // Fill the document with data | |
114 | XmlObjMgt_Element anElement = aDOMDoc.getDocumentElement(); | |
115 | ||
116 | if (WriteToDomDocument (theDocument, anElement, theFileName) == Standard_False) { | |
117 | // Write DOM_Document into XML file, | |
118 | TCollection_AsciiString aFileName (theFileName, '?'); | |
119 | FILE * aFile = fopen(aFileName.ToCString(), "wt"); | |
120 | ||
121 | if (aFile) { | |
122 | LDOM_XmlWriter aWriter (aFile); | |
123 | aWriter.SetIndentation(1); | |
124 | aWriter << aDOMDoc; | |
125 | fclose(aFile); | |
126 | ::take_time (0, " +++++ Fin formatting to XML : ", aMessageDriver); | |
127 | ||
128 | }else{ | |
15e8b082 | 129 | SetIsError (Standard_True); |
8e1e79f0 | 130 | SetStoreStatus(PCDM_SS_WriteFailure); |
7fd59977 | 131 | TCollection_ExtendedString aMsg = |
132 | TCollection_ExtendedString("Error: the file ") + aFileName + | |
133 | " cannot be opened for writing"; | |
134 | aMessageDriver -> Write (aMsg.ToExtString()); | |
135 | Standard_Failure::Raise("File cannot be opened for writing"); | |
136 | } | |
137 | } | |
7fd59977 | 138 | } |
139 | ||
140 | //======================================================================= | |
141 | //function : WriteToDomDocument | |
142 | //purpose : management of the macro-structure of XML document data | |
143 | //remark : If the application needs to use myRelocTable to store additional | |
144 | // data to XML, this method should be reimplemented avoiding step 3 | |
145 | //======================================================================= | |
146 | ||
147 | Standard_Boolean XmlLDrivers_DocumentStorageDriver::WriteToDomDocument | |
148 | (const Handle(CDM_Document)& theDocument, | |
149 | XmlObjMgt_Element& theElement, | |
150 | const TCollection_ExtendedString& theFileName) | |
151 | { | |
15e8b082 | 152 | SetIsError(Standard_False); |
7fd59977 | 153 | Handle(CDM_MessageDriver) aMessageDriver = |
154 | theDocument -> Application() -> MessageDriver(); | |
155 | // 1. Write header information | |
156 | Standard_Integer i; | |
157 | XmlObjMgt_Document aDOMDoc = theElement.getOwnerDocument(); | |
158 | ||
159 | // 1.a File Format | |
160 | TCollection_AsciiString aStorageFormat (theDocument->StorageFormat(), '?'); | |
161 | theElement.setAttribute ("format", aStorageFormat.ToCString()); | |
162 | // theElement.setAttribute ("schema", "XSD"); | |
163 | ||
164 | theElement.setAttribute ("xmlns" , "http://www.opencascade.org/OCAF/XML"); | |
165 | for (i = 1; i <= mySeqOfNS.Length(); i++) { | |
166 | TCollection_AsciiString aPrefix = | |
167 | TCollection_AsciiString("xmlns:") + mySeqOfNS(i).Prefix().ToCString(); | |
168 | theElement.setAttribute (aPrefix.ToCString(), | |
169 | mySeqOfNS(i).URI().ToCString()); | |
170 | } | |
171 | theElement.setAttribute ("xmlns:xsi", | |
172 | "http://www.w3.org/2001/XMLSchema-instance"); | |
173 | //mkv 15.09.05 OCC10001 | |
174 | //theElement.setAttribute ("xsi:schemaLocation", | |
175 | // "http://www.opencascade.org/OCAF/XML" | |
176 | // " http://www.nnov.matra-dtv.fr/~agv/XmlOcaf.xsd"); | |
177 | // | |
178 | // the order of search : by CSF_XmlOcafResource and then by CASROOT | |
179 | TCollection_AsciiString anHTTP = "http://www.opencascade.org/OCAF/XML"; | |
180 | Standard_Boolean aToSetCSFVariable = Standard_False; | |
181 | const char * aCSFVariable [2] = { | |
182 | "CSF_XmlOcafResource", | |
183 | "CASROOT" | |
184 | }; | |
185 | TCollection_AsciiString aResourceDir = ""; | |
186 | aResourceDir = getenv (aCSFVariable[0]); | |
187 | if (aResourceDir.IsEmpty()) { | |
188 | // now try by CASROOT | |
189 | aResourceDir = getenv (aCSFVariable[1]); | |
190 | if ( !aResourceDir.IsEmpty() ) { | |
191 | aResourceDir += "/src/XmlOcafResource" ; | |
192 | aToSetCSFVariable = Standard_True; //CSF variable to be set later | |
193 | } | |
194 | #ifdef DEB | |
195 | else { | |
196 | TCollection_ExtendedString aWarn = FAILSTR "Neither "; | |
197 | aWarn = (aWarn + aCSFVariable[0] + ", nor " + aCSFVariable[1] | |
198 | + " variables have been set"); | |
199 | aMessageDriver->Write (aWarn.ToExtString()); | |
200 | } | |
201 | #endif | |
202 | } | |
203 | if (!aResourceDir.IsEmpty()) { | |
204 | TCollection_AsciiString aResourceFileName = aResourceDir + "/XmlOcaf.xsd"; | |
205 | // search directory name that has been constructed, now check whether | |
206 | // it and the file exist | |
207 | OSD_File aResourceFile ( aResourceFileName ); | |
208 | if ( aResourceFile.Exists() ) { | |
209 | if (aToSetCSFVariable) { | |
210 | OSD_Environment aCSFVarEnv ( aCSFVariable[0], aResourceDir ); | |
211 | aCSFVarEnv.Build(); | |
212 | #ifdef DEB | |
213 | TCollection_ExtendedString aWarn1 = "Variable "; | |
214 | aWarn1 = (aWarn1 + aCSFVariable[0] | |
215 | + " has not been explicitly defined. Set to " + aResourceDir); | |
216 | aMessageDriver->Write (aWarn1.ToExtString()); | |
217 | #endif | |
218 | if ( aCSFVarEnv.Failed() ) { | |
219 | TCollection_ExtendedString aWarn = FAILSTR "Failed to initialize "; | |
220 | aWarn = aWarn + aCSFVariable[0] + " with " + aResourceDir; | |
221 | aMessageDriver->Write (aWarn.ToExtString()); | |
222 | } | |
223 | } | |
224 | } | |
225 | #ifdef DEB | |
226 | else { | |
227 | TCollection_ExtendedString aWarn = FAILSTR "Schema definition file "; | |
228 | aWarn += (aResourceFileName + " was not found"); | |
229 | aMessageDriver->Write (aWarn.ToExtString()); | |
230 | } | |
231 | #endif | |
232 | anHTTP = anHTTP + ' ' + aResourceFileName; | |
233 | } | |
234 | theElement.setAttribute ("xsi:schemaLocation", anHTTP.ToCString() ); | |
235 | ||
236 | // 1.b Info section | |
237 | XmlObjMgt_Element anInfoElem = aDOMDoc.createElement("info"); | |
238 | theElement.appendChild(anInfoElem); | |
239 | ||
240 | TCollection_AsciiString aCreationDate = XmlLDrivers::CreationDate(); | |
241 | ||
242 | // anInfoElem.setAttribute("dbv", 0); | |
243 | anInfoElem.setAttribute("date", aCreationDate.ToCString()); | |
244 | anInfoElem.setAttribute("schemav", 0); | |
245 | // anInfoElem.setAttribute("appv", anAppVersion.ToCString()); | |
246 | ||
247 | // Document version | |
248 | anInfoElem.setAttribute("DocVersion", XmlLDrivers::StorageVersion().ToCString()); | |
249 | ||
250 | // User info with Copyright | |
251 | TColStd_SequenceOfAsciiString aUserInfo; | |
252 | if (myCopyright.Length() > 0) | |
253 | aUserInfo.Append (TCollection_AsciiString(myCopyright,'?')); | |
254 | ||
255 | Handle(Storage_Data) theData = new Storage_Data; | |
256 | //PCDM_ReadWriter::WriteFileFormat( theData, theDocument ); | |
257 | PCDM_ReadWriter::Writer()->WriteReferenceCounter(theData,theDocument); | |
258 | PCDM_ReadWriter::Writer()->WriteReferences(theData,theDocument,theFileName); | |
259 | PCDM_ReadWriter::Writer()->WriteExtensions(theData,theDocument); | |
260 | PCDM_ReadWriter::Writer()->WriteVersion(theData,theDocument); | |
261 | ||
262 | const TColStd_SequenceOfAsciiString& aRefs = theData->UserInfo(); | |
263 | for(i = 1; i <= aRefs.Length(); i++) | |
264 | aUserInfo.Append(aRefs.Value(i)); | |
265 | ||
266 | for (i = 1; i <= aUserInfo.Length(); i++) | |
267 | { | |
268 | XmlObjMgt_Element aUIItem = aDOMDoc.createElement ("iitem"); | |
269 | anInfoElem.appendChild (aUIItem); | |
270 | LDOM_Text aUIText = aDOMDoc.createTextNode (aUserInfo(i).ToCString()); | |
271 | aUIItem.appendChild (aUIText); | |
272 | } | |
273 | ||
274 | // 1.c Comments section | |
275 | TColStd_SequenceOfExtendedString aComments; | |
276 | theDocument->Comments(aComments); | |
277 | ||
278 | XmlObjMgt_Element aCommentsElem = aDOMDoc.createElement ("comments"); | |
279 | theElement.appendChild (aCommentsElem); | |
280 | ||
281 | for (i = 1; i <= aComments.Length(); i++) | |
282 | { | |
283 | XmlObjMgt_Element aCItem = aDOMDoc.createElement ("citem"); | |
284 | aCommentsElem.appendChild (aCItem); | |
285 | XmlObjMgt::SetExtendedString (aCItem, aComments(i)); | |
286 | } | |
287 | ||
288 | // 2a. Write document contents | |
289 | Standard_Integer anObjNb = 0; | |
290 | { | |
291 | try | |
292 | { | |
293 | OCC_CATCH_SIGNALS | |
294 | anObjNb = MakeDocument(theDocument, theElement); | |
295 | } | |
296 | catch (Standard_Failure) | |
297 | { | |
15e8b082 | 298 | SetIsError (Standard_True); |
8e1e79f0 | 299 | SetStoreStatus(PCDM_SS_Failure); |
7fd59977 | 300 | TCollection_ExtendedString anErrorString (Standard_Failure::Caught()->GetMessageString()); |
301 | aMessageDriver -> Write (anErrorString.ToExtString()); | |
302 | } | |
303 | } | |
15e8b082 M |
304 | if (anObjNb <= 0 && IsError() == Standard_False) { |
305 | SetIsError (Standard_True); | |
8e1e79f0 | 306 | SetStoreStatus(PCDM_SS_No_Obj); |
7fd59977 | 307 | TCollection_ExtendedString anErrorString ("error occurred"); |
308 | aMessageDriver -> Write (anErrorString.ToExtString()); | |
309 | } | |
310 | // 2b. Write number of objects into the info section | |
311 | anInfoElem.setAttribute("objnb", anObjNb); | |
312 | ::take_time (0, " +++++ Fin DOM data for OCAF : ", aMessageDriver); | |
313 | ||
314 | // 3. Clear relocation table | |
315 | // If the application needs to use myRelocTable to store additional | |
316 | // data to XML, this method should be reimplemented avoiding this step | |
317 | myRelocTable.Clear(); | |
318 | ||
319 | // 4. Write Shapes section | |
320 | if(WriteShapeSection(theElement)) | |
321 | ::take_time (0, " +++ Fin DOM data for Shapes : ", aMessageDriver); | |
15e8b082 | 322 | return IsError(); |
7fd59977 | 323 | } |
324 | ||
325 | //======================================================================= | |
326 | //function : MakeDocument | |
327 | //purpose : | |
328 | //======================================================================= | |
329 | Standard_Integer XmlLDrivers_DocumentStorageDriver::MakeDocument | |
330 | (const Handle(CDM_Document)& theTDoc, | |
331 | XmlObjMgt_Element& theElement) | |
332 | { | |
333 | TCollection_ExtendedString aMessage; | |
334 | Handle(TDocStd_Document) TDOC = Handle(TDocStd_Document)::DownCast(theTDoc); | |
335 | myRelocTable.Clear(); | |
336 | if (!TDOC.IsNull()) | |
337 | { | |
338 | // myRelocTable.SetDocument (theElement.getOwnerDocument()); | |
339 | Handle(TDF_Data) aTDF = TDOC->GetData(); | |
340 | ||
341 | // Find MessageDriver and pass it to AttributeDrivers() | |
342 | Handle(CDM_Application) anApplication= theTDoc -> Application(); | |
343 | Handle(CDM_MessageDriver) aMessageDriver; | |
344 | if (anApplication.IsNull()) | |
345 | aMessageDriver = new CDM_NullMessageDriver; | |
346 | else | |
347 | aMessageDriver = anApplication -> MessageDriver(); | |
348 | if (myDrivers.IsNull()) myDrivers = AttributeDrivers (aMessageDriver); | |
349 | ||
350 | // Retrieve from DOM_Document | |
351 | XmlMDF::FromTo (aTDF, theElement, myRelocTable, myDrivers); | |
352 | #if defined(DEB) && !defined(TAKE_TIMES) | |
353 | aMessage = "First step successfull"; | |
354 | aMessageDriver -> Write (aMessage.ToExtString()); | |
355 | #endif | |
356 | return myRelocTable.Extent(); | |
357 | } | |
358 | #ifdef DEB | |
359 | cout << "First step failed" << endl; // No MessageDriver available | |
360 | #endif | |
361 | return -1; // error | |
362 | } | |
363 | ||
7fd59977 | 364 | //======================================================================= |
365 | //function : AttributeDrivers | |
366 | //purpose : | |
367 | //======================================================================= | |
368 | Handle(XmlMDF_ADriverTable) XmlLDrivers_DocumentStorageDriver::AttributeDrivers | |
369 | (const Handle(CDM_MessageDriver)& theMessageDriver) | |
370 | { | |
371 | return XmlLDrivers::AttributeDrivers (theMessageDriver); | |
372 | } | |
373 | ||
374 | //======================================================================= | |
375 | //function : take_time | |
376 | //class : static | |
377 | //purpose : output astronomical time elapsed | |
378 | //======================================================================= | |
379 | #ifdef TAKE_TIMES | |
380 | #include <time.h> | |
381 | #include <sys/timeb.h> | |
382 | #include <sys/types.h> | |
383 | #include <stdio.h> | |
384 | #ifndef WNT | |
385 | extern "C" int ftime (struct timeb *tp); | |
386 | #endif | |
387 | struct timeb tmbuf0; | |
388 | ||
389 | static void take_time (const Standard_Integer isReset, const char * aHeader, | |
390 | const Handle(CDM_MessageDriver)& aMessageDriver) | |
391 | { | |
392 | struct timeb tmbuf; | |
393 | ftime (&tmbuf); | |
394 | TCollection_ExtendedString aMessage ((Standard_CString)aHeader); | |
395 | if (isReset) tmbuf0 = tmbuf; | |
396 | else { | |
397 | char take_tm_buf [64]; | |
91322f44 | 398 | Sprintf (take_tm_buf, "%9.2f s ++++", |
7fd59977 | 399 | double(tmbuf.time - tmbuf0.time) + |
400 | double(tmbuf.millitm - tmbuf0.millitm)/1000.); | |
401 | aMessage += take_tm_buf; | |
402 | } | |
403 | aMessageDriver -> Write (aMessage.ToExtString()); | |
404 | } | |
405 | #endif | |
406 | ||
407 | //======================================================================= | |
408 | //function : WriteShapeSection | |
409 | //purpose : defines WriteShapeSection | |
410 | //======================================================================= | |
411 | Standard_Boolean XmlLDrivers_DocumentStorageDriver::WriteShapeSection | |
412 | (XmlObjMgt_Element& /*theElement*/) | |
413 | { | |
414 | // empty; should be redefined in subclasses | |
415 | return Standard_False; | |
416 | } | |
417 |