0033230: Data Exchange, DE Wrapper - Update API to find CAD provider
[occt.git] / src / DE / DE_Wrapper.cxx
1 // Copyright (c) 2022 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 <DE_Wrapper.hxx>
15
16 #include <DE_ConfigurationContext.hxx>
17 #include <DE_ConfigurationNode.hxx>
18 #include <DE_Provider.hxx>
19 #include <Message_ProgressRange.hxx>
20 #include <NCollection_Buffer.hxx>
21 #include <OSD_File.hxx>
22 #include <OSD_Path.hxx>
23 #include <OSD_FileSystem.hxx>
24 #include <OSD_Protection.hxx>
25 #include <Standard_ErrorHandler.hxx>
26 #include <TopoDS_Shape.hxx>
27
28 IMPLEMENT_STANDARD_RTTIEXT(DE_Wrapper, Standard_Transient)
29
30 namespace
31 {
32   static const TCollection_AsciiString& THE_CONFIGURATION_SCOPE()
33   {
34     static const TCollection_AsciiString aScope ("global");
35     return aScope;
36   }
37 }
38
39 //=======================================================================
40 // function : DE_Wrapper
41 // purpose  :
42 //=======================================================================
43 DE_Wrapper::DE_Wrapper()
44 {}
45
46 //=======================================================================
47 // function : DE_Wrapper
48 // purpose  :
49 //=======================================================================
50 DE_Wrapper::DE_Wrapper(const Handle(DE_Wrapper)& theWrapper)
51   : DE_Wrapper()
52 {
53   if (theWrapper.IsNull())
54   {
55     return;
56   }
57   GlobalParameters = theWrapper->GlobalParameters;
58   for (DE_ConfigurationFormatMap::Iterator aFormatIter(theWrapper->Nodes());
59        aFormatIter.More(); aFormatIter.Next())
60   {
61     for (DE_ConfigurationVendorMap::Iterator aVendorIter(aFormatIter.Value());
62          aVendorIter.More(); aVendorIter.Next())
63     {
64       Bind(aVendorIter.Value());
65     }
66   }
67 }
68
69 //=======================================================================
70 // function : GlobalWrapper
71 // purpose  :
72 //=======================================================================
73 Handle(DE_Wrapper) DE_Wrapper::GlobalWrapper()
74 {
75   static const Handle(DE_Wrapper)& aConfiguration = new DE_Wrapper();
76   return aConfiguration;
77 }
78
79 //=======================================================================
80 // function : Read
81 // purpose  :
82 //=======================================================================
83 Standard_Boolean DE_Wrapper::Read(const TCollection_AsciiString& thePath,
84                                   const Handle(TDocStd_Document)& theDocument,
85                                   Handle(XSControl_WorkSession)& theWS,
86                                   const Message_ProgressRange& theProgress)
87 {
88   if (theDocument.IsNull())
89   {
90     return Standard_False;
91   }
92   if (theWS.IsNull())
93   {
94     return Read(thePath, theDocument, theProgress);
95   }
96   Handle(DE_Provider) aProvider;
97   if (!FindProvider(thePath, Standard_True, aProvider))
98   {
99     return Standard_False;
100   }
101   return aProvider->Read(thePath, theDocument, theWS, theProgress);
102 }
103
104 //=======================================================================
105 // function : Write
106 // purpose  :
107 //=======================================================================
108 Standard_Boolean DE_Wrapper::Write(const TCollection_AsciiString& thePath,
109                                    const Handle(TDocStd_Document)& theDocument,
110                                    Handle(XSControl_WorkSession)& theWS,
111                                    const Message_ProgressRange& theProgress)
112 {
113   if (theDocument.IsNull())
114   {
115     return Standard_False;
116   }
117   if (theWS.IsNull())
118   {
119     return Write(thePath, theDocument, theProgress);
120   }
121   Handle(DE_Provider) aProvider;
122   if (!FindProvider(thePath, Standard_False, aProvider))
123   {
124     return Standard_False;
125   }
126   return aProvider->Write(thePath, theDocument, theWS, theProgress);
127 }
128
129 //=======================================================================
130 // function : Read
131 // purpose  :
132 //=======================================================================
133 Standard_Boolean DE_Wrapper::Read(const TCollection_AsciiString& thePath,
134                                   const Handle(TDocStd_Document)& theDocument,
135                                   const Message_ProgressRange& theProgress)
136 {
137   if (theDocument.IsNull())
138   {
139     return Standard_False;
140   }
141   Handle(DE_Provider) aProvider;
142   if (!FindProvider(thePath, Standard_True, aProvider))
143   {
144     return Standard_False;
145   }
146   return aProvider->Read(thePath, theDocument, theProgress);
147 }
148
149 //=======================================================================
150 // function : Write
151 // purpose  :
152 //=======================================================================
153 Standard_Boolean DE_Wrapper::Write(const TCollection_AsciiString& thePath,
154                                    const Handle(TDocStd_Document)& theDocument,
155                                    const Message_ProgressRange& theProgress)
156 {
157   if (theDocument.IsNull())
158   {
159     return Standard_False;
160   }
161   Handle(DE_Provider) aProvider;
162   if (!FindProvider(thePath, Standard_False, aProvider))
163   {
164     return Standard_False;
165   }
166   return aProvider->Write(thePath, theDocument, theProgress);
167 }
168
169 //=======================================================================
170 // function : Read
171 // purpose  :
172 //=======================================================================
173 Standard_Boolean DE_Wrapper::Read(const TCollection_AsciiString& thePath,
174                                   TopoDS_Shape& theShape,
175                                   Handle(XSControl_WorkSession)& theWS,
176                                   const Message_ProgressRange& theProgress)
177 {
178   if (theWS.IsNull())
179   {
180     return Read(thePath, theShape, theProgress);
181   }
182   Handle(DE_Provider) aProvider;
183   if (!FindProvider(thePath, Standard_True, aProvider))
184   {
185     return Standard_False;
186   }
187   return aProvider->Read(thePath, theShape, theWS, theProgress);
188 }
189
190 //=======================================================================
191 // function : Write
192 // purpose  :
193 //=======================================================================
194 Standard_Boolean DE_Wrapper::Write(const TCollection_AsciiString& thePath,
195                                    const TopoDS_Shape& theShape,
196                                    Handle(XSControl_WorkSession)& theWS,
197                                    const Message_ProgressRange& theProgress)
198 {
199   if (theWS.IsNull())
200   {
201     return Write(thePath, theShape, theProgress);
202   }
203   Handle(DE_Provider) aProvider;
204   if (!FindProvider(thePath, Standard_False, aProvider))
205   {
206     return Standard_False;
207   }
208   return aProvider->Write(thePath, theShape, theWS, theProgress);
209 }
210
211 //=======================================================================
212 // function : Read
213 // purpose  :
214 //=======================================================================
215 Standard_Boolean DE_Wrapper::Read(const TCollection_AsciiString& thePath,
216                                   TopoDS_Shape& theShape,
217                                   const Message_ProgressRange& theProgress)
218 {
219
220   Handle(DE_Provider) aProvider;
221   if (!FindProvider(thePath, Standard_True, aProvider))
222   {
223     return Standard_False;
224   }
225   return aProvider->Read(thePath, theShape, theProgress);
226 }
227
228 //=======================================================================
229 // function : Write
230 // purpose  :
231 //=======================================================================
232 Standard_Boolean DE_Wrapper::Write(const TCollection_AsciiString& thePath,
233                                    const TopoDS_Shape& theShape,
234                                    const Message_ProgressRange& theProgress)
235 {
236   Handle(DE_Provider) aProvider;
237   if (!FindProvider(thePath, Standard_False, aProvider))
238   {
239     return Standard_False;
240   }
241   return aProvider->Write(thePath, theShape, theProgress);
242 }
243
244 //=======================================================================
245 // function : Load
246 // purpose  :
247 //=======================================================================
248 Standard_Boolean DE_Wrapper::Load(const TCollection_AsciiString& theResource,
249                                   const Standard_Boolean theIsRecursive)
250 {
251   Handle(DE_ConfigurationContext) aResource = new DE_ConfigurationContext();
252   aResource->Load(theResource);
253   return Load(aResource, theIsRecursive);
254 }
255
256 //=======================================================================
257 // function : Load
258 // purpose  :
259 //=======================================================================
260 Standard_Boolean DE_Wrapper::Load(const Handle(DE_ConfigurationContext)& theResource,
261                                   const Standard_Boolean theIsRecursive)
262 {
263   GlobalParameters.LengthUnit = theResource->RealVal("general.length.unit", GlobalParameters.LengthUnit, THE_CONFIGURATION_SCOPE());
264   if (theIsRecursive)
265   {
266     for (DE_ConfigurationFormatMap::Iterator aFormatIter(myConfiguration);
267          aFormatIter.More(); aFormatIter.Next())
268     {
269       for (DE_ConfigurationVendorMap::Iterator aVendorIter(aFormatIter.Value());
270            aVendorIter.More(); aVendorIter.Next())
271       {
272         aVendorIter.Value()->Load(theResource);
273       }
274     }
275     sort(theResource);
276   }
277   return Standard_True;
278 }
279
280 //=======================================================================
281 // function : Save
282 // purpose  :
283 //=======================================================================
284 Standard_Boolean DE_Wrapper::Save(const TCollection_AsciiString& theResourcePath,
285                                   const Standard_Boolean theIsRecursive,
286                                   const TColStd_ListOfAsciiString& theFormats,
287                                   const TColStd_ListOfAsciiString& theVendors)
288 {
289   OSD_Path aPath = theResourcePath;
290   OSD_File aFile(aPath);
291   OSD_Protection aProt;
292   {
293     try
294     {
295       OCC_CATCH_SIGNALS
296         aFile.Build(OSD_ReadWrite, aProt);
297     }
298     catch (Standard_Failure const&)
299     {
300       return Standard_False;
301     }
302   }
303   if (aFile.Failed())
304   {
305     return Standard_False;
306   }
307   TCollection_AsciiString aResConfiguration = Save(theIsRecursive, theFormats, theVendors);
308   aFile.Write(aResConfiguration, aResConfiguration.Length());
309   aFile.Close();
310   return Standard_True;
311 }
312
313 //=======================================================================
314 // function : Save
315 // purpose  :
316 //=======================================================================
317 TCollection_AsciiString DE_Wrapper::Save(const Standard_Boolean theIsRecursive,
318                                          const TColStd_ListOfAsciiString& theFormats,
319                                          const TColStd_ListOfAsciiString& theVendors)
320 {
321   TCollection_AsciiString aResult;
322   aResult += "!Description of the config file for DE toolkit\n";
323   aResult += "!*****************************************************************************\n";
324   aResult += "!\n";
325   aResult += "!Format of the file is compliant with the standard Open CASCADE resource files\n";
326   aResult += "!Each key defines a sequence of either further keys.\n";
327   aResult += "!Keys can be nested down to an arbitrary level.\n";
328   aResult += "!\n";
329   aResult += "!*****************************************************************************\n";
330   aResult += "!DE_Wrapper\n";
331   aResult += "!Priority vendor list. For every CAD format set indexed list of vendors\n";
332   for (DE_ConfigurationFormatMap::Iterator aFormatIter(myConfiguration);
333        aFormatIter.More(); aFormatIter.Next())
334   {
335     const TCollection_AsciiString& aFormat = aFormatIter.Key();
336     aResult += THE_CONFIGURATION_SCOPE() + '.' + "priority" + '.' + aFormat + " :\t ";
337     for (DE_ConfigurationVendorMap::Iterator aVendorIter(aFormatIter.Value());
338          aVendorIter.More(); aVendorIter.Next())
339     {
340       const TCollection_AsciiString& aVendorName = aVendorIter.Value()->GetVendor();
341       aResult += aVendorName + " ";
342     }
343     aResult += "\n";
344   }
345   aResult += "!Global parameters. Used for all providers\n";
346   aResult += "!Length scale unit value. Should be more the 0. Default value: 1.0(MM)\n";
347   aResult += THE_CONFIGURATION_SCOPE() + ".general.length.unit :\t " + GlobalParameters.LengthUnit + "\n";
348   if (theIsRecursive)
349   {
350     for (DE_ConfigurationFormatMap::Iterator aFormatIter(myConfiguration);
351          aFormatIter.More(); aFormatIter.Next())
352     {
353       if (!theFormats.IsEmpty() && !theFormats.Contains(aFormatIter.Key()))
354       {
355         continue;
356       }
357       for (DE_ConfigurationVendorMap::Iterator aVendorIter(aFormatIter.Value());
358            aVendorIter.More(); aVendorIter.Next())
359       {
360         if (!theVendors.IsEmpty() && !theVendors.Contains(aVendorIter.Key()))
361         {
362           continue;
363         }
364         aResult += "!\n";
365         aResult += aVendorIter.Value()->Save();
366         aResult += "!\n";
367       }
368     }
369   }
370   aResult += "!*****************************************************************************\n";
371   return aResult;
372 }
373
374 //=======================================================================
375 // function : Bind
376 // purpose  :
377 //=======================================================================
378 Standard_Boolean DE_Wrapper::Bind(const Handle(DE_ConfigurationNode)& theNode)
379 {
380   if (theNode.IsNull())
381   {
382     return Standard_False;
383   }
384   const TCollection_AsciiString aFileFormat = theNode->GetFormat();
385   const TCollection_AsciiString aVendorName = theNode->GetVendor();
386   DE_ConfigurationVendorMap* aVendorMap = myConfiguration.ChangeSeek(aFileFormat);
387   if (aVendorMap == NULL)
388   {
389     DE_ConfigurationVendorMap aTmpVendorMap;
390     aVendorMap = myConfiguration.Bound(aFileFormat, aTmpVendorMap);
391   }
392   return aVendorMap->Add(aVendorName, theNode) > 0;
393 }
394
395 //=======================================================================
396 // function : Find
397 // purpose  :
398 //=======================================================================
399 Standard_Boolean DE_Wrapper::Find(const TCollection_AsciiString& theFormat,
400                                   const TCollection_AsciiString& theVendor,
401                                   Handle(DE_ConfigurationNode)& theNode) const
402 {
403   const DE_ConfigurationVendorMap* aVendorMap = myConfiguration.Seek(theFormat);
404   return aVendorMap != nullptr && aVendorMap->FindFromKey(theVendor, theNode);
405 }
406
407 //=======================================================================
408 // function : ChangePriority
409 // purpose  :
410 //=======================================================================
411 void DE_Wrapper::ChangePriority(const TCollection_AsciiString& theFormat,
412                                 const TColStd_ListOfAsciiString& theVendorPriority,
413                                 const Standard_Boolean theToDisable)
414 {
415   DE_ConfigurationVendorMap aVendorMap;
416   if (!myConfiguration.Find(theFormat, aVendorMap))
417   {
418     return;
419   }
420   DE_ConfigurationVendorMap aNewVendorMap;
421   // Sets according to the input priority
422   for (TColStd_ListOfAsciiString::Iterator aPriorIter(theVendorPriority);
423        aPriorIter.More(); aPriorIter.Next())
424   {
425     const TCollection_AsciiString& aVendorName = aPriorIter.Value();
426     Handle(DE_ConfigurationNode) aNode;
427     if (aVendorMap.FindFromKey(aVendorName, aNode))
428     {
429       aNode->SetEnabled(Standard_True);
430       aNode->UpdateLoad();
431       aNewVendorMap.Add(aVendorName, aNode);
432     }
433   }
434   // Sets not used elements
435   for (DE_ConfigurationVendorMap::Iterator aVendorIter(aVendorMap);
436        aVendorIter.More(); aVendorIter.Next())
437   {
438     const TCollection_AsciiString& aVendorName = aVendorIter.Key();
439     if (!theVendorPriority.Contains(aVendorName))
440     {
441       Handle(DE_ConfigurationNode) aNode = aVendorIter.Value();
442       if (theToDisable)
443       {
444         aNode->SetEnabled(Standard_False);
445       }
446       aNewVendorMap.Add(aVendorName, aNode);
447     }
448   }
449   myConfiguration.Bind(theFormat, aNewVendorMap);
450 }
451
452 //=======================================================================
453 // function : ChangePriority
454 // purpose  :
455 //=======================================================================
456 void DE_Wrapper::ChangePriority(const TColStd_ListOfAsciiString& theVendorPriority,
457                                 const Standard_Boolean theToDisable)
458 {
459   for (DE_ConfigurationFormatMap::Iterator aFormatIter(myConfiguration);
460        aFormatIter.More(); aFormatIter.Next())
461   {
462     ChangePriority(aFormatIter.Key(), theVendorPriority, theToDisable);
463   }
464 }
465
466 //=======================================================================
467 // function : Nodes
468 // purpose  :
469 //=======================================================================
470 const DE_ConfigurationFormatMap& DE_Wrapper::Nodes() const
471 {
472   return myConfiguration;
473 }
474
475 //=======================================================================
476 // function : Copy
477 // purpose  :
478 //=======================================================================
479 Handle(DE_Wrapper) DE_Wrapper::Copy() const
480 {
481   return new DE_Wrapper(*this);
482 }
483
484 //=======================================================================
485 // function : FindProvider
486 // purpose  :
487 //=======================================================================
488 Standard_Boolean DE_Wrapper::FindProvider(const TCollection_AsciiString& thePath,
489                                           const Standard_Boolean theToImport,
490                                           Handle(DE_Provider)& theProvider) const
491 {
492   Handle(NCollection_Buffer) aBuffer;
493   if (theToImport)
494   {
495     const Handle(OSD_FileSystem)& aFileSystem = OSD_FileSystem::DefaultFileSystem();
496     std::shared_ptr<std::istream> aStream = aFileSystem->OpenIStream(thePath, std::ios::in | std::ios::binary);
497     if (aStream.get() != nullptr)
498     {
499       aBuffer = new NCollection_Buffer(NCollection_BaseAllocator::CommonBaseAllocator(), 2048);
500       aStream->read((char*)aBuffer->ChangeData(), 2048);
501       aBuffer->ChangeData()[2047] = '\0';
502     }
503   }
504   OSD_Path aPath(thePath);
505   const TCollection_AsciiString anExtr = aPath.Extension();
506   for (DE_ConfigurationFormatMap::Iterator aFormatIter(myConfiguration);
507        aFormatIter.More(); aFormatIter.Next())
508   {
509     for (DE_ConfigurationVendorMap::Iterator aVendorIter(aFormatIter.Value());
510          aVendorIter.More(); aVendorIter.Next())
511     {
512       const Handle(DE_ConfigurationNode)& aNode = aVendorIter.Value();
513       if (aNode->IsEnabled() &&
514           ((theToImport && aNode->IsImportSupported()) ||
515           (!theToImport && aNode->IsExportSupported())) &&
516           (aNode->CheckExtension(anExtr) ||
517           (theToImport && aNode->CheckContent(aBuffer))))
518       {
519         theProvider = aNode->BuildProvider();
520         aNode->GlobalParameters = GlobalParameters;
521         theProvider->SetNode(aNode);
522         return Standard_True;
523       }
524     }
525   }
526   return Standard_False;
527 }
528
529 //=======================================================================
530 // function : sort
531 // purpose  :
532 //=======================================================================
533 void DE_Wrapper::sort(const Handle(DE_ConfigurationContext)& theResource)
534 {
535   const TCollection_AsciiString aScope(THE_CONFIGURATION_SCOPE() + '.' + "priority");
536   NCollection_List<Handle(DE_ConfigurationNode)> aVendors;
537   for (DE_ConfigurationFormatMap::Iterator aFormatIter(myConfiguration);
538        aFormatIter.More(); aFormatIter.Next())
539   {
540     TColStd_ListOfAsciiString aVendorPriority;
541     if (!theResource->GetStringSeq(aFormatIter.Key(), aVendorPriority, aScope))
542     {
543       continue;
544     }
545     ChangePriority(aFormatIter.Key(), aVendorPriority, Standard_True);
546   }
547 }