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