summaryrefslogtreecommitdiff
path: root/src/Message/Message_MsgFile.cxx
blob: 7aa228c23257c33277d39fedef4459f53e1e6e6c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
// File:      Message_MsgFile.cxx
// Created:   26.04.01 19:48:39
// Author:    OCC Team
// Copyright: Open CASCADE S.A. 2005

#include <Message_MsgFile.hxx>

#include <TCollection_AsciiString.hxx>
#include <TCollection_ExtendedString.hxx>
#include <NCollection_DefineBaseCollection.hxx>
#include <NCollection_DefineDataMap.hxx>
#include <OSD_Environment.hxx>
#include <stdlib.h>
#include <stdio.h>

DEFINE_BASECOLLECTION(Message_CollectionOfExtendedString, TCollection_ExtendedString)
DEFINE_DATAMAP(Message_DataMapOfExtendedString,
               Message_CollectionOfExtendedString,
               TCollection_AsciiString,
               TCollection_ExtendedString)

static Message_DataMapOfExtendedString& msgsDataMap ()
{
  static Message_DataMapOfExtendedString aDataMap;
  return aDataMap;
}

typedef enum
{
  MsgFile_WaitingKeyword,
  MsgFile_WaitingMessage,
  MsgFile_WaitingMoreMessage,
  MsgFile_Indefinite
} LoadingState;

//=======================================================================
//function : Message_MsgFile
//purpose  : Load file from given directories
//           theDirName may be represented as list: "/dirA/dirB /dirA/dirC"
//=======================================================================

Standard_Boolean Message_MsgFile::Load (const Standard_CString theDirName,
					const Standard_CString theFileName)
{
  if ( ! theDirName || ! theFileName ) return Standard_False;

  Standard_Boolean ret = Standard_True;
  TCollection_AsciiString aDirList (theDirName);
  //  Try to load from all consecutive directories in list
  for (int i = 1;; i++)
  {
    TCollection_AsciiString aFileName = aDirList.Token (" \t\n", i);
    if (aFileName.IsEmpty()) break;
#ifdef WNT
    aFileName += '\\';
#else
    aFileName += '/';
#endif
    aFileName += theFileName;
    if ( ! LoadFile (aFileName.ToCString()) ) 
      ret = Standard_False;
  }
  return ret;
}

//=======================================================================
//function : getString
//purpose  : Takes a TCollection_ExtendedString from Ascii or Unicode
//           Strings are left-trimmed; those beginning with '!' are omitted
//Called   : from loadFile()
//=======================================================================

template <class _Char> static inline Standard_Boolean
getString (_Char *&                     thePtr,
           TCollection_ExtendedString&  theString,
           Standard_Integer&            theLeftSpaces)
{
  _Char * anEndPtr = thePtr;
  _Char * aPtr;
  Standard_Integer aLeftSpaces;

  do 
  {
    //    Skip whitespaces in the beginning of the string
    aPtr = anEndPtr;
    aLeftSpaces = 0;
    while (1)
    {
      _Char aChar = * aPtr;
      if      (aChar == ' ')  aLeftSpaces++;
      else if (aChar == '\t') aLeftSpaces += 8;
      else if (aChar == '\r' || * aPtr == '\n') aLeftSpaces = 0;
      else break;
      aPtr++;
    }

    //    Find the end of the string
    for (anEndPtr = aPtr; * anEndPtr; anEndPtr++)
      if (anEndPtr[0] == '\n')
      {
        if (anEndPtr[-1] == '\r') anEndPtr--;
        break;
      }

  } while (aPtr[0] == '!');

  //    form the result
  if (aPtr == anEndPtr) return Standard_False;
  thePtr = anEndPtr;
  if (*thePtr)
    *thePtr++ = '\0';
  theString = TCollection_ExtendedString (aPtr);
  theLeftSpaces = aLeftSpaces;
  return Standard_True;
}

//=======================================================================
//function : loadFile
//purpose  : Static function, fills the DataMap of Messages from Ascii or Unicode
//Called   : from LoadFile()
//=======================================================================

