Coverage Report

Created: 2025-08-11 08:01

/src/graphicsmagick/magick/locale.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
% Copyright (C) 2003 - 2022 GraphicsMagick Group
3
%
4
% This program is covered by multiple licenses, which are described in
5
% Copyright.txt. You should have received a copy of Copyright.txt with this
6
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
7
%
8
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9
%                                                                             %
10
%                                                                             %
11
%                                                                             %
12
%                  L       OOO    CCCC   AAA   L      EEEEE                   %
13
%                  L      O   O  C      A   A  L      E                       %
14
%                  L      O   O  C      AAAAA  L      EEE                     %
15
%                  L      O   O  C      A   A  L      E                       %
16
%                  LLLLL   OOO    CCCC  A   A  LLLLL  EEEEE                   %
17
%                                                                             %
18
%                                                                             %
19
%                   GraphicsMagick Locale Message Methods                     %
20
%                                                                             %
21
%                                                                             %
22
%                              Software Design                                %
23
%                            William T. Radcliffe                             %
24
%                                 July 2003                                   %
25
%                                                                             %
26
%                                                                             %
27
%                                                                             %
28
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
29
%
30
*/
31
 
32
/*
33
  Include declarations.
34
*/
35
#include "studio.h"
36
#include "utility.h"
37
#define _INCLUDE_CATEGORYMAP_TABLE_
38
#define _INCLUDE_SEVERITYMAP_TABLE_
39
#define _INCLUDE_TAGMAP_TABLE_
40
#if defined(MAGICK_WINDOWS_MESSAGE_TABLES)
41
#  include "spinlock.h"
42
#else
43
#  define _INCLUDE_MESSAGE_TABLE_
44
#endif
45
#include "locale_c.h"
46
 
47
/*
48
  Static declaractions.
49
*/
50
#if defined(MAGICK_WINDOWS_MESSAGE_TABLES)
51
#define MAX_CACHE_SIZE 32
52
53
static char
54
  cache[MaxTextExtent * MAX_CACHE_SIZE];
55
56
static const char *
57
AllocateManagedString(const char *s)
58
{
59
  char
60
    *cs;
61
62
  static int
63
    index = -1;
64
65
  SPINLOCK_WAIT;
66
  index++;
67
  if (index >= MAX_CACHE_SIZE)
68
    index=0;
69
  cs=&cache[MaxTextExtent * index];
70
  (void) strlcpy(cs,s,MaxTextExtent);
71
  SPINLOCK_RELEASE;
72
  return cs;
73
}
74
75
static const char *
76
NTFormatMessage(DWORD id, ...)
77
{
78
  va_list
79
    args;
80
81
  const char
82
    *result;
83
84
  char
85
    temp[MaxTextExtent];
86
87
  HMODULE
88
    handle;
89
90
  int
91
    status;
92
93
  LPVOID
94
    buffer;
95
96
  va_start( args, id );
97
98
  buffer = (LPVOID) NULL; /* stop compiler from complaining */
99
  FormatString(temp,"%.1024s%.1024s%.1024s",SetClientPath((char *) NULL),
100
               DirectorySeparator,SetClientFilename((char *) NULL));
101
  if (IsAccessibleNoLogging(temp))
102
    handle=GetModuleHandle(temp);
103
  else
104
    handle=GetModuleHandle(0);
105
  if (handle)
106
    {
107
      /*
108
        Sample of how to change threads locale explicitly to English.
109
        you can use this same API call to switch locales on a thread
110
        by thread basis and extract the correct localized message
111
      */
112
      /*
113
        SetThreadLocale( MAKELCID( MAKELANGID( 0x0409, SUBLANG_NEUTRAL
114
        ), SORT_DEFAULT ) );
115
      */
116
      status=FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
117
                           FORMAT_MESSAGE_FROM_HMODULE,
118
                           handle,
119
                           id,
120
                           MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
121
                           (LPTSTR) &buffer,
122
                           0,
123
                           &args
124
                           );
125
      if (!status)
126
        {
127
          FormatString(temp,"Undefined message %ld (0x%08lx)",(long) id,
128
                       (long) id);
129
          result=AllocateManagedString(temp);
130
        }
131
      else
132
        {
133
          char
134
            *s;
135
136
          int
137
            len;
138
139
          s = buffer;
140
          len = strlen(s);
141
          if (len > 1)
142
            {
143
              /*
144
                The string that is stored in the resource has a CR LF
145
                on the end, so we need to zap this off before
146
                returning it
147
              */
148
              s[len-1]='\0';
149
              s[len-2]='\0';
150
            }
151
          result=AllocateManagedString(s);
152
          LocalFree(buffer);
153
        }
154
    }
155
  else
156
    {
157
      FormatString(temp,"Undefined message %ld (0x%08lx)",(long) id, (long) id);
158
      result=AllocateManagedString(temp);
159
    }
160
  return(result);
