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