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