161
}
162
#endif /* defined(MAGICK_WINDOWS_MESSAGE_TABLES) */
163
164
static void
165
ChopLocaleComponents(char *path,const unsigned long components)
166
2.92M
{
167
2.92M
  unsigned long
168
2.92M
    count;
169
170
2.92M
  register char
171
2.92M
    *p;
172
173
2.92M
  if (*path == '\0')
174
0
    return;
175
2.92M
  p=path+strlen(path)-1;
176
2.92M
  if (*p == '/')
177
2.57M
    *p='\0';
178
40.6M
  for (count=0; (count < components) && (p > path); p--)
179
37.7M
    if (*p == '/')
180
3.52M
      {
181
3.52M
        *p='\0';
182
3.52M
        count++;
183
3.52M
      }
184
2.92M
}
185
186
static const char *
187
GetLocaleMessageFromTag(const char *tag)
188
1.70M
{
189
1.70M
#if defined(_INCLUDE_TAGMAP_TABLE_)
190
1.70M
  char
191
1.70M
    category[MaxTextExtent],
192
1.70M
    severity[MaxTextExtent];
193
194
1.70M
  register unsigned int
195
1.70M
    i,
196
1.70M
    j,
197
1.70M
    k;
198
199
1.70M
  (void) strlcpy(category,tag,MaxTextExtent);
200
1.70M
  ChopLocaleComponents(category,2);
201
34.1M
  for (k=0; k < ArraySize(category_map)-1; k++)
202
32.4M
    {
203
32.4M
      if (LocaleCompare(category,category_map[k].name) == 0)
204
1.22M
        {
205
1.22M
          (void) strlcpy(severity,tag,MaxTextExtent);
206
1.22M
          ChopLocaleComponents(severity,1);
207
4.88M
          for (j=category_map[k].offset; j < category_map[k+1].offset; j++)
208
3.66M
            {
209
3.66M
              if (LocaleCompare(severity,severity_map[j].name) == 0)
210
107k
                {
211
3.72M
                  for (i=severity_map[j].offset; i < severity_map[j+1].offset; i++)
212
3.61M
                    {
213
3.61M
                      size_t
214
3.61M
                        prefix,
215
3.61M
                        taglen;
216
217
3.61M
                      prefix=strlen(severity);
218
3.61M
                      taglen=strlen(tag);
219
3.61M
                      if ((prefix > 0) && (prefix < taglen) &&
220
3.61M
                          LocaleCompare(&tag[prefix+1],message_map[i].name) == 0)
221
0
                        {
222
0
#if defined(_INCLUDE_MESSAGE_TABLE_) /* &message_dat[message_dat_offsets[id]] */
223
0
                          return &message_dat[message_dat_offsets[message_map[i].messageid]];
224
#else
225
#  if defined(MAGICK_WINDOWS_MESSAGE_TABLES)
226
                          return &NTFormatMessage(message_dat_offsets[message_map[i].messageid]);
227
#  else
228
                          return tag;
229
#  endif /* defined(MAGICK_WINDOWS_MESSAGE_TABLES) */
230
#endif /* defined(_INCLUDE_MESSAGE_TABLE_) */
231
0
                        }
232
3.61M
                    }
233
107k
                }
234
3.66M
            }
235
1.22M
        }
236
32.4M
    }
237
1.70M
#endif
238
1.70M
  return tag;
239
1.70M
}
240
241
/*
242
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
243
%                                                                             %
244
%                                                                             %
245
%                                                                             %
246
%   G e t L o c a l e M e s s a g e                                           %
247
%                                                                             %
248
%                                                                             %
249
%                                                                             %
250
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
251
%
252
%  GetLocaleMessage() returns a message in the current locale that matches the
253
%  supplied tag.
254
%
255
%  The format of the GetLocaleMessage method is:
256
%
257
%      const char *GetLocaleMessage(const char *tag)
258
%
259
%  A description of each parameter follows:
260
%
261
%    o tag: Return a message that matches this tag in the current locale.
262
%
263
%
264
*/
265
MagickExport const char *
266
GetLocaleMessage(const char *tag)
267
1.70M
{
268
1.70M
  return GetLocaleMessageFromTag(tag);
269
1.70M
}
270
271
/*
272
  This routine translates a severity code to it's string value. It is
273
  slow but the idea is to eventually move away from using strings to
274
  lookup any messages and use binary codes instead.
275
 */
276
#if 0 /* not currently used */
277
static const char *
278
SeverityToTag(const ExceptionType severity)
279
{
280
  register unsigned int
281
    i;
282
283
  for (i=0; (i < ArraySize(severity_map)) && (severity_map[i].name != 0); i++)
284
  {
285
    if (severity == severity_map[i].severityid)
286
      return severity_map[i].name;
287
  }
288
  return("");
289
}
290
291
/*
292
  This routine is intended to be a replacement for
293
  GetLocaleExceptionMessage in the code, but using the data from the
294
  locale MGK files to do it's job rather then some hard coded case
295
  statement.
296
 */
297
static const char *
298
GetLocaleMessageFromSeverityAndTag(const ExceptionType severity,
299
                                   const char *tag)
300
{
301
  char
302
    message[MaxTextExtent];
303
304
  const char
305
    *locale_message;
306
307
  /*
308
    This is a hack that depends on the fact that tag can never have
309
    spaces in them. If a space is found then it means we are being
310
    asked to translate a message that has already been translated. A
311
    big waste of time. The reason this happens is that messages are
312
    translated at the point of an exception and then again when the
313
    exception is caught and processed via the default error and
314
    warning handlers
315
  */
316
  if (strrchr(tag, ' '))
317
    return(tag);
318
  FormatString(message,"%.1024s%.1024s",SeverityToTag(severity),tag);
319
  locale_message=GetLocaleMessage(message);
320
  if (locale_message == message)
321
    return(tag);
322
  return(locale_message);
323
}
324
#endif /* not currently used */
325
326
/*
327
  This routine is used to lookup a message directly from an id pulled
328
  from the header file generated by the coders\local.c header file
329
  coder.
330
 */
331
MagickExport const char *
332
GetLocaleMessageFromID(const int id)
333
2.04M
{
334
2.04M
  if ((id > 0) && (id <= MAX_LOCALE_MSGS))
335
2.04M
    {
336
#if defined(MAGICK_WINDOWS_MESSAGE_TABLES)
337
      return NTFormatMessage(id);
338
#else
339
2.04M
      return &message_dat[message_dat_offsets[id]];
340
2.04M
#endif
341
2.04M
    }
342
0
  return (const char *) NULL;
343
2.04M
}