template <class _Char> static inline Standard_Boolean loadFile (_Char * theBuffer)
{
  TCollection_AsciiString               aKeyword;
  TCollection_ExtendedString            aMessage, aString;
  LoadingState                          aState = MsgFile_WaitingKeyword;
  _Char                                 * sCurrentString = theBuffer;
  Standard_Integer                      aLeftSpaces=0, aFirstLeftSpaces = 0;

  //    Take strings one-by-one; comments already screened
  while (::getString (sCurrentString, aString, aLeftSpaces))
  {
    Standard_Boolean isKeyword = (aString.Value(1) == '.');
    switch (aState)
    {
    case MsgFile_WaitingMoreMessage:
      if (isKeyword)
        Message_MsgFile::AddMsg (aKeyword, aMessage); // terminate the previous one
        //      Pass from here to 'case MsgFile_WaitingKeyword'
      else
      {
        //      Add another line to the message already in the buffer 'aMessage'
        aMessage += '\n';
        aLeftSpaces -= aFirstLeftSpaces;
        if (aLeftSpaces > 0) aMessage += TCollection_ExtendedString (aLeftSpaces, ' ');
        aMessage += aString;
        break;
      }
    case MsgFile_WaitingMessage:
      if (isKeyword == Standard_False)
      {
        aMessage         = aString;
        aFirstLeftSpaces = aLeftSpaces;         // remember the starting position
        aState = MsgFile_WaitingMoreMessage;
        break;
      }
      //      Pass from here to 'case MsgFile_WaitingKeyword'
    case MsgFile_WaitingKeyword:
      if (isKeyword)
      {
        // remove the first dot character and all subsequent spaces + right-trim
        aKeyword = TCollection_AsciiString (aString.Split(1));
        aKeyword.LeftAdjust();
        aKeyword.RightAdjust();
        aState = MsgFile_WaitingMessage;
      }
      break;
    default:
      break;
    }
  }
  //    Process the last string still remaining in the buffer
  if (aState == MsgFile_WaitingMoreMessage)
    Message_MsgFile::AddMsg (aKeyword, aMessage);
  return Standard_True;
}

//=======================================================================
//function : GetFileSize
//purpose  : 
//=======================================================================

static Standard_Integer GetFileSize (FILE *theFile)
{
  if ( !theFile ) return -1;

  // get real file size
  long nRealFileSize = 0;
  if ( fseek(theFile, 0, SEEK_END) != 0 ) return -1;
  nRealFileSize = ftell(theFile);
  if ( fseek(theFile, 0, SEEK_SET) != 0 ) return -1;

  return (Standard_Integer) nRealFileSize;
}

//=======================================================================
//function : LoadFile
//purpose  : Load the list of messages from a file
//=======================================================================

Standard_Boolean Message_MsgFile::LoadFile (const Standard_CString theFileName)
{
  if (theFileName == NULL || * theFileName == '\0') return Standard_False;

  //    Open the file
  FILE *anMsgFile = fopen (theFileName, "rb");
  if (!anMsgFile) return Standard_False;

  //    Read the file into memory
  class Buffer
  {
    // self-destructing buffer
    char *myBuf;
  public:
    Buffer (Standard_Integer theSize) : myBuf(new char [theSize]) {}
    ~Buffer () { delete [] myBuf; }
    operator char* () const { return myBuf; }
    char& operator [] (Standard_Integer theInd) { return myBuf[theInd]; }
  };
  Standard_Integer aFileSize = GetFileSize (anMsgFile);
  if (aFileSize <= 0)
  {
    fclose (anMsgFile);
    return Standard_False;
  }
  Buffer anMsgBuffer (aFileSize + 2);
  Standard_Integer nbRead =
    (Standard_Integer) fread (anMsgBuffer, 1, aFileSize, anMsgFile);
  fclose (anMsgFile);
  if (nbRead != aFileSize)
    return Standard_False;
  anMsgBuffer[aFileSize] = 0;
  anMsgBuffer[aFileSize+1] = 0;

  // Read the messages in the file and append them to the global DataMap
  Standard_Boolean isLittleEndian = (anMsgBuffer[0] == '\xff' && anMsgBuffer[1] == '\xfe');
  Standard_Boolean isBigEndian    = (anMsgBuffer[0] == '\xfe' && anMsgBuffer[1] == '\xff');
  if ( isLittleEndian || isBigEndian )
  {
    Standard_ExtCharacter * aUnicodeBuffer =
      (Standard_ExtCharacter *) &anMsgBuffer[2];
    // Convert Unicode representation to order adopted on current platform
#if defined(__sparc) && defined(__sun)
    if ( isLittleEndian ) 
#else
    if ( isBigEndian ) 
#endif
    {
      // Reverse the bytes throughout the buffer
      for (Standard_ExtCharacter * aPtr = aUnicodeBuffer;
	   aPtr < (Standard_ExtCharacter *) &anMsgBuffer[aFileSize]; aPtr++)
      {
	unsigned short aWord = *aPtr;
	*aPtr = (aWord & 0x00ff) << 8 | (aWord & 0xff00) >> 8;
      }
    }
    return ::loadFile (aUnicodeBuffer);
  }
  else
    return ::loadFile ((char*) anMsgBuffer);
}

