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