0029352: Adding support of GBK and Big5 code pages
[occt.git] / src / Resource / Resource_Manager.cxx
CommitLineData
b311480e 1// Copyright (c) 1998-1999 Matra Datavision
973c2be1 2// Copyright (c) 1999-2014 OPEN CASCADE SAS
b311480e 3//
973c2be1 4// This file is part of Open CASCADE Technology software library.
b311480e 5//
d5f74e42 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
973c2be1 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.
b311480e 11//
973c2be1 12// Alternatively, this file may be used under the terms of Open CASCADE
13// commercial license or contractual agreement.
b311480e 14
7fd59977 15
7fd59977 16#include <OSD_Directory.hxx>
742cc8b0 17#include <OSD_Environment.hxx>
42cf5bc1 18#include <OSD_File.hxx>
19#include <OSD_Path.hxx>
7fd59977 20#include <OSD_Protection.hxx>
42cf5bc1 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>
7fd59977 26#include <Standard_ErrorHandler.hxx>
42cf5bc1 27#include <Standard_OutOfRange.hxx>
28#include <Standard_Type.hxx>
29#include <Standard_TypeMismatch.hxx>
30#include <TCollection_AsciiString.hxx>
7fd59977 31#include <TCollection_ExtendedString.hxx>
7fd59977 32#include <TColStd_Array1OfAsciiString.hxx>
33
e35db416 34#include <algorithm>
42cf5bc1 35#include <errno.h>
7fd59977 36
25e59720 37IMPLEMENT_STANDARD_RTTIEXT(Resource_Manager,Standard_Transient)
92efcf78 38
969d1caf 39//! Auxiliary enumeration for function WhatKindOfLine().
40enum 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
49static Resource_KindOfLine WhatKindOfLine(OSD_File& aFile,
7fd59977 50 TCollection_AsciiString& aToken1,
51 TCollection_AsciiString& aToken2);
52
53static Standard_Integer GetLine(OSD_File& aFile,TCollection_AsciiString& aLine);
54
55static Standard_Boolean Debug;
56
57Resource_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() ) {
b6d779d9 63 OSD_Path anOSDPath(aDefaultsDirectory);
f9ac4dc9 64 if (!anOSDPath.Name().IsEmpty())
65 {
66 anOSDPath.DownTrek (anOSDPath.Name () + anOSDPath.Extension ());
67 }
b6d779d9 68 anOSDPath.SetName(aName);
f9ac4dc9 69 anOSDPath.SetExtension("");
b6d779d9 70 TCollection_AsciiString aPath;
71 anOSDPath.SystemName(aPath);
72 Load(aPath,myRefMap);
7fd59977 73 }
74 else
75 if (myVerbose)
76 cout << "Resource Manager Warning: aDefaultsDirectory is empty." << endl;
77
78 if ( !anUserDefaultsDirectory.IsEmpty() ) {
b6d779d9 79 OSD_Path anOSDPath(anUserDefaultsDirectory);
f9ac4dc9 80 if (!anOSDPath.Name().IsEmpty())
81 {
82 anOSDPath.DownTrek (anOSDPath.Name () + anOSDPath.Extension ());
83 }
b6d779d9 84 anOSDPath.SetName(aName);
f9ac4dc9 85 anOSDPath.SetExtension("");
b6d779d9 86 TCollection_AsciiString aPath;
87 anOSDPath.SystemName(aPath);
88 Load(aPath,myRefMap);
7fd59977 89 }
90 else
91 if (myVerbose)
92 cout << "Resource Manager Warning: anUserDefaultsDirectory is empty." << endl;
93}
94
95Resource_Manager::Resource_Manager(const Standard_CString aName,
96 const Standard_Boolean Verbose) : myName(aName), myVerbose(Verbose)
97{
742cc8b0 98 OSD_Environment envDebug("ResourceDebug");
99 Debug = (!envDebug.Value().IsEmpty()) ;
7fd59977 100
7fd59977 101 TCollection_AsciiString Directory ;
7fd59977 102
742cc8b0 103 OSD_Environment envVerbose("CSF_ResourceVerbose");
104 if (!envVerbose.Value().IsEmpty())
7fd59977 105 myVerbose = Standard_True;
106
b6d779d9 107 TCollection_AsciiString aPath,aUserPath;
108 GetResourcePath(aPath,aName,Standard_False);
109 GetResourcePath(aUserPath,aName,Standard_True);
7fd59977 110
b6d779d9 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;
7fd59977 120}
121
b6d779d9 122void Resource_Manager::Load(TCollection_AsciiString& aPath,
123 Resource_DataMapOfAsciiStringAsciiString& aMap)
7fd59977 124{
969d1caf 125 Resource_KindOfLine aKind;
7fd59977 126 TCollection_AsciiString Token1, Token2;
a1530ab1
BB
127 OSD_Path Path(aPath);
128 OSD_File File = Path;
129 TCollection_AsciiString FileName = Path.Name();
7fd59977 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;
969d1caf 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:
7fd59977 143 break ;
969d1caf 144 case Resource_KOL_Resource:
7fd59977 145 if (!aMap.Bind(Token1,Token2))
146 aMap(Token1) = Token2;
147 break;
969d1caf 148 case Resource_KOL_Error:
7fd59977 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
969d1caf 162static Resource_KindOfLine WhatKindOfLine(OSD_File& aFile,
7fd59977 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))
969d1caf 171 return Resource_KOL_End;
7fd59977 172
173 if (Line.Value(1) == '!')
969d1caf 174 return Resource_KOL_Comment;
7fd59977 175
7fd59977 176 Pos1 = Line.FirstLocationNotInSet(WhiteSpace, 1, Line.Length());
177 if (Line.Value(Pos1) == '\n')
969d1caf 178 return Resource_KOL_Empty;
7fd59977 179
180 Pos2 = Line.Location(1,':',Pos1,Line.Length());
181 if (!Pos2 || Pos1 == Pos2)
969d1caf 182 return Resource_KOL_Error;
7fd59977 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
302f96fb 190 Pos = Line.FirstLocationNotInSet(WhiteSpace, Pos2+1, Line.Length());
191 if (Pos) {
7fd59977 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();
bcf50875 203 else {
204 Line.Remove(1,Pos-1);
205 Line.Remove(Line.Length());
206 aToken2 = Line;
207 }
7fd59977 208 if (Debug)
209 cout << "'\t Value = '" << aToken2 << "'" << endl << flush;
969d1caf 210 return Resource_KOL_Resource;
7fd59977 211}
212
213// Retourne 0 (EOF) ou une ligne toujours terminee par <NL>.
214
215static 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;
eafb234b 225 if (aFile.IsAtEnd()) {
7fd59977 226 if (!aLine.Length()) return 0;
227 else aLine += "\n";
eafb234b 228 }
7fd59977 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//=======================================================================
239Standard_Boolean Resource_Manager::Save() const
240{
b6d779d9 241 TCollection_AsciiString anEnvVar("CSF_");
242 anEnvVar += myName;
243 anEnvVar += "UserDefaults";
7fd59977 244
742cc8b0 245 TCollection_AsciiString dir;
246 OSD_Environment anEnv(anEnvVar);
247 dir = anEnv.Value();
248 if (dir.IsEmpty()) {
7fd59977 249 if (myVerbose)
250 cout << "Resource Manager Warning: environment variable \""
b6d779d9 251 << anEnvVar << "\" not set. Cannot save resources." << endl ;
7fd59977 252 return Standard_False;
253 }
b6d779d9 254
255 TCollection_AsciiString aFilePath(dir);
256 OSD_Path anOSDPath(aFilePath);
257 OSD_Directory Dir = anOSDPath;
9fd2d2c3 258 Standard_Boolean aStatus = Standard_True;
7fd59977 259 if ( !Dir.Exists() ) {
260 {
261 try {
262 OCC_CATCH_SIGNALS
73594f72 263 Dir.Build(OSD_Protection(OSD_RX, OSD_RWXD, OSD_RX, OSD_RX));
7fd59977 264 }
265 catch (Standard_Failure) {
9fd2d2c3 266 aStatus = Standard_False;
7fd59977 267 }
268 }
9fd2d2c3 269 aStatus = aStatus && !Dir.Failed();
270 if (!aStatus) {
7fd59977 271 if (myVerbose)
b6d779d9 272 cout << "Resource Manager: Error opening or creating directory \"" << aFilePath
273 << "\". Permission denied. Cannot save resources." << endl;
7fd59977 274 return Standard_False;
275 }
276 }
277
f9ac4dc9 278 if (!anOSDPath.Name().IsEmpty())
279 {
280 anOSDPath.DownTrek (anOSDPath.Name () + anOSDPath.Extension ());
281 }
b6d779d9 282 anOSDPath.SetName(myName);
f9ac4dc9 283 anOSDPath.SetExtension("");
b6d779d9 284 anOSDPath.SystemName(aFilePath);
285
286 OSD_File File = anOSDPath;
7fd59977 287 OSD_Protection theProt;
9fd2d2c3 288 aStatus = Standard_True;
7fd59977 289 {
290 try {
291 OCC_CATCH_SIGNALS
292 File.Build(OSD_ReadWrite, theProt);
293 }
294 catch (Standard_Failure) {
9fd2d2c3 295 aStatus = Standard_False;
7fd59977 296 }
297 }
9fd2d2c3 298 aStatus = aStatus && !File.Failed();
299 if (!aStatus) {
7fd59977 300 if (myVerbose)
b6d779d9 301 cout << "Resource Manager: Error opening or creating file \"" << aFilePath
7fd59977 302 << "\". Permission denied. Cannot save resources." << endl;
303 return Standard_False;
304 }
305
b6d779d9 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
e35db416 316 std::sort (KeyArray.begin(), KeyArray.end());
b6d779d9 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;
7fd59977 338 }
7fd59977 339 File.Close();
340 return Standard_True;
341}
342
343//=======================================================================
344//function : Integer
345//purpose : Gets the value of an integer resource
346//=======================================================================
347
348Standard_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";
9775fa61 355 throw Standard_TypeMismatch(n.ToCString());
7fd59977 356 }
357 return Result.IntegerValue();
358}
359
360//=======================================================================
361//function : Real
362//purpose : Gets the value of a real resource
363//=======================================================================
364
365Standard_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";
9775fa61 372 throw Standard_TypeMismatch(n.ToCString());
7fd59977 373 }
374 return Result.RealValue();
375}
376
377//=======================================================================
378//function : Value
379//purpose : Gets the value of a CString resource
380//=======================================================================
381
382Standard_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();
9775fa61 389 throw Resource_NoSuchResource(aResource);
7fd59977 390}
391
392//=======================================================================
393//function : ExtValue
394//purpose : Gets the value of a ExtString resource
395//=======================================================================
396
397Standard_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//=======================================================================
417void 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//=======================================================================
428void 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//=======================================================================
439void 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//=======================================================================
464void 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//=======================================================================
477Standard_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}
b6d779d9 484
485//=======================================================================
486//function : GetResourcePath
487//purpose :
488//=======================================================================
489
490void 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
742cc8b0 498 TCollection_AsciiString dir;
499 OSD_Environment anEnv(anEnvVar);
500 dir = anEnv.Value();
501 if (dir.IsEmpty())
b6d779d9 502 return;
503
504 TCollection_AsciiString aResPath(dir);
505
506 OSD_Path anOSDPath(aResPath);
a1530ab1
BB
507
508 if (!anOSDPath.Name().IsEmpty())
509 {
f9ac4dc9 510 anOSDPath.DownTrek (anOSDPath.Name () + anOSDPath.Extension ());
a1530ab1 511 }
f9ac4dc9 512 anOSDPath.SetName (aName);
513 anOSDPath.SetExtension ("");
b6d779d9 514
515 anOSDPath.SystemName(aPath);
42cf5bc1 516}