0023909: FPE in BSplSLib::RationalDerivative
[occt.git] / src / Resource / Resource_Manager.cxx
1 // Copyright (c) 1998-1999 Matra Datavision
2 // Copyright (c) 1999-2012 OPEN CASCADE SAS
3 //
4 // The content of this file is subject to the Open CASCADE Technology Public
5 // License Version 6.5 (the "License"). You may not use the content of this file
6 // except in compliance with the License. Please obtain a copy of the License
7 // at http://www.opencascade.org and read it completely before using this file.
8 //
9 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
10 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
11 //
12 // The Original Code and all software distributed under the License is
13 // distributed on an "AS IS" basis, without warranty of any kind, and the
14 // Initial Developer hereby disclaims all such warranties, including without
15 // limitation, any warranties of merchantability, fitness for a particular
16 // purpose or non-infringement. Please see the License for the specific terms
17 // and conditions governing the rights and limitations under the License.
18
19 #include <Resource_Manager.hxx>
20 #include <Resource_Manager.ixx>
21 #include <Resource_DataMapIteratorOfDataMapOfAsciiStringAsciiString.hxx>
22 #include <Resource_QuickSortOfArray1.hxx>
23 #include <Resource_LexicalCompare.hxx>
24
25 #include <OSD_Path.hxx>
26 #include <OSD_File.hxx>
27 #include <OSD_Directory.hxx>
28 #include <OSD_Protection.hxx>
29
30 #include <Standard_ErrorHandler.hxx>
31 #include <TCollection_ExtendedString.hxx>
32 #include <Resource_Unicode.hxx>
33 #include <TColStd_Array1OfAsciiString.hxx>
34
35 #include <errno.h>
36
37 #define END      0
38 #define EMPTY    1
39 #define COMMENT  2
40 #define INCLUDE  3
41 #define RESOURCE 4
42 #define ERROR   -1
43
44 static Standard_Integer WhatKindOfLine(OSD_File& aFile,
45                                        TCollection_AsciiString& aToken1,
46                                        TCollection_AsciiString& aToken2);
47
48 static Standard_Integer GetLine(OSD_File& aFile,TCollection_AsciiString& aLine);
49
50 static Standard_Boolean Debug;
51
52 Resource_Manager::Resource_Manager(const Standard_CString aName,
53                                    TCollection_AsciiString& aDefaultsDirectory,
54                                    TCollection_AsciiString& anUserDefaultsDirectory,
55                                    const Standard_Boolean Verbose) : myName(aName), myVerbose(Verbose)
56 {
57   if ( !aDefaultsDirectory.IsEmpty() ) {
58     Load(aDefaultsDirectory,myName,myRefMap);
59   }
60   else
61     if (myVerbose)
62       cout << "Resource Manager Warning: aDefaultsDirectory is empty." << endl;
63
64   if ( !anUserDefaultsDirectory.IsEmpty() ) {
65     Load(anUserDefaultsDirectory,myName,myRefMap);
66   }
67   else
68     if (myVerbose)
69       cout << "Resource Manager Warning: anUserDefaultsDirectory is empty." << endl;
70 }
71
72 Resource_Manager::Resource_Manager(const Standard_CString aName,
73                                    const Standard_Boolean Verbose) : myName(aName), myVerbose(Verbose)
74 {
75   Debug = (getenv("ResourceDebug") != NULL) ;
76
77   TCollection_AsciiString EnvVar, CSF_ = "CSF_" ;
78   TCollection_AsciiString Directory ;
79   Standard_CString dir ;
80
81   if ( getenv ("CSF_ResourceVerbose") != NULL )
82     myVerbose = Standard_True;
83
84   EnvVar = CSF_ + aName + "Defaults" ;
85   if ((dir = getenv (EnvVar.ToCString())) != NULL) {
86     Directory = dir;
87     Load(Directory,myName,myRefMap);
88   }
89   else
90     if (myVerbose)
91       cout << "Resource Manager Warning: Environment variable \"" << EnvVar
92            << "\" not set." << endl;
93
94   EnvVar = CSF_ + aName + "UserDefaults" ;
95   if ((dir = getenv (EnvVar.ToCString())) != NULL) {
96     Directory = dir;
97     Load(Directory, myName, myUserMap);
98   }
99   else
100     if (myVerbose)
101       cout << "Resource Manager Warning: Environment variable \"" << EnvVar
102            << "\" not set." << endl;
103 }
104
105 void Resource_Manager::Load(TCollection_AsciiString& aDirectory,
106                             TCollection_AsciiString& aName,
107                             Resource_DataMapOfAsciiStringAsciiString& aMap)
108 {
109   Standard_Integer Kind, Pos;
110   TCollection_AsciiString Token1, Token2;
111   TCollection_AsciiString Directory, Name;
112   TCollection_AsciiString FileName;
113   FileName =  aDirectory + "/" + aName;
114   OSD_File File = OSD_Path(FileName);
115   File.Open(OSD_ReadOnly,OSD_Protection());
116   if (File.Failed()) {
117     if (myVerbose)
118       cout << "Resource Manager Warning: Cannot read file \"" << FileName
119            << "\". File not found or permission denied." << endl;
120     return;
121   }
122   Standard_Integer LineNumber = 1;
123   while ((Kind = WhatKindOfLine(File, Token1, Token2)) != END) {
124     switch (Kind) {
125     case COMMENT :
126     case EMPTY :
127       break ;
128     case INCLUDE :
129       Directory = OSD_Path::AbsolutePath(aDirectory,Token1);
130       Pos = Directory.SearchFromEnd("/");
131       if (Pos != 0) {
132         Name = Directory.Split(Pos);
133         Directory.Trunc(Pos-1);
134         Load(Directory,Name,aMap);
135       }
136       break;
137     case RESOURCE :
138       if (!aMap.Bind(Token1,Token2))
139         aMap(Token1) = Token2;
140       break;
141     case ERROR :
142       if (myVerbose)
143         cout << "Resource Manager: Syntax error at line "
144           << LineNumber << " in file : " << FileName << endl;
145       break;
146     }
147     LineNumber++;
148   }
149   File.Close();
150   if (myVerbose)
151     cout << "Resource Manager: " << ((&aMap == &myUserMap) ? "User" : "Reference")
152          << " file \"" << FileName << "\" loaded" << endl;
153 }
154
155 static Standard_Integer WhatKindOfLine(OSD_File& aFile,
156                                        TCollection_AsciiString& aToken1,
157                                        TCollection_AsciiString& aToken2)
158 {
159   TCollection_AsciiString WhiteSpace = " \t" ;
160   Standard_Integer Pos1,Pos2,Pos ;
161   TCollection_AsciiString Line ;
162
163   if (!GetLine(aFile,Line))
164     return END;
165
166   if (Line.Value(1) == '!')
167     return COMMENT;
168
169   if (Line.Value(1) == '#') {
170     Line.Remove(1);
171     if ((Line.Token(" \t")).IsDifferent("include"))
172       return ERROR;
173
174     aToken1 = Line.Token(" \t\n",2);
175     return INCLUDE;
176   }
177
178   Pos1 = Line.FirstLocationNotInSet(WhiteSpace, 1, Line.Length());
179   if (Line.Value(Pos1) == '\n')
180     return EMPTY;
181
182   Pos2 = Line.Location(1,':',Pos1,Line.Length());
183   if (!Pos2 || Pos1 == Pos2)
184     return ERROR;
185
186   for (Pos = Pos2-1; Line.Value(Pos) == '\t' || Line.Value(Pos) == ' ' ; Pos--);
187   aToken1 = Line.SubString(Pos1, Pos);
188
189   if (Debug)
190     cout << "Key = '" << aToken1 << flush ;
191
192   if ((Pos = Line.FirstLocationNotInSet(WhiteSpace, Pos2+1, Line.Length()))) {
193     if (Line.Value(Pos) == '\\')
194       switch(Line.Value(Pos+1)) {
195       case '\\' :
196       case ' '  :
197       case '\t' :
198         Pos++;
199         break;
200       }
201   }
202   if (Pos == Line.Length())
203     aToken2.Clear();
204   else
205     aToken2 = Line.SubString(Pos,Line.Length()-1);
206
207   if (Debug)
208     cout << "'\t Value = '" << aToken2 << "'" << endl << flush;
209   return RESOURCE;
210 }
211
212 // Retourne 0 (EOF) ou une ligne toujours terminee par <NL>.
213
214 static Standard_Integer GetLine(OSD_File& aFile,TCollection_AsciiString& aLine)
215 {
216   TCollection_AsciiString Buffer;
217   Standard_Integer BufSize = 10;
218   Standard_Integer Len;
219
220   aLine.Clear();
221   do {
222     aFile.ReadLine(Buffer,BufSize,Len);
223     aLine += Buffer;
224     if (aFile.IsAtEnd())
225       if (!aLine.Length()) return 0;
226       else aLine += "\n";
227   } while (aLine.Value(aLine.Length()) != '\n');
228
229   return 1;
230 }
231
232 //=======================================================================
233 //function : Save
234 //purpose  : Sort and save the user resources in the user file.
235 //           Creates the file if it does not exist.
236 //=======================================================================
237 Standard_Boolean Resource_Manager::Save() const
238 {
239   Standard_Integer Index;
240   TCollection_AsciiString EnvVar, CSF_ = "CSF_";
241   Standard_CString dir;
242
243   EnvVar = CSF_ + myName + "UserDefaults";
244
245   if ((dir = getenv (EnvVar.ToCString())) == NULL) {
246     if (myVerbose)
247       cout << "Resource Manager Warning: environment variable \""
248            << EnvVar << "\" not set.  Cannot save resources." << endl ;
249     return Standard_False;
250   }
251   TCollection_AsciiString FilePath = dir;
252   OSD_Directory Dir = OSD_Path(FilePath);
253   Standard_Boolean Status = Standard_True;
254   if ( !Dir.Exists() ) {
255     {
256       try {
257         OCC_CATCH_SIGNALS
258         Dir.Build(OSD_Protection(OSD_RX, OSD_RWX, OSD_RX, OSD_RX));
259       }
260       catch (Standard_Failure) {
261         Status = Standard_False;
262       }
263     }
264     Status = Status && !Dir.Failed();
265     if (!Status) {
266       if (myVerbose)
267         cout << "Resource Manager: Error opening or creating directory \"" << FilePath
268              << "\". Permission denied. Cannot save resources." << endl;
269       return Standard_False;
270     }
271   }
272
273   FilePath += "/"; FilePath += myName;
274   OSD_Path Path(FilePath);
275   OSD_File File = Path;
276   OSD_Protection theProt;
277   Status = Standard_True;
278   {
279     try {
280       OCC_CATCH_SIGNALS
281       File.Build(OSD_ReadWrite, theProt);
282     }
283     catch (Standard_Failure) {
284       Status = Standard_False;
285     }
286   }
287   Status = Status && !File.Failed();
288   if (!Status) {
289     if (myVerbose)
290       cout << "Resource Manager: Error opening or creating file \"" << FilePath
291            << "\". Permission denied. Cannot save resources." << endl;
292     return Standard_False;
293   }
294
295   Resource_LexicalCompare Comp;
296   Standard_Integer NbKey = myUserMap.Extent();
297   TColStd_Array1OfAsciiString KeyArray(1,NbKey+1); // 1 more item is added to allow saving empty resource
298   Resource_DataMapIteratorOfDataMapOfAsciiStringAsciiString Iter(myUserMap);
299
300   for ( Index = 1; Iter.More(); Iter.Next())
301     KeyArray(Index++)= Iter.Key();
302
303   Resource_QuickSortOfArray1::Sort(KeyArray, Comp);
304
305   TCollection_AsciiString Line, Value;
306   for (Index = 1 ; Index <= NbKey ; Index++) {
307     Value = myUserMap(KeyArray(Index));
308     if (!Value.IsEmpty())
309       switch(Value.Value(1)) {
310       case '\\' :
311       case ' ' :
312       case '\t' :
313         Value.Insert(1,'\\');
314         break;
315       }
316     Line = KeyArray(Index) + ":\t" + Value + "\n";
317
318     if (Debug)
319       cout << "Line = '" << Line << "'" << endl;
320
321     File.Write(Line, Line.Length());
322   }
323   if (myVerbose)
324     cout << "Resource Manager: Resources saved in file " << FilePath << endl;
325   File.Close();
326   return Standard_True;
327 }
328
329 //=======================================================================
330 //function : Integer
331 //purpose  : Gets the value of an integer resource
332 //=======================================================================
333
334 Standard_Integer Resource_Manager::Integer(const Standard_CString aResourceName) const
335 {
336   TCollection_AsciiString Result = Value(aResourceName) ;
337   if (!Result.IsIntegerValue()) {
338     TCollection_AsciiString n("Value of resource `");
339     n+= aResourceName;
340     n+= "` is not an integer";
341     Standard_TypeMismatch::Raise(n.ToCString());
342   }
343   return Result.IntegerValue();
344 }
345
346 //=======================================================================
347 //function : Real
348 //purpose  : Gets the value of a real resource
349 //=======================================================================
350
351 Standard_Real Resource_Manager::Real(const Standard_CString  aResourceName) const
352 {
353   TCollection_AsciiString Result = Value(aResourceName) ;
354   if (!Result.IsRealValue()) {
355     TCollection_AsciiString n("Value of resource `");
356     n+= aResourceName;
357     n+= "` is not a real";
358     Standard_TypeMismatch::Raise(n.ToCString());
359   }
360   return Result.RealValue();
361 }
362
363 //=======================================================================
364 //function : Value
365 //purpose  : Gets the value of a CString resource
366 //=======================================================================
367
368 Standard_CString Resource_Manager::Value(const Standard_CString aResource) const
369 {
370   TCollection_AsciiString  Resource(aResource);
371   if (myUserMap.IsBound(Resource))
372     return myUserMap(Resource).ToCString();
373   if (myRefMap.IsBound(Resource))
374     return myRefMap(Resource).ToCString();
375   Resource_NoSuchResource::Raise(aResource);
376   return ("");
377 }
378
379 //=======================================================================
380 //function : ExtValue
381 //purpose  : Gets the value of a ExtString resource
382 //=======================================================================
383
384 Standard_ExtString Resource_Manager::ExtValue(const Standard_CString aResource)
385 {
386   TCollection_AsciiString  Resource(aResource);
387   if (myExtStrMap.IsBound(Resource))
388     return myExtStrMap(Resource).ToExtString();
389
390   TCollection_AsciiString Result = Value(aResource);
391   TCollection_ExtendedString ExtResult;
392
393   Resource_Unicode::ConvertFormatToUnicode(Result.ToCString(),ExtResult);
394
395   myExtStrMap.Bind(Resource, ExtResult);
396   return  myExtStrMap(Resource).ToExtString();
397 }
398
399 //=======================================================================
400 //function : SetResource
401 //purpose  : Sets the new value of an integer resource.
402 //           If the resource does not exist, it is created.
403 //=======================================================================
404 void Resource_Manager::SetResource(const Standard_CString aResourceName,
405                                    const Standard_Integer aValue)
406 {
407   SetResource(aResourceName,TCollection_AsciiString(aValue).ToCString());
408 }
409
410 //=======================================================================
411 //function : SetResource
412 //purpose  : Sets the new value of a real resource.
413 //           If the resource does not exist, it is created.
414 //=======================================================================
415 void Resource_Manager::SetResource(const Standard_CString aResourceName,
416                                    const Standard_Real    aValue)
417 {
418   SetResource(aResourceName,TCollection_AsciiString(aValue).ToCString());
419 }
420
421 //=======================================================================
422 //function : SetResource
423 //purpose  : Sets the new value of ExtString resource.
424 //           If the resource does not exist, it is created.
425 //=======================================================================
426 void Resource_Manager::SetResource(const Standard_CString aResource,
427                                    const Standard_ExtString aValue)
428 {
429   Standard_PCharacter pStr;
430   TCollection_AsciiString Resource = aResource;
431   TCollection_ExtendedString ExtValue = aValue;
432   TCollection_AsciiString FormatStr(ExtValue.Length()*3+10, ' ');
433
434   if (!myExtStrMap.Bind(Resource,ExtValue)) {
435     myExtStrMap(Resource) = ExtValue;
436   }
437   //
438   pStr=(Standard_PCharacter)FormatStr.ToCString();
439   //
440   Resource_Unicode::ConvertUnicodeToFormat(ExtValue,
441                                            pStr,//FormatStr.ToCString(),
442                                            FormatStr.Length()) ;
443   SetResource(aResource,FormatStr.ToCString());
444 }
445
446 //=======================================================================
447 //function : SetResource
448 //purpose  : Sets the new value of an enum resource.
449 //           If the resource does not exist, it is created.
450 //=======================================================================
451 void Resource_Manager::SetResource(const Standard_CString aResource,
452                                    const Standard_CString aValue)
453 {
454   TCollection_AsciiString Resource = aResource;
455   TCollection_AsciiString Value = aValue;
456   if (!myUserMap.Bind(Resource, Value))
457     myUserMap(Resource) = Value;
458 }
459
460 //=======================================================================
461 //function : Find
462 //purpose  : Tells if a resource exits.
463 //=======================================================================
464 Standard_Boolean Resource_Manager::Find(const Standard_CString aResource) const
465 {
466   TCollection_AsciiString  Resource(aResource);
467   if (myUserMap.IsBound(Resource) || myRefMap.IsBound(Resource))
468     return Standard_True;
469   return Standard_False;
470 }