/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 | } |