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