//=======================================================================
//function : LoadFromEnv
//purpose  : 
//=======================================================================
void  Message_MsgFile::LoadFromEnv
  (const Standard_CString envname,
   const Standard_CString filename,
   const Standard_CString ext)
{
  Standard_CString extname = ext;
  TCollection_AsciiString extstr;
  if (!extname || extname[0] == '\0') {
    OSD_Environment extenv("CSF_LANGUAGE");
    extstr  = extenv.Value();
    extname = extstr.ToCString();
  }
  if (!extname || extname[0] == '\0') extname = "us";

  TCollection_AsciiString filestr(filename);
  if (envname && envname[0] != '\0') {
    OSD_Environment envenv(envname);
    TCollection_AsciiString envstr  = envenv.Value();
    if (envstr.Length() > 0) {
      if (envstr.Value(envstr.Length()) != '/') filestr.Insert (1,'/');
      filestr.Insert (1,envstr.ToCString());
    }
  }
  if (extname[0] != '.') filestr.AssignCat ('.');
  filestr.AssignCat (extname);

  Message_MsgFile::LoadFile (filestr.ToCString());
}

//=======================================================================
//function : AddMsg
//purpose  : Add one message to the global table. Fails if the same keyword
//           already exists in the table
//=======================================================================

Standard_Boolean Message_MsgFile::AddMsg (const TCollection_AsciiString& theKeyword,
					  const TCollection_ExtendedString&  theMessage)
{
  Message_DataMapOfExtendedString& aDataMap = ::msgsDataMap();
//  if (aDataMap.IsBound (theKeyword))
//    return Standard_False;
  aDataMap.Bind (theKeyword, theMessage);
  return Standard_True;
}

//=======================================================================
//function : getMsg
//purpose  : retrieve the message previously defined for the given keyword
//=======================================================================

const TCollection_ExtendedString &Message_MsgFile::Msg (const Standard_CString theKeyword)
{
  TCollection_AsciiString aKey((char*)theKeyword);
  return Msg (aKey);
} 

//=======================================================================
//function : getMsg
//purpose  : retrieve the message previously defined for the given keyword
//=======================================================================

const TCollection_ExtendedString &Message_MsgFile::Msg (const TCollection_AsciiString& theKeyword)
{
  // find message in the map
  Message_DataMapOfExtendedString& aDataMap = ::msgsDataMap();
  if (aDataMap.IsBound (theKeyword))
    return aDataMap.Find (theKeyword);

  // if not found, generate error message
  static const TCollection_ExtendedString aDefPrefix ("Unknown message invoked with the keyword: ");
  static const TCollection_AsciiString aPrefixCode ("Message_Msg_BadKeyword");
  static TCollection_ExtendedString aFailureMessage;
  if (aDataMap.IsBound (aPrefixCode))
    aFailureMessage = aDataMap.Find (aPrefixCode) + " " + theKeyword;
  else aFailureMessage = aDefPrefix + theKeyword;
  return aFailureMessage;
}