1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % L OOO CCCC AAA L EEEEE %
7 % L O O C A A L E %
8 % L O O C AAAAA L EEE %
9 % L O O C A A L E %
10 % LLLLL OOO CCCC A A LLLLL EEEEE %
11 % %
12 % %
13 % MagickCore Image Locale Methods %
14 % %
15 % Software Design %
16 % Cristy %
17 % July 2003 %
18 % %
19 % %
20 % Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % https://imagemagick.org/script/license.php %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38
39 /*
40 Include declarations.
41 */
42 #include "magick/studio.h"
43 #include "magick/blob.h"
44 #include "magick/client.h"
45 #include "magick/configure.h"
46 #include "magick/exception.h"
47 #include "magick/exception-private.h"
48 #include "magick/hashmap.h"
49 #include "magick/image-private.h"
50 #include "magick/locale_.h"
51 #include "magick/log.h"
52 #include "magick/memory_.h"
53 #include "magick/nt-base-private.h"
54 #include "magick/semaphore.h"
55 #include "magick/splay-tree.h"
56 #include "magick/string_.h"
57 #include "magick/token.h"
58 #include "magick/utility.h"
59 #include "magick/xml-tree.h"
60 #include "magick/xml-tree-private.h"
61
62 /*
63 Define declarations.
64 */
65 #if (defined(MAGICKCORE_HAVE_NEWLOCALE) || defined(MAGICKCORE_WINDOWS_SUPPORT)) && !defined(__MINGW32__)
66 # define MAGICKCORE_LOCALE_SUPPORT
67 #endif
68 #define LocaleFilename "locale.xml"
69 #define MaxRecursionDepth 200
70
71 /*
72 Static declarations.
73 */
74 static const char
75 *LocaleMap =
76 "<?xml version=\"1.0\"?>"
77 "<localemap>"
78 " <locale name=\"C\">"
79 " <Exception>"
80 " <Message name=\"\">"
81 " </Message>"
82 " </Exception>"
83 " </locale>"
84 "</localemap>";
85
86 #ifdef __VMS
87 #define asciimap AsciiMap
88 #endif
89 #if !defined(MAGICKCORE_HAVE_STRCASECMP) || !defined(MAGICKCORE_HAVE_STRNCASECMP)
90 static const unsigned char
91 AsciiMap[] =
92 {
93 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
94 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
95 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
96 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
97 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
98 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
99 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73,
100 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
101 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
102 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
103 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
104 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
105 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
106 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
107 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,
108 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
109 0xc0, 0xe1, 0xe2, 0xe3, 0xe4, 0xc5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb,
110 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
111 0xf8, 0xf9, 0xfa, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3,
112 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
113 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb,
114 0xfc, 0xfd, 0xfe, 0xff,
115 };
116 #endif
117
118 static SemaphoreInfo
119 *locale_semaphore = (SemaphoreInfo *) NULL;
120
121 static SplayTreeInfo
122 *locale_cache = (SplayTreeInfo *) NULL;
123
124 #if defined(MAGICKCORE_LOCALE_SUPPORT)
125 static volatile locale_t
126 c_locale = (locale_t) NULL;
127 #endif
128
129 /*
130 Forward declarations.
131 */
132 static MagickBooleanType
133 IsLocaleTreeInstantiated(ExceptionInfo *),
134 LoadLocaleCache(SplayTreeInfo *,const char *,const char *,const char *,
135 const size_t,ExceptionInfo *);
136
137 #if defined(MAGICKCORE_LOCALE_SUPPORT)
138 /*
139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
140 % %
141 % %
142 % %
143 + A c q u i r e C L o c a l e %
144 % %
145 % %
146 % %
147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
148 %
149 % AcquireCLocale() allocates the C locale object, or (locale_t) 0 with
150 % errno set if it cannot be acquired.
151 %
152 % The format of the AcquireCLocale method is:
153 %
154 % locale_t AcquireCLocale(void)
155 %
156 */
AcquireCLocale(void)157 static locale_t AcquireCLocale(void)
158 {
159 #if defined(MAGICKCORE_HAVE_NEWLOCALE)
160 if (c_locale == (locale_t) NULL)
161 c_locale=newlocale(LC_ALL_MASK,"C",(locale_t) 0);
162 #elif defined(MAGICKCORE_WINDOWS_SUPPORT) && !defined(__MINGW32__)
163 if (c_locale == (locale_t) NULL)
164 c_locale=_create_locale(LC_ALL,"C");
165 #endif
166 return(c_locale);
167 }
168 #endif
169
170 /*
171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172 % %
173 % %
174 % %
175 % A c q u i r e L o c a l e S p l a y T r e e %
176 % %
177 % %
178 % %
179 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
180 %
181 % AcquireLocaleSplayTree() caches one or more locale configurations which
182 % provides a mapping between locale attributes and a locale tag.
183 %
184 % The format of the AcquireLocaleSplayTree method is:
185 %
186 % SplayTreeInfo *AcquireLocaleSplayTree(const char *filename,
187 % ExceptionInfo *exception)
188 %
189 % A description of each parameter follows:
190 %
191 % o filename: the font file tag.
192 %
193 % o locale: the actual locale.
194 %
195 % o exception: return any errors or warnings in this structure.
196 %
197 */
198
DestroyLocaleNode(void * locale_info)199 static void *DestroyLocaleNode(void *locale_info)
200 {
201 LocaleInfo
202 *p;
203
204 p=(LocaleInfo *) locale_info;
205 if (p->path != (char *) NULL)
206 p->path=DestroyString(p->path);
207 if (p->tag != (char *) NULL)
208 p->tag=DestroyString(p->tag);
209 if (p->message != (char *) NULL)
210 p->message=DestroyString(p->message);
211 return(RelinquishMagickMemory(p));
212 }
213
AcquireLocaleSplayTree(const char * filename,const char * locale,ExceptionInfo * exception)214 static SplayTreeInfo *AcquireLocaleSplayTree(const char *filename,
215 const char *locale,ExceptionInfo *exception)
216 {
217 MagickStatusType
218 status;
219
220 SplayTreeInfo
221 *cache;
222
223 cache=NewSplayTree(CompareSplayTreeString,(void *(*)(void *)) NULL,
224 DestroyLocaleNode);
225 if (cache == (SplayTreeInfo *) NULL)
226 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
227 status=MagickTrue;
228 #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
229 {
230 const StringInfo
231 *option;
232
233 LinkedListInfo
234 *options;
235
236 options=GetLocaleOptions(filename,exception);
237 option=(const StringInfo *) GetNextValueInLinkedList(options);
238 while (option != (const StringInfo *) NULL)
239 {
240 status&=LoadLocaleCache(cache,(const char *) GetStringInfoDatum(option),
241 GetStringInfoPath(option),locale,0,exception);
242 option=(const StringInfo *) GetNextValueInLinkedList(options);
243 }
244 options=DestroyLocaleOptions(options);
245 if (GetNumberOfNodesInSplayTree(cache) == 0)
246 {
247 options=GetLocaleOptions("english.xml",exception);
248 option=(const StringInfo *) GetNextValueInLinkedList(options);
249 while (option != (const StringInfo *) NULL)
250 {
251 status&=LoadLocaleCache(cache,(const char *)
252 GetStringInfoDatum(option),GetStringInfoPath(option),locale,0,
253 exception);
254 option=(const StringInfo *) GetNextValueInLinkedList(options);
255 }
256 options=DestroyLocaleOptions(options);
257 }
258 }
259 #endif
260 if (GetNumberOfNodesInSplayTree(cache) == 0)
261 status&=LoadLocaleCache(cache,LocaleMap,"built-in",locale,0,
262 exception);
263 return(cache);
264 }
265
266 #if defined(MAGICKCORE_LOCALE_SUPPORT)
267 /*
268 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
269 % %
270 % %
271 % %
272 + D e s t r o y C L o c a l e %
273 % %
274 % %
275 % %
276 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
277 %
278 % DestroyCLocale() releases the resources allocated for a locale object
279 % returned by a call to the AcquireCLocale() method.
280 %
281 % The format of the DestroyCLocale method is:
282 %
283 % void DestroyCLocale(void)
284 %
285 */
DestroyCLocale(void)286 static void DestroyCLocale(void)
287 {
288 if (c_locale != (locale_t) NULL)
289 freelocale(c_locale);
290 c_locale=(locale_t) NULL;
291 }
292 #endif
293
294 /*
295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
296 % %
297 % %
298 % %
299 % D e s t r o y L o c a l e O p t i o n s %
300 % %
301 % %
302 % %
303 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
304 %
305 % DestroyLocaleOptions() releases memory associated with an locale
306 % messages.
307 %
308 % The format of the DestroyProfiles method is:
309 %
310 % LinkedListInfo *DestroyLocaleOptions(Image *image)
311 %
312 % A description of each parameter follows:
313 %
314 % o image: the image.
315 %
316 */
317
DestroyOptions(void * message)318 static void *DestroyOptions(void *message)
319 {
320 return(DestroyStringInfo((StringInfo *) message));
321 }
322
DestroyLocaleOptions(LinkedListInfo * messages)323 MagickExport LinkedListInfo *DestroyLocaleOptions(LinkedListInfo *messages)
324 {
325 assert(messages != (LinkedListInfo *) NULL);
326 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
327 return(DestroyLinkedList(messages,DestroyOptions));
328 }
329
330 /*
331 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
332 % %
333 % %
334 % %
335 + F o r m a t L o c a l e F i l e %
336 % %
337 % %
338 % %
339 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
340 %
341 % FormatLocaleFile() prints formatted output of a variable argument list to a
342 % file in the "C" locale.
343 %
344 % The format of the FormatLocaleFile method is:
345 %
346 % ssize_t FormatLocaleFile(FILE *file,const char *format,...)
347 %
348 % A description of each parameter follows.
349 %
350 % o file: the file.
351 %
352 % o format: A file describing the format to use to write the remaining
353 % arguments.
354 %
355 */
356
FormatLocaleFileList(FILE * file,const char * magick_restrict format,va_list operands)357 MagickExport ssize_t FormatLocaleFileList(FILE *file,
358 const char *magick_restrict format,va_list operands)
359 {
360 ssize_t
361 n;
362
363 #if defined(MAGICKCORE_LOCALE_SUPPORT) && defined(MAGICKCORE_HAVE_VFPRINTF_L)
364 {
365 locale_t
366 locale;
367
368 locale=AcquireCLocale();
369 if (locale == (locale_t) NULL)
370 n=(ssize_t) vfprintf(file,format,operands);
371 else
372 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
373 n=(ssize_t) vfprintf_l(file,format,locale,operands);
374 #else
375 n=(ssize_t) vfprintf_l(file,locale,format,operands);
376 #endif
377 }
378 #else
379 #if defined(MAGICKCORE_LOCALE_SUPPORT) && defined(MAGICKCORE_HAVE_USELOCALE)
380 {
381 locale_t
382 locale,
383 previous_locale;
384
385 locale=AcquireCLocale();
386 if (locale == (locale_t) NULL)
387 n=(ssize_t) vfprintf(file,format,operands);
388 else
389 {
390 previous_locale=uselocale(locale);
391 n=(ssize_t) vfprintf(file,format,operands);
392 uselocale(previous_locale);
393 }
394 }
395 #else
396 n=(ssize_t) vfprintf(file,format,operands);
397 #endif
398 #endif
399 return(n);
400 }
401
FormatLocaleFile(FILE * file,const char * magick_restrict format,...)402 MagickExport ssize_t FormatLocaleFile(FILE *file,
403 const char *magick_restrict format,...)
404 {
405 ssize_t
406 n;
407
408 va_list
409 operands;
410
411 va_start(operands,format);
412 n=FormatLocaleFileList(file,format,operands);
413 va_end(operands);
414 return(n);
415 }
416
417 /*
418 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
419 % %
420 % %
421 % %
422 + F o r m a t L o c a l e S t r i n g %
423 % %
424 % %
425 % %
426 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
427 %
428 % FormatLocaleString() prints formatted output of a variable argument list to
429 % a string buffer in the "C" locale.
430 %
431 % The format of the FormatLocaleString method is:
432 %
433 % ssize_t FormatLocaleString(char *string,const size_t length,
434 % const char *format,...)
435 %
436 % A description of each parameter follows.
437 %
438 % o string: FormatLocaleString() returns the formatted string in this
439 % character buffer.
440 %
441 % o length: the maximum length of the string.
442 %
443 % o format: A string describing the format to use to write the remaining
444 % arguments.
445 %
446 */
447
FormatLocaleStringList(char * magick_restrict string,const size_t length,const char * magick_restrict format,va_list operands)448 MagickExport ssize_t FormatLocaleStringList(char *magick_restrict string,
449 const size_t length,const char *magick_restrict format,va_list operands)
450 {
451 ssize_t
452 n;
453
454 #if defined(MAGICKCORE_LOCALE_SUPPORT) && defined(MAGICKCORE_HAVE_VSNPRINTF_L)
455 {
456 locale_t
457 locale;
458
459 locale=AcquireCLocale();
460 if (locale == (locale_t) NULL)
461 n=(ssize_t) vsnprintf(string,length,format,operands);
462 else
463 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
464 n=(ssize_t) vsnprintf_l(string,length,format,locale,operands);
465 #else
466 n=(ssize_t) vsnprintf_l(string,length,locale,format,operands);
467 #endif
468 }
469 #elif defined(MAGICKCORE_HAVE_VSNPRINTF)
470 #if defined(MAGICKCORE_LOCALE_SUPPORT) && defined(MAGICKCORE_HAVE_USELOCALE)
471 {
472 locale_t
473 locale,
474 previous_locale;
475
476 locale=AcquireCLocale();
477 if (locale == (locale_t) NULL)
478 n=(ssize_t) vsnprintf(string,length,format,operands);
479 else
480 {
481 previous_locale=uselocale(locale);
482 n=(ssize_t) vsnprintf(string,length,format,operands);
483 uselocale(previous_locale);
484 }
485 }
486 #else
487 n=(ssize_t) vsnprintf(string,length,format,operands);
488 #endif
489 #else
490 n=(ssize_t) vsprintf(string,format,operands);
491 #endif
492 if (n < 0)
493 string[length-1]='\0';
494 return(n);
495 }
496
FormatLocaleString(char * magick_restrict string,const size_t length,const char * magick_restrict format,...)497 MagickExport ssize_t FormatLocaleString(char *magick_restrict string,
498 const size_t length,const char *magick_restrict format,...)
499 {
500 ssize_t
501 n;
502
503 va_list
504 operands;
505
506 va_start(operands,format);
507 n=FormatLocaleStringList(string,length,format,operands);
508 va_end(operands);
509 return(n);
510 }
511
512 /*
513 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
514 % %
515 % %
516 % %
517 + G e t L o c a l e I n f o _ %
518 % %
519 % %
520 % %
521 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
522 %
523 % GetLocaleInfo_() searches the locale list for the specified tag and if
524 % found returns attributes for that element.
525 %
526 % The format of the GetLocaleInfo method is:
527 %
528 % const LocaleInfo *GetLocaleInfo_(const char *tag,
529 % ExceptionInfo *exception)
530 %
531 % A description of each parameter follows:
532 %
533 % o tag: the locale tag.
534 %
535 % o exception: return any errors or warnings in this structure.
536 %
537 */
GetLocaleInfo_(const char * tag,ExceptionInfo * exception)538 MagickExport const LocaleInfo *GetLocaleInfo_(const char *tag,
539 ExceptionInfo *exception)
540 {
541 const LocaleInfo
542 *locale_info;
543
544 assert(exception != (ExceptionInfo *) NULL);
545 if (IsLocaleTreeInstantiated(exception) == MagickFalse)
546 return((const LocaleInfo *) NULL);
547 LockSemaphoreInfo(locale_semaphore);
548 if ((tag == (const char *) NULL) || (LocaleCompare(tag,"*") == 0))
549 {
550 ResetSplayTreeIterator(locale_cache);
551 locale_info=(const LocaleInfo *) GetNextValueInSplayTree(locale_cache);
552 UnlockSemaphoreInfo(locale_semaphore);
553 return(locale_info);
554 }
555 locale_info=(const LocaleInfo *) GetValueFromSplayTree(locale_cache,tag);
556 UnlockSemaphoreInfo(locale_semaphore);
557 return(locale_info);
558 }
559
560 /*
561 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
562 % %
563 % %
564 % %
565 % G e t L o c a l e I n f o L i s t %
566 % %
567 % %
568 % %
569 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
570 %
571 % GetLocaleInfoList() returns any locale messages that match the
572 % specified pattern.
573 %
574 % The format of the GetLocaleInfoList function is:
575 %
576 % const LocaleInfo **GetLocaleInfoList(const char *pattern,
577 % size_t *number_messages,ExceptionInfo *exception)
578 %
579 % A description of each parameter follows:
580 %
581 % o pattern: Specifies a pointer to a text string containing a pattern.
582 %
583 % o number_messages: This integer returns the number of locale messages in
584 % the list.
585 %
586 % o exception: return any errors or warnings in this structure.
587 %
588 */
589
590 #if defined(__cplusplus) || defined(c_plusplus)
591 extern "C" {
592 #endif
593
LocaleInfoCompare(const void * x,const void * y)594 static int LocaleInfoCompare(const void *x,const void *y)
595 {
596 const LocaleInfo
597 **p,
598 **q;
599
600 p=(const LocaleInfo **) x,
601 q=(const LocaleInfo **) y;
602 if (LocaleCompare((*p)->path,(*q)->path) == 0)
603 return(LocaleCompare((*p)->tag,(*q)->tag));
604 return(LocaleCompare((*p)->path,(*q)->path));
605 }
606
607 #if defined(__cplusplus) || defined(c_plusplus)
608 }
609 #endif
610
GetLocaleInfoList(const char * pattern,size_t * number_messages,ExceptionInfo * exception)611 MagickExport const LocaleInfo **GetLocaleInfoList(const char *pattern,
612 size_t *number_messages,ExceptionInfo *exception)
613 {
614 const LocaleInfo
615 **messages;
616
617 const LocaleInfo
618 *p;
619
620 ssize_t
621 i;
622
623 /*
624 Allocate locale list.
625 */
626 assert(pattern != (char *) NULL);
627 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
628 assert(number_messages != (size_t *) NULL);
629 *number_messages=0;
630 p=GetLocaleInfo_("*",exception);
631 if (p == (const LocaleInfo *) NULL)
632 return((const LocaleInfo **) NULL);
633 messages=(const LocaleInfo **) AcquireQuantumMemory((size_t)
634 GetNumberOfNodesInSplayTree(locale_cache)+1UL,sizeof(*messages));
635 if (messages == (const LocaleInfo **) NULL)
636 return((const LocaleInfo **) NULL);
637 /*
638 Generate locale list.
639 */
640 LockSemaphoreInfo(locale_semaphore);
641 ResetSplayTreeIterator(locale_cache);
642 p=(const LocaleInfo *) GetNextValueInSplayTree(locale_cache);
643 for (i=0; p != (const LocaleInfo *) NULL; )
644 {
645 if ((p->stealth == MagickFalse) &&
646 (GlobExpression(p->tag,pattern,MagickTrue) != MagickFalse))
647 messages[i++]=p;
648 p=(const LocaleInfo *) GetNextValueInSplayTree(locale_cache);
649 }
650 UnlockSemaphoreInfo(locale_semaphore);
651 qsort((void *) messages,(size_t) i,sizeof(*messages),LocaleInfoCompare);
652 messages[i]=(LocaleInfo *) NULL;
653 *number_messages=(size_t) i;
654 return(messages);
655 }
656
657 /*
658 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
659 % %
660 % %
661 % %
662 % G e t L o c a l e L i s t %
663 % %
664 % %
665 % %
666 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
667 %
668 % GetLocaleList() returns any locale messages that match the specified
669 % pattern.
670 %
671 % The format of the GetLocaleList function is:
672 %
673 % char **GetLocaleList(const char *pattern,size_t *number_messages,
674 % Exceptioninfo *exception)
675 %
676 % A description of each parameter follows:
677 %
678 % o pattern: Specifies a pointer to a text string containing a pattern.
679 %
680 % o number_messages: This integer returns the number of messages in the
681 % list.
682 %
683 % o exception: return any errors or warnings in this structure.
684 %
685 */
686
687 #if defined(__cplusplus) || defined(c_plusplus)
688 extern "C" {
689 #endif
690
LocaleTagCompare(const void * x,const void * y)691 static int LocaleTagCompare(const void *x,const void *y)
692 {
693 char
694 **p,
695 **q;
696
697 p=(char **) x;
698 q=(char **) y;
699 return(LocaleCompare(*p,*q));
700 }
701
702 #if defined(__cplusplus) || defined(c_plusplus)
703 }
704 #endif
705
GetLocaleList(const char * pattern,size_t * number_messages,ExceptionInfo * exception)706 MagickExport char **GetLocaleList(const char *pattern,
707 size_t *number_messages,ExceptionInfo *exception)
708 {
709 char
710 **messages;
711
712 const LocaleInfo
713 *p;
714
715 ssize_t
716 i;
717
718 /*
719 Allocate locale list.
720 */
721 assert(pattern != (char *) NULL);
722 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
723 assert(number_messages != (size_t *) NULL);
724 *number_messages=0;
725 p=GetLocaleInfo_("*",exception);
726 if (p == (const LocaleInfo *) NULL)
727 return((char **) NULL);
728 messages=(char **) AcquireQuantumMemory((size_t)
729 GetNumberOfNodesInSplayTree(locale_cache)+1UL,sizeof(*messages));
730 if (messages == (char **) NULL)
731 return((char **) NULL);
732 LockSemaphoreInfo(locale_semaphore);
733 p=(const LocaleInfo *) GetNextValueInSplayTree(locale_cache);
734 for (i=0; p != (const LocaleInfo *) NULL; )
735 {
736 if ((p->stealth == MagickFalse) &&
737 (GlobExpression(p->tag,pattern,MagickTrue) != MagickFalse))
738 messages[i++]=ConstantString(p->tag);
739 p=(const LocaleInfo *) GetNextValueInSplayTree(locale_cache);
740 }
741 UnlockSemaphoreInfo(locale_semaphore);
742 qsort((void *) messages,(size_t) i,sizeof(*messages),LocaleTagCompare);
743 messages[i]=(char *) NULL;
744 *number_messages=(size_t) i;
745 return(messages);
746 }
747
748 /*
749 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
750 % %
751 % %
752 % %
753 % G e t L o c a l e M e s s a g e %
754 % %
755 % %
756 % %
757 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
758 %
759 % GetLocaleMessage() returns a message in the current locale that matches the
760 % supplied tag.
761 %
762 % The format of the GetLocaleMessage method is:
763 %
764 % const char *GetLocaleMessage(const char *tag)
765 %
766 % A description of each parameter follows:
767 %
768 % o tag: Return a message that matches this tag in the current locale.
769 %
770 */
GetLocaleMessage(const char * tag)771 MagickExport const char *GetLocaleMessage(const char *tag)
772 {
773 char
774 name[MaxTextExtent];
775
776 const LocaleInfo
777 *locale_info;
778
779 ExceptionInfo
780 *exception;
781
782 if ((tag == (const char *) NULL) || (*tag == '\0'))
783 return(tag);
784 exception=AcquireExceptionInfo();
785 (void) FormatLocaleString(name,MaxTextExtent,"%s/",tag);
786 locale_info=GetLocaleInfo_(name,exception);
787 exception=DestroyExceptionInfo(exception);
788 if (locale_info != (const LocaleInfo *) NULL)
789 return(locale_info->message);
790 return(tag);
791 }
792
793 /*
794 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
795 % %
796 % %
797 % %
798 % G e t L o c a l e O p t i o n s %
799 % %
800 % %
801 % %
802 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
803 %
804 % GetLocaleOptions() returns any Magick configuration messages associated
805 % with the specified filename.
806 %
807 % The format of the GetLocaleOptions method is:
808 %
809 % LinkedListInfo *GetLocaleOptions(const char *filename,
810 % ExceptionInfo *exception)
811 %
812 % A description of each parameter follows:
813 %
814 % o filename: the locale file tag.
815 %
816 % o exception: return any errors or warnings in this structure.
817 %
818 */
GetLocaleOptions(const char * filename,ExceptionInfo * exception)819 MagickExport LinkedListInfo *GetLocaleOptions(const char *filename,
820 ExceptionInfo *exception)
821 {
822 char
823 path[MaxTextExtent];
824
825 const char
826 *element;
827
828 LinkedListInfo
829 *messages,
830 *paths;
831
832 StringInfo
833 *xml;
834
835 assert(filename != (const char *) NULL);
836 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
837 assert(exception != (ExceptionInfo *) NULL);
838 (void) CopyMagickString(path,filename,MaxTextExtent);
839 /*
840 Load XML from configuration files to linked-list.
841 */
842 messages=NewLinkedList(0);
843 paths=GetConfigurePaths(filename,exception);
844 if (paths != (LinkedListInfo *) NULL)
845 {
846 ResetLinkedListIterator(paths);
847 element=(const char *) GetNextValueInLinkedList(paths);
848 while (element != (const char *) NULL)
849 {
850 (void) FormatLocaleString(path,MaxTextExtent,"%s%s",element,filename);
851 (void) LogMagickEvent(LocaleEvent,GetMagickModule(),
852 "Searching for locale file: \"%s\"",path);
853 xml=ConfigureFileToStringInfo(path);
854 if (xml != (StringInfo *) NULL)
855 (void) AppendValueToLinkedList(messages,xml);
856 element=(const char *) GetNextValueInLinkedList(paths);
857 }
858 paths=DestroyLinkedList(paths,RelinquishMagickMemory);
859 }
860 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
861 {
862 char
863 *blob;
864
865 blob=(char *) NTResourceToBlob(filename);
866 if (blob != (char *) NULL)
867 {
868 xml=AcquireStringInfo(0);
869 SetStringInfoLength(xml,strlen(blob)+1);
870 SetStringInfoDatum(xml,(const unsigned char *) blob);
871 blob=(char *) RelinquishMagickMemory(blob);
872 SetStringInfoPath(xml,filename);
873 (void) AppendValueToLinkedList(messages,xml);
874 }
875 }
876 #endif
877 ResetLinkedListIterator(messages);
878 return(messages);
879 }
880
881 /*
882 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
883 % %
884 % %
885 % %
886 % G e t L o c a l e V a l u e %
887 % %
888 % %
889 % %
890 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
891 %
892 % GetLocaleValue() returns the message associated with the locale info.
893 %
894 % The format of the GetLocaleValue method is:
895 %
896 % const char *GetLocaleValue(const LocaleInfo *locale_info)
897 %
898 % A description of each parameter follows:
899 %
900 % o locale_info: The locale info.
901 %
902 */
GetLocaleValue(const LocaleInfo * locale_info)903 MagickExport const char *GetLocaleValue(const LocaleInfo *locale_info)
904 {
905 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
906 assert(locale_info != (LocaleInfo *) NULL);
907 assert(locale_info->signature == MagickCoreSignature);
908 return(locale_info->message);
909 }
910
911 /*
912 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
913 % %
914 % %
915 % %
916 + I s L o c a l e T r e e I n s t a n t i a t e d %
917 % %
918 % %
919 % %
920 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
921 %
922 % IsLocaleTreeInstantiated() determines if the locale tree is instantiated.
923 % If not, it instantiates the tree and returns it.
924 %
925 % The format of the IsLocaleInstantiated method is:
926 %
927 % MagickBooleanType IsLocaleTreeInstantiated(ExceptionInfo *exception)
928 %
929 % A description of each parameter follows.
930 %
931 % o exception: return any errors or warnings in this structure.
932 %
933 */
IsLocaleTreeInstantiated(ExceptionInfo * exception)934 static MagickBooleanType IsLocaleTreeInstantiated(ExceptionInfo *exception)
935 {
936 if (locale_cache == (SplayTreeInfo *) NULL)
937 {
938 if (locale_semaphore == (SemaphoreInfo *) NULL)
939 ActivateSemaphoreInfo(&locale_semaphore);
940 LockSemaphoreInfo(locale_semaphore);
941 if (locale_cache == (SplayTreeInfo *) NULL)
942 {
943 char
944 *locale;
945
946 const char
947 *p;
948
949 locale=(char *) NULL;
950 p=setlocale(LC_CTYPE,(const char *) NULL);
951 if (p != (const char *) NULL)
952 locale=ConstantString(p);
953 if (locale == (char *) NULL)
954 locale=GetEnvironmentValue("LC_ALL");
955 if (locale == (char *) NULL)
956 locale=GetEnvironmentValue("LC_MESSAGES");
957 if (locale == (char *) NULL)
958 locale=GetEnvironmentValue("LC_CTYPE");
959 if (locale == (char *) NULL)
960 locale=GetEnvironmentValue("LANG");
961 if (locale == (char *) NULL)
962 locale=ConstantString("C");
963 locale_cache=AcquireLocaleSplayTree(LocaleFilename,locale,exception);
964 locale=DestroyString(locale);
965 }
966 UnlockSemaphoreInfo(locale_semaphore);
967 }
968 return(locale_cache != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
969 }
970
971 /*
972 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
973 % %
974 % %
975 % %
976 + I n t e r p r e t L o c a l e V a l u e %
977 % %
978 % %
979 % %
980 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
981 %
982 % InterpretLocaleValue() interprets the string as a floating point number in
983 % the "C" locale and returns its value as a double. If sentinal is not a null
984 % pointer, the method also sets the value pointed by sentinal to point to the
985 % first character after the number.
986 %
987 % The format of the InterpretLocaleValue method is:
988 %
989 % double InterpretLocaleValue(const char *value,char **sentinal)
990 %
991 % A description of each parameter follows:
992 %
993 % o value: the string value.
994 %
995 % o sentinal: if sentinal is not NULL, a pointer to the character after the
996 % last character used in the conversion is stored in the location
997 % referenced by sentinal.
998 %
999 */
InterpretLocaleValue(const char * magick_restrict string,char ** magick_restrict sentinal)1000 MagickExport double InterpretLocaleValue(const char *magick_restrict string,
1001 char **magick_restrict sentinal)
1002 {
1003 char
1004 *q;
1005
1006 double
1007 value;
1008
1009 if ((*string == '0') && ((string[1] | 0x20)=='x'))
1010 value=(double) strtoul(string,&q,16);
1011 else
1012 {
1013 #if defined(MAGICKCORE_LOCALE_SUPPORT) && defined(MAGICKCORE_HAVE_STRTOD_L)
1014 locale_t
1015 locale;
1016
1017 locale=AcquireCLocale();
1018 if (locale == (locale_t) NULL)
1019 value=strtod(string,&q);
1020 else
1021 value=strtod_l(string,&q,locale);
1022 #else
1023 value=strtod(string,&q);
1024 #endif
1025 }
1026 if (sentinal != (char **) NULL)
1027 *sentinal=q;
1028 return(value);
1029 }
1030
1031 /*
1032 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1033 % %
1034 % %
1035 % %
1036 % L i s t L o c a l e I n f o %
1037 % %
1038 % %
1039 % %
1040 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1041 %
1042 % ListLocaleInfo() lists the locale info to a file.
1043 %
1044 % The format of the ListLocaleInfo method is:
1045 %
1046 % MagickBooleanType ListLocaleInfo(FILE *file,ExceptionInfo *exception)
1047 %
1048 % A description of each parameter follows.
1049 %
1050 % o file: An pointer to a FILE.
1051 %
1052 % o exception: return any errors or warnings in this structure.
1053 %
1054 */
ListLocaleInfo(FILE * file,ExceptionInfo * exception)1055 MagickExport MagickBooleanType ListLocaleInfo(FILE *file,
1056 ExceptionInfo *exception)
1057 {
1058 const char
1059 *path;
1060
1061 const LocaleInfo
1062 **locale_info;
1063
1064 ssize_t
1065 i;
1066
1067 size_t
1068 number_messages;
1069
1070 if (file == (const FILE *) NULL)
1071 file=stdout;
1072 number_messages=0;
1073 locale_info=GetLocaleInfoList("*",&number_messages,exception);
1074 if (locale_info == (const LocaleInfo **) NULL)
1075 return(MagickFalse);
1076 path=(const char *) NULL;
1077 for (i=0; i < (ssize_t) number_messages; i++)
1078 {
1079 if (locale_info[i]->stealth != MagickFalse)
1080 continue;
1081 if ((path == (const char *) NULL) ||
1082 (LocaleCompare(path,locale_info[i]->path) != 0))
1083 {
1084 if (locale_info[i]->path != (char *) NULL)
1085 (void) FormatLocaleFile(file,"\nPath: %s\n\n",locale_info[i]->path);
1086 (void) FormatLocaleFile(file,"Tag/Message\n");
1087 (void) FormatLocaleFile(file,
1088 "-------------------------------------------------"
1089 "------------------------------\n");
1090 }
1091 path=locale_info[i]->path;
1092 (void) FormatLocaleFile(file,"%s\n",locale_info[i]->tag);
1093 if (locale_info[i]->message != (char *) NULL)
1094 (void) FormatLocaleFile(file," %s",locale_info[i]->message);
1095 (void) FormatLocaleFile(file,"\n");
1096 }
1097 (void) fflush(file);
1098 locale_info=(const LocaleInfo **)
1099 RelinquishMagickMemory((void *) locale_info);
1100 return(MagickTrue);
1101 }
1102
1103 /*
1104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1105 % %
1106 % %
1107 % %
1108 + L o a d L o c a l e C a c h e %
1109 % %
1110 % %
1111 % %
1112 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1113 %
1114 % LoadLocaleCache() loads the locale configurations which provides a mapping
1115 % between locale attributes and a locale name.
1116 %
1117 % The format of the LoadLocaleCache method is:
1118 %
1119 % MagickBooleanType LoadLocaleCache(SplayTreeInfo *cache,const char *xml,
1120 % const char *filename,const size_t depth,ExceptionInfo *exception)
1121 %
1122 % A description of each parameter follows:
1123 %
1124 % o xml: The locale list in XML format.
1125 %
1126 % o filename: The locale list filename.
1127 %
1128 % o depth: depth of <include /> statements.
1129 %
1130 % o exception: return any errors or warnings in this structure.
1131 %
1132 */
1133
ChopLocaleComponents(char * path,const size_t components)1134 static void ChopLocaleComponents(char *path,const size_t components)
1135 {
1136 char
1137 *p;
1138
1139 ssize_t
1140 count;
1141
1142 if (*path == '\0')
1143 return;
1144 p=path+strlen(path)-1;
1145 if (*p == '/')
1146 *p='\0';
1147 for (count=0; (count < (ssize_t) components) && (p > path); p--)
1148 if (*p == '/')
1149 {
1150 *p='\0';
1151 count++;
1152 }
1153 if (count < (ssize_t) components)
1154 *path='\0';
1155 }
1156
LocaleFatalErrorHandler(const ExceptionType magick_unused (severity),const char * reason,const char * description)1157 static void LocaleFatalErrorHandler(
1158 const ExceptionType magick_unused(severity),
1159 const char *reason,const char *description)
1160 {
1161 magick_unreferenced(severity);
1162
1163 if (reason == (char *) NULL)
1164 return;
1165 (void) FormatLocaleFile(stderr,"%s: %s",GetClientName(),reason);
1166 if (description != (char *) NULL)
1167 (void) FormatLocaleFile(stderr," (%s)",description);
1168 (void) FormatLocaleFile(stderr,".\n");
1169 (void) fflush(stderr);
1170 exit(1);
1171 }
1172
LoadLocaleCache(SplayTreeInfo * cache,const char * xml,const char * filename,const char * locale,const size_t depth,ExceptionInfo * exception)1173 static MagickBooleanType LoadLocaleCache(SplayTreeInfo *cache,const char *xml,
1174 const char *filename,const char *locale,const size_t depth,
1175 ExceptionInfo *exception)
1176 {
1177 char
1178 keyword[MaxTextExtent],
1179 message[MaxTextExtent],
1180 tag[MaxTextExtent],
1181 *token;
1182
1183 const char
1184 *q;
1185
1186 FatalErrorHandler
1187 fatal_handler;
1188
1189 LocaleInfo
1190 *locale_info;
1191
1192 MagickStatusType
1193 status;
1194
1195 char
1196 *p;
1197
1198 size_t
1199 extent;
1200
1201 /*
1202 Read the locale configure file.
1203 */
1204 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1205 "Loading locale configure file \"%s\" ...",filename);
1206 if (xml == (const char *) NULL)
1207 return(MagickFalse);
1208 status=MagickTrue;
1209 locale_info=(LocaleInfo *) NULL;
1210 *tag='\0';
1211 *message='\0';
1212 *keyword='\0';
1213 fatal_handler=SetFatalErrorHandler(LocaleFatalErrorHandler);
1214 token=AcquireString(xml);
1215 extent=strlen(token)+MaxTextExtent;
1216 for (q=(char *) xml; *q != '\0'; )
1217 {
1218 /*
1219 Interpret XML.
1220 */
1221 (void) GetNextToken(q,&q,extent,token);
1222 if (*token == '\0')
1223 break;
1224 (void) CopyMagickString(keyword,token,MaxTextExtent);
1225 if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
1226 {
1227 /*
1228 Doctype element.
1229 */
1230 while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
1231 {
1232 (void) GetNextToken(q,&q,extent,token);
1233 while (isspace((int) ((unsigned char) *q)) != 0)
1234 q++;
1235 }
1236 continue;
1237 }
1238 if (LocaleNCompare(keyword,"<!--",4) == 0)
1239 {
1240 /*
1241 Comment element.
1242 */
1243 while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
1244 {
1245 (void) GetNextToken(q,&q,extent,token);
1246 while (isspace((int) ((unsigned char) *q)) != 0)
1247 q++;
1248 }
1249 continue;
1250 }
1251 if (LocaleCompare(keyword,"<include") == 0)
1252 {
1253 /*
1254 Include element.
1255 */
1256 while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
1257 {
1258 (void) CopyMagickString(keyword,token,MaxTextExtent);
1259 (void) GetNextToken(q,&q,extent,token);
1260 if (*token != '=')
1261 continue;
1262 (void) GetNextToken(q,&q,extent,token);
1263 if (LocaleCompare(keyword,"locale") == 0)
1264 {
1265 if (LocaleCompare(locale,token) != 0)
1266 break;
1267 continue;
1268 }
1269 if (LocaleCompare(keyword,"file") == 0)
1270 {
1271 if (depth > MagickMaxRecursionDepth)
1272 (void) ThrowMagickException(exception,GetMagickModule(),
1273 ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
1274 else
1275 {
1276 char
1277 path[MaxTextExtent],
1278 *xml;
1279
1280 *path='\0';
1281 GetPathComponent(filename,HeadPath,path);
1282 if (*path != '\0')
1283 (void) ConcatenateMagickString(path,DirectorySeparator,
1284 MaxTextExtent);
1285 if (*token == *DirectorySeparator)
1286 (void) CopyMagickString(path,token,MaxTextExtent);
1287 else
1288 (void) ConcatenateMagickString(path,token,MaxTextExtent);
1289 xml=FileToXML(path,~0UL);
1290 if (xml != (char *) NULL)
1291 {
1292 status&=LoadLocaleCache(cache,xml,path,locale,
1293 depth+1,exception);
1294 xml=(char *) RelinquishMagickMemory(xml);
1295 }
1296 }
1297 }
1298 }
1299 continue;
1300 }
1301 if (LocaleCompare(keyword,"<locale") == 0)
1302 {
1303 /*
1304 Locale element.
1305 */
1306 while ((*token != '>') && (*q != '\0'))
1307 {
1308 (void) CopyMagickString(keyword,token,MaxTextExtent);
1309 (void) GetNextToken(q,&q,extent,token);
1310 if (*token != '=')
1311 continue;
1312 (void) GetNextToken(q,&q,extent,token);
1313 }
1314 continue;
1315 }
1316 if (LocaleCompare(keyword,"</locale>") == 0)
1317 {
1318 ChopLocaleComponents(tag,1);
1319 (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
1320 continue;
1321 }
1322 if (LocaleCompare(keyword,"<localemap>") == 0)
1323 continue;
1324 if (LocaleCompare(keyword,"</localemap>") == 0)
1325 continue;
1326 if (LocaleCompare(keyword,"<message") == 0)
1327 {
1328 /*
1329 Message element.
1330 */
1331 while ((*token != '>') && (*q != '\0'))
1332 {
1333 (void) CopyMagickString(keyword,token,MaxTextExtent);
1334 (void) GetNextToken(q,&q,extent,token);
1335 if (*token != '=')
1336 continue;
1337 (void) GetNextToken(q,&q,extent,token);
1338 if (LocaleCompare(keyword,"name") == 0)
1339 {
1340 (void) ConcatenateMagickString(tag,token,MaxTextExtent);
1341 (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
1342 }
1343 }
1344 for (p=(char *) q; (*q != '<') && (*q != '\0'); q++) ;
1345 while (isspace((int) ((unsigned char) *p)) != 0)
1346 p++;
1347 q--;
1348 while ((isspace((int) ((unsigned char) *q)) != 0) && (q > p))
1349 q--;
1350 (void) CopyMagickString(message,p,MagickMin((size_t) (q-p+2),
1351 MaxTextExtent));
1352 locale_info=(LocaleInfo *) AcquireMagickMemory(sizeof(*locale_info));
1353 if (locale_info == (LocaleInfo *) NULL)
1354 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1355 (void) memset(locale_info,0,sizeof(*locale_info));
1356 locale_info->path=ConstantString(filename);
1357 locale_info->tag=ConstantString(tag);
1358 locale_info->message=ConstantString(message);
1359 locale_info->signature=MagickCoreSignature;
1360 status=AddValueToSplayTree(cache,locale_info->tag,locale_info);
1361 if (status == MagickFalse)
1362 (void) ThrowMagickException(exception,GetMagickModule(),
1363 ResourceLimitError,"MemoryAllocationFailed","`%s'",
1364 locale_info->tag);
1365 (void) ConcatenateMagickString(tag,message,MaxTextExtent);
1366 (void) ConcatenateMagickString(tag,"\n",MaxTextExtent);
1367 q++;
1368 continue;
1369 }
1370 if (LocaleCompare(keyword,"</message>") == 0)
1371 {
1372 ChopLocaleComponents(tag,2);
1373 (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
1374 continue;
1375 }
1376 if (*keyword == '<')
1377 {
1378 /*
1379 Subpath element.
1380 */
1381 if (*(keyword+1) == '?')
1382 continue;
1383 if (*(keyword+1) == '/')
1384 {
1385 ChopLocaleComponents(tag,1);
1386 if (*tag != '\0')
1387 (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
1388 continue;
1389 }
1390 token[strlen(token)-1]='\0';
1391 (void) CopyMagickString(token,token+1,MaxTextExtent);
1392 (void) ConcatenateMagickString(tag,token,MaxTextExtent);
1393 (void) ConcatenateMagickString(tag,"/",MaxTextExtent);
1394 continue;
1395 }
1396 (void) GetNextToken(q,(const char **) NULL,extent,token);
1397 if (*token != '=')
1398 continue;
1399 }
1400 token=(char *) RelinquishMagickMemory(token);
1401 (void) SetFatalErrorHandler(fatal_handler);
1402 return(status != 0 ? MagickTrue : MagickFalse);
1403 }
1404
1405 /*
1406 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1407 % %
1408 % %
1409 % %
1410 % L o c a l e C o m p a r e %
1411 % %
1412 % %
1413 % %
1414 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1415 %
1416 % LocaleCompare() performs a case-insensitive comparison of two strings
1417 % byte-by-byte, according to the ordering of the current locale encoding.
1418 % LocaleCompare returns an integer greater than, equal to, or less than 0,
1419 % if the string pointed to by p is greater than, equal to, or less than the
1420 % string pointed to by q respectively. The sign of a non-zero return value
1421 % is determined by the sign of the difference between the values of the first
1422 % pair of bytes that differ in the strings being compared.
1423 %
1424 % The format of the LocaleCompare method is:
1425 %
1426 % int LocaleCompare(const char *p,const char *q)
1427 %
1428 % A description of each parameter follows:
1429 %
1430 % o p: A pointer to a character string.
1431 %
1432 % o q: A pointer to a character string to compare to p.
1433 %
1434 */
LocaleCompare(const char * p,const char * q)1435 MagickExport int LocaleCompare(const char *p,const char *q)
1436 {
1437 if (p == (char *) NULL)
1438 {
1439 if (q == (char *) NULL)
1440 return(0);
1441 return(-1);
1442 }
1443 if (q == (char *) NULL)
1444 return(1);
1445 #if defined(MAGICKCORE_HAVE_STRCASECMP)
1446 return(strcasecmp(p,q));
1447 #else
1448 {
1449 int
1450 c,
1451 d;
1452
1453 for ( ; ; )
1454 {
1455 c=(int) *((unsigned char *) p);
1456 d=(int) *((unsigned char *) q);
1457 if ((c == 0) || (AsciiMap[c] != AsciiMap[d]))
1458 break;
1459 p++;
1460 q++;
1461 }
1462 return(AsciiMap[c]-(int) AsciiMap[d]);
1463 }
1464 #endif
1465 }
1466
1467 /*
1468 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1469 % %
1470 % %
1471 % %
1472 % L o c a l e L o w e r %
1473 % %
1474 % %
1475 % %
1476 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1477 %
1478 % LocaleLower() transforms all of the characters in the supplied
1479 % null-terminated string, changing all uppercase letters to lowercase.
1480 %
1481 % The format of the LocaleLower method is:
1482 %
1483 % void LocaleLower(char *string)
1484 %
1485 % A description of each parameter follows:
1486 %
1487 % o string: A pointer to the string to convert to lower-case Locale.
1488 %
1489 */
LocaleLower(char * string)1490 MagickExport void LocaleLower(char *string)
1491 {
1492 char
1493 *q;
1494
1495 assert(string != (char *) NULL);
1496 for (q=string; *q != '\0'; q++)
1497 *q=(char) LocaleLowercase((int) *q);
1498 }
1499
1500 /*
1501 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1502 % %
1503 % %
1504 % %
1505 % L o c a l e L o w e r c a s e %
1506 % %
1507 % %
1508 % %
1509 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1510 %
1511 % LocaleLowercase() convert to uppercase.
1512 %
1513 % The format of the LocaleLowercase method is:
1514 %
1515 % void LocaleLowercase(const int c)
1516 %
1517 % A description of each parameter follows:
1518 %
1519 % o If c is a uppercase letter, return its lowercase equivalent.
1520 %
1521 */
LocaleLowercase(const int c)1522 MagickExport int LocaleLowercase(const int c)
1523 {
1524 if ((c == EOF) || (c != (unsigned char) c))
1525 return(c);
1526 #if defined(MAGICKCORE_LOCALE_SUPPORT)
1527 if (c_locale != (locale_t) NULL)
1528 return(tolower_l((int) ((unsigned char) c),c_locale));
1529 #endif
1530 return(tolower((int) ((unsigned char) c)));
1531 }
1532
1533 /*
1534 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1535 % %
1536 % %
1537 % %
1538 % L o c a l e N C o m p a r e %
1539 % %
1540 % %
1541 % %
1542 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1543 %
1544 % LocaleNCompare() performs a case-insensitive comparison of two strings
1545 % byte-by-byte, according to the ordering of the current locale encoding.
1546 %
1547 % LocaleNCompare returns an integer greater than, equal to, or less than 0,
1548 % if the string pointed to by p is greater than, equal to, or less than the
1549 % string pointed to by q respectively. The sign of a non-zero return value
1550 % is determined by the sign of the difference between the values of the first
1551 % pair of bytes that differ in the strings being compared.
1552 %
1553 % The LocaleNCompare method makes the same comparison as LocaleCompare but
1554 % looks at a maximum of n bytes. Bytes following a null byte are not
1555 % compared.
1556 %
1557 % The format of the LocaleNCompare method is:
1558 %
1559 % int LocaleNCompare(const char *p,const char *q,const size_t n)
1560 %
1561 % A description of each parameter follows:
1562 %
1563 % o p: A pointer to a character string.
1564 %
1565 % o q: A pointer to a character string to compare to p.
1566 %
1567 % o length: the number of characters to compare in strings p and q.
1568 %
1569 */
LocaleNCompare(const char * p,const char * q,const size_t length)1570 MagickExport int LocaleNCompare(const char *p,const char *q,const size_t length)
1571 {
1572 if (p == (char *) NULL)
1573 {
1574 if (q == (char *) NULL)
1575 return(0);
1576 return(-1);
1577 }
1578 if (q == (char *) NULL)
1579 return(1);
1580 #if defined(MAGICKCORE_HAVE_STRNCASECMP)
1581 return(strncasecmp(p,q,length));
1582 #else
1583 {
1584 int
1585 c,
1586 d;
1587
1588 size_t
1589 i;
1590
1591 for (i=length; i != 0; i--)
1592 {
1593 c=(int) *((unsigned char *) p);
1594 d=(int) *((unsigned char *) q);
1595 if (AsciiMap[c] != AsciiMap[d])
1596 return(AsciiMap[c]-(int) AsciiMap[d]);
1597 if (c == 0)
1598 return(0);
1599 p++;
1600 q++;
1601 }
1602 return(0);
1603 }
1604 #endif
1605 }
1606
1607 /*
1608 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1609 % %
1610 % %
1611 % %
1612 % L o c a l e U p p e r %
1613 % %
1614 % %
1615 % %
1616 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1617 %
1618 % LocaleUpper() transforms all of the characters in the supplied
1619 % null-terminated string, changing all lowercase letters to uppercase.
1620 %
1621 % The format of the LocaleUpper method is:
1622 %
1623 % void LocaleUpper(char *string)
1624 %
1625 % A description of each parameter follows:
1626 %
1627 % o string: A pointer to the string to convert to upper-case Locale.
1628 %
1629 */
LocaleUpper(char * string)1630 MagickExport void LocaleUpper(char *string)
1631 {
1632 char
1633 *q;
1634
1635 assert(string != (char *) NULL);
1636 for (q=string; *q != '\0'; q++)
1637 *q=(char) LocaleUppercase((int) *q);
1638 }
1639
1640 /*
1641 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1642 % %
1643 % %
1644 % %
1645 % L o c a l e U p p e r c a s e %
1646 % %
1647 % %
1648 % %
1649 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1650 %
1651 % LocaleUppercase() convert to uppercase.
1652 %
1653 % The format of the LocaleUppercase method is:
1654 %
1655 % void LocaleUppercase(const int c)
1656 %
1657 % A description of each parameter follows:
1658 %
1659 % o If c is a lowercase letter, return its uppercase equivalent.
1660 %
1661 */
LocaleUppercase(const int c)1662 MagickExport int LocaleUppercase(const int c)
1663 {
1664 if (c == EOF)
1665 return(c);
1666 #if defined(MAGICKCORE_LOCALE_SUPPORT)
1667 if (c_locale != (locale_t) NULL)
1668 return(toupper_l((int) ((unsigned char) c),c_locale));
1669 #endif
1670 return(toupper((int) ((unsigned char) c)));
1671 }
1672
1673 /*
1674 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1675 % %
1676 % %
1677 % %
1678 + L o c a l e C o m p o n e n t G e n e s i s %
1679 % %
1680 % %
1681 % %
1682 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1683 %
1684 % LocaleComponentGenesis() instantiates the locale component.
1685 %
1686 % The format of the LocaleComponentGenesis method is:
1687 %
1688 % MagickBooleanType LocaleComponentGenesis(void)
1689 %
1690 */
LocaleComponentGenesis(void)1691 MagickExport MagickBooleanType LocaleComponentGenesis(void)
1692 {
1693 if (locale_semaphore == (SemaphoreInfo *) NULL)
1694 locale_semaphore=AllocateSemaphoreInfo();
1695 #if defined(MAGICKCORE_LOCALE_SUPPORT)
1696 (void) AcquireCLocale();
1697 #endif
1698 return(MagickTrue);
1699 }
1700
1701 /*
1702 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1703 % %
1704 % %
1705 % %
1706 + L o c a l e C o m p o n e n t T e r m i n u s %
1707 % %
1708 % %
1709 % %
1710 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1711 %
1712 % LocaleComponentTerminus() destroys the locale component.
1713 %
1714 % The format of the LocaleComponentTerminus method is:
1715 %
1716 % LocaleComponentTerminus(void)
1717 %
1718 */
LocaleComponentTerminus(void)1719 MagickExport void LocaleComponentTerminus(void)
1720 {
1721 if (locale_semaphore == (SemaphoreInfo *) NULL)
1722 ActivateSemaphoreInfo(&locale_semaphore);
1723 LockSemaphoreInfo(locale_semaphore);
1724 if (locale_cache != (SplayTreeInfo *) NULL)
1725 locale_cache=DestroySplayTree(locale_cache);
1726 #if defined(MAGICKCORE_LOCALE_SUPPORT)
1727 DestroyCLocale();
1728 #endif
1729 UnlockSemaphoreInfo(locale_semaphore);
1730 DestroySemaphoreInfo(&locale_semaphore);
1731 }
1732