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