0033661: Data Exchange, Step Import - Tessellated GDTs are not imported
[occt.git] / src / Resource / Resource_Manager.cxx
1 // Copyright (c) 1998-1999 Matra Datavision
2 // Copyright (c) 1999-2014 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
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.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14
15 #include <Resource_Manager.hxx>
16
17 #include <OSD_Directory.hxx>
18 #include <OSD_Environment.hxx>
19 #include <OSD_File.hxx>
20 #include <OSD_Path.hxx>
21 #include <OSD_Protection.hxx>
22 #include <Resource_LexicalCompare.hxx>
23 #include <Resource_NoSuchResource.hxx>
24 #include <Resource_Unicode.hxx>
25 #include <Standard_ErrorHandler.hxx>
26 #include <Standard_OutOfRange.hxx>
27 #include <Standard_Type.hxx>
28 #include <Standard_TypeMismatch.hxx>
29 #include <TCollection_AsciiString.hxx>
30 #include <TCollection_ExtendedString.hxx>
31 #include <TColStd_Array1OfAsciiString.hxx>
32
33 #include <algorithm>
34 #include <errno.h>
35
36 IMPLEMENT_STANDARD_RTTIEXT(Resource_Manager,Standard_Transient)
37
38 //! Auxiliary enumeration for function WhatKindOfLine().
39 enum Resource_KindOfLine
40 {
41   Resource_KOL_End,
42   Resource_KOL_Empty,
43   Resource_KOL_Comment,
44   Resource_KOL_Resource,
45   Resource_KOL_Error
46 };
47
48 static Resource_KindOfLine WhatKindOfLine(OSD_File& aFile,
49                                        TCollection_AsciiString& aToken1,
50                                        TCollection_AsciiString& aToken2);
51
52 static Standard_Integer GetLine(OSD_File& aFile,TCollection_AsciiString& aLine);
53
54 static Standard_Boolean Debug;
55
56 // =======================================================================
57 // function : Resource_Manager
58 // purpose  :
59 // =======================================================================
60 Resource_Manager::Resource_Manager (const TCollection_AsciiString& theName,
61                                     const TCollection_AsciiString& theDefaultsDirectory,
62                                     const TCollection_AsciiString& theUserDefaultsDirectory,
63                                     const Standard_Boolean theIsVerbose)
64 : myName (theName),
65   myVerbose (theIsVerbose)
66 {
67   if (!theDefaultsDirectory.IsEmpty())
68   {
69     OSD_Path anOSDPath (theDefaultsDirectory);
70     if (!anOSDPath.Name().IsEmpty())
71     {
72       anOSDPath.DownTrek (anOSDPath.Name() + anOSDPath.Extension());
73     }
74     anOSDPath.SetName (theName);
75     anOSDPath.SetExtension ("");
76     TCollection_AsciiString aPath;
77     anOSDPath.SystemName (aPath);
78     Load (aPath, myRefMap);
79   }
80   else if (myVerbose)
81   {
82     std::cout << "Resource Manager Warning: aDefaultsDirectory is empty." << std::endl;
83   }
84
85   if (!theUserDefaultsDirectory.IsEmpty())
86   {
87     OSD_Path anOSDPath (theUserDefaultsDirectory);
88     if (!anOSDPath.Name().IsEmpty())
89     {
90       anOSDPath.DownTrek (anOSDPath.Name() + anOSDPath.Extension());
91     }
92     anOSDPath.SetName (theName);
93     anOSDPath.SetExtension ("");
94     TCollection_AsciiString aPath;
95     anOSDPath.SystemName (aPath);
96     Load (aPath, myRefMap);
97   }
98   else if (myVerbose)
99   {
100     std::cout << "Resource Manager Warning: anUserDefaultsDirectory is empty." << std::endl;
101   }
102 }
103
104 Resource_Manager::Resource_Manager(const Standard_CString aName,
105                                    const Standard_Boolean Verbose) : myName(aName), myVerbose(Verbose)
106 {
107   OSD_Environment envDebug("ResourceDebug");
108   Debug = (!envDebug.Value().IsEmpty()) ;
109
110   TCollection_AsciiString Directory ;
111
112   OSD_Environment envVerbose("CSF_ResourceVerbose");
113   if (!envVerbose.Value().IsEmpty())
114     myVerbose = Standard_True;
115
116   TCollection_AsciiString aPath,aUserPath;
117   GetResourcePath(aPath,aName,Standard_False);
118   GetResourcePath(aUserPath,aName,Standard_True);
119
120   if (!aPath.IsEmpty())
121     Load(aPath,myRefMap);
122   else if (myVerbose)
123     std::cout << "Resource Manager Warning: Environment variable \"CSF_" << aName << "Defaults\" not set." << std::endl;
124
125   if (!aUserPath.IsEmpty())
126     Load(aUserPath,myRefMap);
127   else if (myVerbose)
128     std::cout << "Resource Manager Warning: Environment variable \"CSF_" << aName << "UserDefaults\" not set." << std::endl;
129 }
130
131 // =======================================================================
132 // function : Resource_Manager
133 // purpose  :
134 // =======================================================================
135 Resource_Manager::Resource_Manager()
136   : myName(""), myVerbose(Standard_False)
137 {
138
139 }
140
141 // =======================================================================
142 // function : Load
143 // purpose  :
144 // =======================================================================
145 void Resource_Manager::Load(const TCollection_AsciiString& thePath,
146                             Resource_DataMapOfAsciiStringAsciiString& aMap)
147 {
148   Resource_KindOfLine aKind;
149   TCollection_AsciiString Token1, Token2;
150   OSD_Path Path (thePath);
151   OSD_File File = Path;
152   TCollection_AsciiString FileName = Path.Name();
153   File.Open(OSD_ReadOnly,OSD_Protection());
154   if (File.Failed()) {
155     if (myVerbose)
156       std::cout << "Resource Manager Warning: Cannot read file \"" << FileName
157            << "\". File not found or permission denied." << std::endl;
158     return;
159   }
160   Standard_Integer LineNumber = 1;
161   while ((aKind = WhatKindOfLine(File, Token1, Token2)) != Resource_KOL_End) {
162     switch (aKind) {
163     case Resource_KOL_End:
164     case Resource_KOL_Comment:
165     case Resource_KOL_Empty:
166       break ;
167     case Resource_KOL_Resource:
168       if (!aMap.Bind(Token1,Token2))
169         aMap(Token1) = Token2;
170       break;
171     case Resource_KOL_Error:
172       if (myVerbose)
173         std::cout << "Resource Manager: Syntax error at line "
174           << LineNumber << " in file : " << FileName << std::endl;
175       break;
176     }
177     LineNumber++;
178   }
179   File.Close();
180   if (myVerbose)
181     std::cout << "Resource Manager: " << ((&aMap == &myUserMap) ? "User" : "Reference")
182          << " file \"" << FileName << "\" loaded" << std::endl;
183 }
184
185 static Resource_KindOfLine WhatKindOfLine(OSD_File& aFile,
186                                        TCollection_AsciiString& aToken1,
187                                        TCollection_AsciiString& aToken2)
188 {
189   TCollection_AsciiString WhiteSpace = " \t" ;
190   Standard_Integer Pos1,Pos2,Pos ;
191   TCollection_AsciiString Line ;
192
193   if (!GetLine(aFile,Line))
194     return Resource_KOL_End;
195
196   if (Line.Value(1) == '!')
197     return Resource_KOL_Comment;
198
199   Pos1 = Line.FirstLocationNotInSet(WhiteSpace, 1, Line.Length());
200   if (Line.Value(Pos1) == '\n')
201     return Resource_KOL_Empty;
202
203   Pos2 = Line.Location(1,':',Pos1,Line.Length());
204   if (!Pos2 || Pos1 == Pos2)
205     return Resource_KOL_Error;
206
207   for (Pos = Pos2-1; Line.Value(Pos) == '\t' || Line.Value(Pos) == ' ' ; Pos--);
208   aToken1 = Line.SubString(Pos1, Pos);
209
210   if (Debug)
211     std::cout << "Key = '" << aToken1 << std::flush ;
212
213   Pos = Line.FirstLocationNotInSet(WhiteSpace, Pos2+1, Line.Length());
214   if (Pos) {
215     if (Line.Value(Pos) == '\\')
216       switch(Line.Value(Pos+1)) {
217       case '\\' :
218       case ' '  :
219       case '\t' :
220         Pos++;
221         break;
222       }
223   }
224   if (Pos == Line.Length())
225     aToken2.Clear();
226   else {
227     Line.Remove(1,Pos-1);
228     const Standard_Integer aLineLength = Line.Length();
229     if (aLineLength >= 2)
230     {
231       if (Line.Value(aLineLength - 1) == '\r')
232       {
233         Line.Remove(aLineLength - 1);
234       }
235     }
236     Line.Remove(Line.Length());
237     aToken2 = Line;
238   }
239   if (Debug)
240     std::cout << "'\t Value = '" << aToken2 << "'" << std::endl << std::flush;
241   return Resource_KOL_Resource;
242 }
243
244 // Retourne 0 (EOF) ou une ligne toujours terminee par <NL>.
245
246 static Standard_Integer GetLine(OSD_File& aFile,TCollection_AsciiString& aLine)
247 {
248   TCollection_AsciiString Buffer;
249   Standard_Integer BufSize = 10;
250   Standard_Integer Len;
251
252   aLine.Clear();
253   do {
254     aFile.ReadLine(Buffer,BufSize,Len);
255     aLine += Buffer;
256     if (aFile.IsAtEnd()) {
257       if (!aLine.Length()) return 0;
258       else aLine += "\n";
259     }
260   } while (aLine.Value(aLine.Length()) != '\n');
261
262   return 1;
263 }
264
265 //=======================================================================
266 //function : Save
267 //purpose  : Sort and save the user resources in the user file.
268 //           Creates the file if it does not exist.
269 //=======================================================================
270 Standard_Boolean Resource_Manager::Save() const
271 {
272   TCollection_AsciiString anEnvVar("CSF_");
273   anEnvVar += myName;
274   anEnvVar += "UserDefaults";
275
276   TCollection_AsciiString dir;
277   OSD_Environment anEnv(anEnvVar);
278   dir = anEnv.Value();
279   if (dir.IsEmpty()) {
280     if (myVerbose)
281       std::cout << "Resource Manager Warning: environment variable \""
282            << anEnvVar << "\" not set.  Cannot save resources." << std::endl ;
283     return Standard_False;
284   }
285
286   TCollection_AsciiString aFilePath(dir);
287   OSD_Path anOSDPath(aFilePath);
288   OSD_Directory Dir = anOSDPath;
289   Standard_Boolean aStatus = Standard_True;
290   if ( !Dir.Exists() ) {
291     {
292       try {
293         OCC_CATCH_SIGNALS
294         Dir.Build(OSD_Protection(OSD_RX, OSD_RWXD, OSD_RX, OSD_RX));
295       }
296       catch (Standard_Failure const&) {
297         aStatus = Standard_False;
298       }
299     }
300     aStatus = aStatus && !Dir.Failed();
301     if (!aStatus) {
302       if (myVerbose)
303         std::cout << "Resource Manager: Error opening or creating directory \"" << aFilePath
304              << "\". Permission denied. Cannot save resources." << std::endl;
305       return Standard_False;
306     }
307   }
308
309   if (!anOSDPath.Name().IsEmpty())
310   {
311     anOSDPath.DownTrek (anOSDPath.Name () + anOSDPath.Extension ());
312   }
313   anOSDPath.SetName(myName);
314   anOSDPath.SetExtension("");
315   anOSDPath.SystemName(aFilePath);
316
317   OSD_File File = anOSDPath;
318   OSD_Protection theProt;
319   aStatus = Standard_True;
320   {
321     try {
322       OCC_CATCH_SIGNALS
323       File.Build(OSD_ReadWrite, theProt);
324     }
325     catch (Standard_Failure const&) {
326       aStatus = Standard_False;
327     }
328   }
329   aStatus = aStatus && !File.Failed();
330   if (!aStatus) {
331     if (myVerbose)
332       std::cout << "Resource Manager: Error opening or creating file \"" << aFilePath
333            << "\". Permission denied. Cannot save resources." << std::endl;
334     return Standard_False;
335   }
336
337   const Standard_Integer NbKey = myUserMap.Extent();
338   if (NbKey)
339   {
340     TColStd_Array1OfAsciiString KeyArray(1,NbKey);
341     Resource_DataMapIteratorOfDataMapOfAsciiStringAsciiString Iter(myUserMap);
342
343     Standard_Integer Index;
344     for ( Index = 1; Iter.More(); Iter.Next())
345       KeyArray(Index++)= Iter.Key();
346
347   std::sort (KeyArray.begin(), KeyArray.end());
348
349     TCollection_AsciiString Line, Value;
350     for (Index = 1 ; Index <= NbKey ; Index++) {
351       Value = myUserMap(KeyArray(Index));
352       if (!Value.IsEmpty())
353         switch(Value.Value(1)) {
354         case '\\' :
355         case ' ' :
356         case '\t' :
357           Value.Insert(1,'\\');
358           break;
359         }
360       Line = KeyArray(Index) + ":\t" + Value + "\n";
361
362       if (Debug)
363         std::cout << "Line = '" << Line << "'" << std::endl;
364
365       File.Write(Line, Line.Length());
366     }
367     if (myVerbose)
368       std::cout << "Resource Manager: Resources saved in file " << aFilePath << std::endl;
369   }
370   File.Close();
371   return Standard_True;
372 }
373
374 //=======================================================================
375 //function : Integer
376 //purpose  : Gets the value of an integer resource
377 //=======================================================================
378
379 Standard_Integer Resource_Manager::Integer(const Standard_CString aResourceName) const
380 {
381   TCollection_AsciiString Result = Value(aResourceName) ;
382   if (!Result.IsIntegerValue()) {
383     TCollection_AsciiString n("Value of resource `");
384     n+= aResourceName;
385     n+= "` is not an integer";
386     throw Standard_TypeMismatch(n.ToCString());
387   }
388   return Result.IntegerValue();
389 }
390
391 //=======================================================================
392 //function : Real
393 //purpose  : Gets the value of a real resource
394 //=======================================================================
395
396 Standard_Real Resource_Manager::Real(const Standard_CString  aResourceName) const
397 {
398   TCollection_AsciiString Result = Value(aResourceName) ;
399   if (!Result.IsRealValue()) {
400     TCollection_AsciiString n("Value of resource `");
401     n+= aResourceName;
402     n+= "` is not a real";
403     throw Standard_TypeMismatch(n.ToCString());
404   }
405   return Result.RealValue();
406 }
407
408 //=======================================================================
409 //function : Value
410 //purpose  : Gets the value of a CString resource
411 //=======================================================================
412
413 Standard_CString Resource_Manager::Value(const Standard_CString aResource) const
414 {
415   TCollection_AsciiString  Resource(aResource);
416   if (myUserMap.IsBound(Resource))
417     return myUserMap(Resource).ToCString();
418   if (myRefMap.IsBound(Resource))
419     return myRefMap(Resource).ToCString();
420   throw Resource_NoSuchResource(aResource);
421 }
422
423 //=======================================================================
424 //function : ExtValue
425 //purpose  : Gets the value of a ExtString resource
426 //=======================================================================
427
428 Standard_ExtString Resource_Manager::ExtValue(const Standard_CString aResource)
429 {
430   TCollection_AsciiString  Resource(aResource);
431   if (myExtStrMap.IsBound(Resource))
432     return myExtStrMap(Resource).ToExtString();
433
434   TCollection_AsciiString Result = Value(aResource);
435   TCollection_ExtendedString ExtResult;
436
437   Resource_Unicode::ConvertFormatToUnicode(Result.ToCString(),ExtResult);
438
439   myExtStrMap.Bind(Resource, ExtResult);
440   return  myExtStrMap(Resource).ToExtString();
441 }
442
443 //=======================================================================
444 //function : SetResource
445 //purpose  : Sets the new value of an integer resource.
446 //           If the resource does not exist, it is created.
447 //=======================================================================
448 void Resource_Manager::SetResource(const Standard_CString aResourceName,
449                                    const Standard_Integer aValue)
450 {
451   SetResource(aResourceName,TCollection_AsciiString(aValue).ToCString());
452 }
453
454 //=======================================================================
455 //function : SetResource
456 //purpose  : Sets the new value of a real resource.
457 //           If the resource does not exist, it is created.
458 //=======================================================================
459 void Resource_Manager::SetResource(const Standard_CString aResourceName,
460                                    const Standard_Real    aValue)
461 {
462   SetResource(aResourceName,TCollection_AsciiString(aValue).ToCString());
463 }
464
465 //=======================================================================
466 //function : SetResource
467 //purpose  : Sets the new value of ExtString resource.
468 //           If the resource does not exist, it is created.
469 //=======================================================================
470 void Resource_Manager::SetResource(const Standard_CString aResource,
471                                    const Standard_ExtString aValue)
472 {
473   Standard_PCharacter pStr;
474   TCollection_AsciiString Resource = aResource;
475   TCollection_ExtendedString ExtValue = aValue;
476   TCollection_AsciiString FormatStr(ExtValue.Length()*3+10, ' ');
477
478   if (!myExtStrMap.Bind(Resource,ExtValue)) {
479     myExtStrMap(Resource) = ExtValue;
480   }
481   //
482   pStr=(Standard_PCharacter)FormatStr.ToCString();
483   //
484   Resource_Unicode::ConvertUnicodeToFormat(ExtValue,
485                                            pStr,//FormatStr.ToCString(),
486                                            FormatStr.Length()) ;
487   SetResource(aResource,FormatStr.ToCString());
488 }
489
490 //=======================================================================
491 //function : SetResource
492 //purpose  : Sets the new value of an enum resource.
493 //           If the resource does not exist, it is created.
494 //=======================================================================
495 void Resource_Manager::SetResource(const Standard_CString aResource,
496                                    const Standard_CString aValue)
497 {
498   TCollection_AsciiString Resource = aResource;
499   TCollection_AsciiString Value = aValue;
500   if (!myUserMap.Bind(Resource, Value))
501     myUserMap(Resource) = Value;
502 }
503
504 //=======================================================================
505 //function : Find
506 //purpose  : Tells if a resource exits.
507 //=======================================================================
508 Standard_Boolean Resource_Manager::Find(const Standard_CString aResource) const
509 {
510   TCollection_AsciiString  Resource(aResource);
511   if (myUserMap.IsBound(Resource) || myRefMap.IsBound(Resource))
512     return Standard_True;
513   return Standard_False;
514 }
515
516 //=======================================================================
517 //function : Find
518 //purpose  :
519 //=======================================================================
520 Standard_Boolean Resource_Manager::Find (const TCollection_AsciiString& theResource,
521                                          TCollection_AsciiString& theValue) const
522 {
523   return myUserMap.Find (theResource, theValue)
524       || myRefMap .Find (theResource, theValue);
525 }
526
527 //=======================================================================
528 //function : GetResourcePath
529 //purpose  : 
530 //=======================================================================
531
532 void Resource_Manager::GetResourcePath (TCollection_AsciiString& aPath, const Standard_CString aName, const Standard_Boolean isUserDefaults)
533 {
534   aPath.Clear();
535
536   TCollection_AsciiString anEnvVar("CSF_");
537   anEnvVar += aName;
538   anEnvVar += isUserDefaults?"UserDefaults":"Defaults";
539
540   TCollection_AsciiString dir;
541   OSD_Environment anEnv(anEnvVar);
542   dir = anEnv.Value();
543   if (dir.IsEmpty())
544     return;
545
546   TCollection_AsciiString aResPath(dir);
547
548   OSD_Path anOSDPath(aResPath);
549
550   if (!anOSDPath.Name().IsEmpty())
551   {
552     anOSDPath.DownTrek (anOSDPath.Name () + anOSDPath.Extension ());
553   }
554   anOSDPath.SetName (aName);
555   anOSDPath.SetExtension ("");
556
557   anOSDPath.SystemName(aPath);
558 }
559
560 //=======================================================================
561 // function : GetMap
562 // purpose  :
563 //=======================================================================
564 Resource_DataMapOfAsciiStringAsciiString& Resource_Manager::GetMap(Standard_Boolean theRefMap)
565 {
566   return theRefMap ? myRefMap : myUserMap;
567 }