153a47686738ac21a83a5215e9630b688eb299cd
[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   Pos = Line.FirstLocationNotInSet(WhiteSpace, Pos2+1, Line.Length());
193   if (Pos) {
194     if (Line.Value(Pos) == '\\')
195       switch(Line.Value(Pos+1)) {
196       case '\\' :
197       case ' '  :
198       case '\t' :
199         Pos++;
200         break;
201       }
202   }
203   if (Pos == Line.Length())
204     aToken2.Clear();
205   else
206     aToken2 = Line.SubString(Pos,Line.Length()-1);
207
208   if (Debug)
209     cout << "'\t Value = '" << aToken2 << "'" << endl << flush;
210   return RESOURCE;
211 }
212
213 // Retourne 0 (EOF) ou une ligne toujours terminee par <NL>.
214
215 static Standard_Integer GetLine(OSD_File& aFile,TCollection_AsciiString& aLine)
216 {
217   TCollection_AsciiString Buffer;
218   Standard_Integer BufSize = 10;
219   Standard_Integer Len;
220
221   aLine.Clear();
222   do {
223     aFile.ReadLine(Buffer,BufSize,Len);
224     aLine += Buffer;
225     if (aFile.IsAtEnd()) {
226       if (!aLine.Length()) return 0;
227       else aLine += "\n";
228     }
229   } while (aLine.Value(aLine.Length()) != '\n');
230
231   return 1;
232 }
233
234 //=======================================================================
235 //function : Save
236 //purpose  : Sort and save the user resources in the user file.
237 //           Creates the file if it does not exist.
238 //=======================================================================
239 Standard_Boolean Resource_Manager::Save() const
240 {
241   Standard_Integer Index;
242   TCollection_AsciiString EnvVar, CSF_ = "CSF_";
243   Standard_CString dir;
244
245   EnvVar = CSF_ + myName + "UserDefaults";
246
247   if ((dir = getenv (EnvVar.ToCString())) == NULL) {
248     if (myVerbose)
249       cout << "Resource Manager Warning: environment variable \""
250            << EnvVar << "\" not set.  Cannot save resources." << endl ;
251     return Standard_False;
252   }
253   TCollection_AsciiString FilePath = dir;
254   OSD_Directory Dir = OSD_Path(FilePath);
255   Standard_Boolean Status = Standard_True;
256   if ( !Dir.Exists() ) {
257     {
258       try {
259         OCC_CATCH_SIGNALS
260         Dir.Build(OSD_Protection(OSD_RX, OSD_RWX, OSD_RX, OSD_RX));
261       }
262       catch (Standard_Failure) {
263         Status = Standard_False;
264       }
265     }
266     Status = Status && !Dir.Failed();
267     if (!Status) {
268       if (myVerbose)
269         cout << "Resource Manager: Error opening or creating directory \"" << FilePath
270              << "\". Permission denied. Cannot save resources." << endl;
271       return Standard_False;
272     }
273   }
274
275   FilePath += "/"; FilePath += myName;
276   OSD_Path Path(FilePath);
277   OSD_File File = Path;
278   OSD_Protection theProt;
279   Status = Standard_True;
280   {
281     try {
282       OCC_CATCH_SIGNALS
283       File.Build(OSD_ReadWrite, theProt);
284     }
285     catch (Standard_Failure) {
286       Status = Standard_False;
287     }
288   }
289   Status = Status && !File.Failed();
290   if (!Status) {
291     if (myVerbose)
292       cout << "Resource Manager: Error opening or creating file \"" << FilePath
293            << "\". Permission denied. Cannot save resources." << endl;
294     return Standard_False;
295   }
296
297   Resource_LexicalCompare Comp;
298   Standard_Integer NbKey = myUserMap.Extent();
299   TColStd_Array1OfAsciiString KeyArray(1,NbKey+1); // 1 more item is added to allow saving empty resource
300   Resource_DataMapIteratorOfDataMapOfAsciiStringAsciiString Iter(myUserMap);
301
302   for ( Index = 1; Iter.More(); Iter.Next())
303     KeyArray(Index++)= Iter.Key();
304
305   Resource_QuickSortOfArray1::Sort(KeyArray, Comp);
306
307   TCollection_AsciiString Line, Value;
308   for (Index = 1 ; Index <= NbKey ; Index++) {
309     Value = myUserMap(KeyArray(Index));
310     if (!Value.IsEmpty())
311       switch(Value.Value(1)) {
312       case '\\' :
313       case ' ' :
314       case '\t' :
315         Value.Insert(1,'\\');
316         break;
317       }
318     Line = KeyArray(Index) + ":\t" + Value + "\n";
319
320     if (Debug)
321       cout << "Line = '" << Line << "'" << endl;
322
323     File.Write(Line, Line.Length());
324   }
325   if (myVerbose)
326     cout << "Resource Manager: Resources saved in file " << FilePath << endl;
327   File.Close();
328   return Standard_True;
329 }
330
331 //=======================================================================
332 //function : Integer
333 //purpose  : Gets the value of an integer resource
334 //=======================================================================
335
336 Standard_Integer Resource_Manager::Integer(const Standard_CString aResourceName) const
337 {
338   TCollection_AsciiString Result = Value(aResourceName) ;
339   if (!Result.IsIntegerValue()) {
340     TCollection_AsciiString n("Value of resource `");
341     n+= aResourceName;
342     n+= "` is not an integer";
343     Standard_TypeMismatch::Raise(n.ToCString());
344   }
345   return Result.IntegerValue();
346 }
347
348 //=======================================================================
349 //function : Real
350 //purpose  : Gets the value of a real resource
351 //=======================================================================
352
353 Standard_Real Resource_Manager::Real(const Standard_CString  aResourceName) const
354 {
355   TCollection_AsciiString Result = Value(aResourceName) ;
356   if (!Result.IsRealValue()) {
357     TCollection_AsciiString n("Value of resource `");
358     n+= aResourceName;
359     n+= "` is not a real";
360     Standard_TypeMismatch::Raise(n.ToCString());
361   }
362   return Result.RealValue();
363 }
364
365 //=======================================================================
366 //function : Value
367 //purpose  : Gets the value of a CString resource
368 //=======================================================================
369
370 Standard_CString Resource_Manager::Value(const Standard_CString aResource) const
371 {
372   TCollection_AsciiString  Resource(aResource);
373   if (myUserMap.IsBound(Resource))
374     return myUserMap(Resource).ToCString();
375   if (myRefMap.IsBound(Resource))
376     return myRefMap(Resource).ToCString();
377   Resource_NoSuchResource::Raise(aResource);
378   return ("");
379 }
380
381 //=======================================================================
382 //function : ExtValue
383 //purpose  : Gets the value of a ExtString resource
384 //=======================================================================
385
386 Standard_ExtString Resource_Manager::ExtValue(const Standard_CString aResource)
387 {
388   TCollection_AsciiString  Resource(aResource);
389   if (myExtStrMap.IsBound(Resource))
390     return myExtStrMap(Resource).ToExtString();
391
392   TCollection_AsciiString Result = Value(aResource);
393   TCollection_ExtendedString ExtResult;
394
395   Resource_Unicode::ConvertFormatToUnicode(Result.ToCString(),ExtResult);
396
397   myExtStrMap.Bind(Resource, ExtResult);
398   return  myExtStrMap(Resource).ToExtString();
399 }
400
401 //=======================================================================
402 //function : SetResource
403 //purpose  : Sets the new value of an integer resource.
404 //           If the resource does not exist, it is created.
405 //=======================================================================
406 void Resource_Manager::SetResource(const Standard_CString aResourceName,
407                                    const Standard_Integer aValue)
408 {
409   SetResource(aResourceName,TCollection_AsciiString(aValue).ToCString());
410 }
411
412 //=======================================================================
413 //function : SetResource
414 //purpose  : Sets the new value of a real resource.
415 //           If the resource does not exist, it is created.
416 //=======================================================================
417 void Resource_Manager::SetResource(const Standard_CString aResourceName,
418                                    const Standard_Real    aValue)
419 {
420   SetResource(aResourceName,TCollection_AsciiString(aValue).ToCString());
421 }
422
423 //=======================================================================
424 //function : SetResource
425 //purpose  : Sets the new value of ExtString resource.
426 //           If the resource does not exist, it is created.
427 //=======================================================================
428 void Resource_Manager::SetResource(const Standard_CString aResource,
429                                    const Standard_ExtString aValue)
430 {
431   Standard_PCharacter pStr;
432   TCollection_AsciiString Resource = aResource;
433   TCollection_ExtendedString ExtValue = aValue;
434   TCollection_AsciiString FormatStr(ExtValue.Length()*3+10, ' ');
435
436   if (!myExtStrMap.Bind(Resource,ExtValue)) {
437     myExtStrMap(Resource) = ExtValue;
438   }
439   //
440   pStr=(Standard_PCharacter)FormatStr.ToCString();
441   //
442   Resource_Unicode::ConvertUnicodeToFormat(ExtValue,
443                                            pStr,//FormatStr.ToCString(),
444                                            FormatStr.Length()) ;
445   SetResource(aResource,FormatStr.ToCString());
446 }
447
448 //=======================================================================
449 //function : SetResource
450 //purpose  : Sets the new value of an enum resource.
451 //           If the resource does not exist, it is created.
452 //=======================================================================
453 void Resource_Manager::SetResource(const Standard_CString aResource,
454                                    const Standard_CString aValue)
455 {
456   TCollection_AsciiString Resource = aResource;
457   TCollection_AsciiString Value = aValue;
458   if (!myUserMap.Bind(Resource, Value))
459     myUserMap(Resource) = Value;
460 }
461
462 //=======================================================================
463 //function : Find
464 //purpose  : Tells if a resource exits.
465 //=======================================================================
466 Standard_Boolean Resource_Manager::Find(const Standard_CString aResource) const
467 {
468   TCollection_AsciiString  Resource(aResource);
469   if (myUserMap.IsBound(Resource) || myRefMap.IsBound(Resource))
470     return Standard_True;
471   return Standard_False;
472 }