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