1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % CCCC OOO DDDD EEEEE RRRR %
7 % C O O D D E R R %
8 % C O O D D EEE RRRR %
9 % C O O D D E R R %
10 % CCCC OOO DDDD EEEEE R R %
11 % %
12 % %
13 % MagickCore Image Coder Methods %
14 % %
15 % Software Design %
16 % Cristy %
17 % May 2001 %
18 % %
19 % %
20 % Copyright 1999-2016 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 % http://www.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 "MagickCore/studio.h"
43 #include "MagickCore/blob.h"
44 #include "MagickCore/client.h"
45 #include "MagickCore/coder.h"
46 #include "MagickCore/coder-private.h"
47 #include "MagickCore/configure.h"
48 #include "MagickCore/draw.h"
49 #include "MagickCore/exception.h"
50 #include "MagickCore/exception-private.h"
51 #include "MagickCore/linked-list.h"
52 #include "MagickCore/log.h"
53 #include "MagickCore/memory_.h"
54 #include "MagickCore/option.h"
55 #include "MagickCore/semaphore.h"
56 #include "MagickCore/string_.h"
57 #include "MagickCore/splay-tree.h"
58 #include "MagickCore/token.h"
59 #include "MagickCore/utility.h"
60 #include "MagickCore/utility-private.h"
61 #include "MagickCore/xml-tree.h"
62 #include "MagickCore/xml-tree-private.h"
63
64 /*
65 Define declarations.
66 */
67 #define MagickCoderFilename "coder.xml"
68
69 /*
70 Typedef declarations.
71 */
72 typedef struct _CoderMapInfo
73 {
74 const char
75 *magick,
76 *name;
77 } CoderMapInfo;
78
79 /*
80 Static declarations.
81 */
82 static const CoderMapInfo
83 CoderMap[] =
84 {
85 { "3FR", "DNG" },
86 { "8BIM", "META" },
87 { "8BIMTEXT", "META" },
88 { "8BIMWTEXT", "META" },
89 { "AFM", "TTF" },
90 { "A", "RAW" },
91 { "AI", "PDF" },
92 { "APP1JPEG", "META" },
93 { "APP1", "META" },
94 { "ARW", "DNG" },
95 { "AVI", "MPEG" },
96 { "BIE", "JBIG" },
97 { "BMP2", "BMP" },
98 { "BMP3", "BMP" },
99 { "B", "RAW" },
100 { "BRF", "BRAILLE" },
101 { "BGRA", "BGR" },
102 { "BGRO", "BGR" },
103 { "CMYKA", "CMYK" },
104 { "C", "RAW" },
105 { "CAL", "CALS" },
106 { "CANVAS", "XC" },
107 { "CMYKA", "CMYK" },
108 { "CR2", "DNG" },
109 { "CRW", "DNG" },
110 { "CUR", "ICON" },
111 { "DATA", "INLINE" },
112 { "DCR", "DNG" },
113 { "DCX", "PCX" },
114 { "DFONT", "TTF" },
115 { "DXT1", "DDS" },
116 { "DXT5", "DDS" },
117 { "EPDF", "PDF" },
118 { "EPI", "PS" },
119 { "EPS2", "PS2" },
120 { "EPS3", "PS3" },
121 { "EPSF", "PS" },
122 { "EPSI", "PS" },
123 { "EPS", "PS" },
124 { "EPT2", "EPT" },
125 { "EPT3", "EPT" },
126 { "ERF", "DNG" },
127 { "EXIF", "META" },
128 { "FILE", "URL" },
129 { "FRACTAL", "PLASMA" },
130 { "FTP", "URL" },
131 { "FTS", "FITS" },
132 { "G3", "FAX" },
133 { "G4", "FAX" },
134 { "GIF87", "GIF" },
135 { "G", "RAW" },
136 { "GRANITE", "MAGICK" },
137 { "GROUP4", "TIFF" },
138 { "GV", "DOT" },
139 { "HTM", "HTML" },
140 { "ICB", "TGA" },
141 { "ICO", "ICON" },
142 { "IIQ", "DNG" },
143 { "K25", "DNG" },
144 { "KDC", "DNG" },
145 { "H", "MAGICK" },
146 { "HTM", "HTML" },
147 { "HTTP", "URL" },
148 { "HTTPS", "URL" },
149 { "ICB", "TGA" },
150 { "ICC", "META" },
151 { "ICM", "META" },
152 { "ICO", "ICON" },
153 { "IMPLICIT", "***" },
154 { "IPTC", "META" },
155 { "IPTCTEXT", "META" },
156 { "IPTCWTEXT", "META" },
157 { "ISOBRL", "BRAILLE" },
158 { "ISOBRL6", "BRAILLE" },
159 { "JBG", "JBIG" },
160 { "JNG", "PNG" },
161 { "JPC", "JP2" },
162 { "JPT", "JP2" },
163 { "JPM", "JP2" },
164 { "J2C", "JP2" },
165 { "J2K", "JP2" },
166 { "JNG", "PNG" },
167 { "JPE", "JPEG" },
168 { "JPG", "JPEG" },
169 { "JPM", "JP2" },
170 { "JPS", "JPEG" },
171 { "JPT", "JP2" },
172 { "JPX", "JP2" },
173 { "K", "RAW" },
174 { "K25", "DNG" },
175 { "KDC", "DNG" },
176 { "LOGO", "MAGICK" },
177 { "M", "RAW" },
178 { "M2V", "MPEG" },
179 { "M4V", "MPEG" },
180 { "MEF", "DNG" },
181 { "MKV", "MPEG" },
182 { "MNG", "PNG" },
183 { "MOV", "MPEG" },
184 { "MP4", "MPEG" },
185 { "MPG", "MPEG" },
186 { "MPRI", "MPR" },
187 { "MEF", "DNG" },
188 { "MRW", "DNG" },
189 { "MSVG", "SVG" },
190 { "NEF", "DNG" },
191 { "NETSCAPE", "MAGICK" },
192 { "NRW", "DNG" },
193 { "O", "RAW" },
194 { "ORF", "DNG" },
195 { "OTF", "TTF" },
196 { "P7", "PNM" },
197 { "PAL", "UYVY" },
198 { "PAM", "PNM" },
199 { "PBM", "PNM" },
200 { "PCDS", "PCD" },
201 { "PCT", "PICT" },
202 { "PDFA", "PDF" },
203 { "PEF", "DNG" },
204 { "PEF", "DNG" },
205 { "PFA", "TTF" },
206 { "PFB", "TTF" },
207 { "PFM", "PNM" },
208 { "PGM", "PNM" },
209 { "PGX", "JP2" },
210 { "PICON", "XPM" },
211 { "PJPEG", "JPEG" },
212 { "PM", "XPM" },
213 { "PNG00", "PNG" },
214 { "PNG24", "PNG" },
215 { "PNG32", "PNG" },
216 { "PNG48", "PNG" },
217 { "PNG64", "PNG" },
218 { "PNG8", "PNG" },
219 { "PPM", "PNM" },
220 { "PSB", "PSD" },
221 { "PTIF", "TIFF" },
222 { "R", "RAW" },
223 { "RADIAL-GRADIENT", "GRADIENT" },
224 { "RAF", "DNG" },
225 { "RAS", "SUN" },
226 { "RAW", "DNG" },
227 { "RGBA", "RGB" },
228 { "RGBO", "RGB" },
229 { "RMF", "DNG" },
230 { "ROSE", "MAGICK" },
231 { "RW2", "DNG" },
232 { "SHTML", "HTML" },
233 { "SIX", "SIXEL" },
234 { "SPARSE-COLOR", "TXT" },
235 { "SR2", "DNG" },
236 { "SRF", "DNG" },
237 { "SVGZ", "SVG" },
238 { "TEXT", "TXT" },
239 { "TIFF64", "TIFF" },
240 { "TIF", "TIFF" },
241 { "TTC", "TTF" },
242 { "UBRL", "BRAILLE" },
243 { "UBRL6", "BRAILLE" },
244 { "VDA", "TGA" },
245 { "VST", "TGA" },
246 { "WIZARD", "MAGICK" },
247 #if defined(MAGICKCORE_WINGDI32_DELEGATE)
248 { "WMF", "EMF" },
249 #endif
250 { "WMV", "MPEG" },
251 { "WMZ", "WMF" },
252 { "X3f", "DNG" },
253 { "XMP", "META" },
254 { "XTRNARRAY", "XTRN" },
255 { "XTRNBLOB", "XTRN" },
256 { "XTRNFILE", "XTRN" },
257 { "XTRNIMAGE", "XTRN" },
258 { "XV", "VIFF" },
259 { "Y", "RAW" },
260 { "YCbCrA", "YCbCr" }
261 };
262
263 static SemaphoreInfo
264 *coder_semaphore = (SemaphoreInfo *) NULL;
265
266 static SplayTreeInfo
267 *coder_cache = (SplayTreeInfo *) NULL;
268
269 /*
270 Forward declarations.
271 */
272 static MagickBooleanType
273 IsCoderTreeInstantiated(ExceptionInfo *),
274 LoadCoderCache(SplayTreeInfo *,const char *,const char *,const size_t,
275 ExceptionInfo *);
276
277 /*
278 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
279 % %
280 % %
281 % %
282 + A c q u i r e C o d e r C a c h e %
283 % %
284 % %
285 % %
286 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
287 %
288 % AcquireCoderCache() caches one or more coder configurations which provides a
289 % mapping between coder attributes and a coder name.
290 %
291 % The format of the AcquireCoderCache coder is:
292 %
293 % SplayTreeInfo *AcquireCoderCache(const char *filename,
294 % ExceptionInfo *exception)
295 %
296 % A description of each parameter follows:
297 %
298 % o filename: the font file name.
299 %
300 % o exception: return any errors or warnings in this structure.
301 %
302 */
303
DestroyCoderNode(void * coder_info)304 static void *DestroyCoderNode(void *coder_info)
305 {
306 register CoderInfo
307 *p;
308
309 p=(CoderInfo *) coder_info;
310 if (p->exempt == MagickFalse)
311 {
312 if (p->path != (char *) NULL)
313 p->path=DestroyString(p->path);
314 if (p->name != (char *) NULL)
315 p->name=DestroyString(p->name);
316 if (p->magick != (char *) NULL)
317 p->magick=DestroyString(p->magick);
318 }
319 return(RelinquishMagickMemory(p));
320 }
321
AcquireCoderCache(const char * filename,ExceptionInfo * exception)322 static SplayTreeInfo *AcquireCoderCache(const char *filename,
323 ExceptionInfo *exception)
324 {
325 MagickStatusType
326 status;
327
328 register ssize_t
329 i;
330
331 SplayTreeInfo
332 *cache;
333
334 /*
335 Load external coder map.
336 */
337 cache=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
338 DestroyCoderNode);
339 if (cache == (SplayTreeInfo *) NULL)
340 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
341 status=MagickTrue;
342 #if !defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT)
343 {
344 const StringInfo
345 *option;
346
347 LinkedListInfo
348 *options;
349
350 options=GetConfigureOptions(filename,exception);
351 option=(const StringInfo *) GetNextValueInLinkedList(options);
352 while (option != (const StringInfo *) NULL)
353 {
354 status&=LoadCoderCache(cache,(const char *) GetStringInfoDatum(option),
355 GetStringInfoPath(option),0,exception);
356 option=(const StringInfo *) GetNextValueInLinkedList(options);
357 }
358 options=DestroyConfigureOptions(options);
359 }
360 #endif
361 /*
362 Load built-in coder map.
363 */
364 for (i=0; i < (ssize_t) (sizeof(CoderMap)/sizeof(*CoderMap)); i++)
365 {
366 CoderInfo
367 *coder_info;
368
369 register const CoderMapInfo
370 *p;
371
372 p=CoderMap+i;
373 coder_info=(CoderInfo *) AcquireMagickMemory(sizeof(*coder_info));
374 if (coder_info == (CoderInfo *) NULL)
375 {
376 (void) ThrowMagickException(exception,GetMagickModule(),
377 ResourceLimitError,"MemoryAllocationFailed","`%s'",p->name);
378 continue;
379 }
380 (void) ResetMagickMemory(coder_info,0,sizeof(*coder_info));
381 coder_info->path=(char *) "[built-in]";
382 coder_info->magick=(char *) p->magick;
383 coder_info->name=(char *) p->name;
384 coder_info->exempt=MagickTrue;
385 coder_info->signature=MagickCoreSignature;
386 status&=AddValueToSplayTree(cache,ConstantString(coder_info->magick),
387 coder_info);
388 if (status == MagickFalse)
389 (void) ThrowMagickException(exception,GetMagickModule(),
390 ResourceLimitError,"MemoryAllocationFailed","`%s'",coder_info->name);
391 }
392 return(cache);
393 }
394
395 /*
396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
397 % %
398 % %
399 % %
400 + C o d e r C o m p o n e n t G e n e s i s %
401 % %
402 % %
403 % %
404 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
405 %
406 % CoderComponentGenesis() instantiates the coder component.
407 %
408 % The format of the CoderComponentGenesis method is:
409 %
410 % MagickBooleanType CoderComponentGenesis(void)
411 %
412 */
CoderComponentGenesis(void)413 MagickPrivate MagickBooleanType CoderComponentGenesis(void)
414 {
415 if (coder_semaphore == (SemaphoreInfo *) NULL)
416 coder_semaphore=AcquireSemaphoreInfo();
417 return(MagickTrue);
418 }
419
420 /*
421 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
422 % %
423 % %
424 % %
425 + C o d e r C o m p o n e n t T e r m i n u s %
426 % %
427 % %
428 % %
429 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
430 %
431 % CoderComponentTerminus() destroys the coder component.
432 %
433 % The format of the CoderComponentTerminus method is:
434 %
435 % CoderComponentTerminus(void)
436 %
437 */
CoderComponentTerminus(void)438 MagickPrivate void CoderComponentTerminus(void)
439 {
440 if (coder_semaphore == (SemaphoreInfo *) NULL)
441 ActivateSemaphoreInfo(&coder_semaphore);
442 LockSemaphoreInfo(coder_semaphore);
443 if (coder_cache != (SplayTreeInfo *) NULL)
444 coder_cache=DestroySplayTree(coder_cache);
445 UnlockSemaphoreInfo(coder_semaphore);
446 RelinquishSemaphoreInfo(&coder_semaphore);
447 }
448
449 /*
450 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
451 % %
452 % %
453 % %
454 + G e t C o d e r I n f o %
455 % %
456 % %
457 % %
458 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
459 %
460 % GetCoderInfo searches the coder list for the specified name and if found
461 % returns attributes for that coder.
462 %
463 % The format of the GetCoderInfo method is:
464 %
465 % const CoderInfo *GetCoderInfo(const char *name,ExceptionInfo *exception)
466 %
467 % A description of each parameter follows:
468 %
469 % o name: the coder name.
470 %
471 % o exception: return any errors or warnings in this structure.
472 %
473 */
GetCoderInfo(const char * name,ExceptionInfo * exception)474 MagickExport const CoderInfo *GetCoderInfo(const char *name,
475 ExceptionInfo *exception)
476 {
477 const CoderInfo
478 *coder_info;
479
480 assert(exception != (ExceptionInfo *) NULL);
481 if (IsCoderTreeInstantiated(exception) == MagickFalse)
482 return((const CoderInfo *) NULL);
483 LockSemaphoreInfo(coder_semaphore);
484 if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
485 {
486 ResetSplayTreeIterator(coder_cache);
487 coder_info=(const CoderInfo *) GetNextValueInSplayTree(coder_cache);
488 UnlockSemaphoreInfo(coder_semaphore);
489 return(coder_info);
490 }
491 coder_info=(const CoderInfo *) GetValueFromSplayTree(coder_cache,name);
492 UnlockSemaphoreInfo(coder_semaphore);
493 return(coder_info);
494 }
495
496 /*
497 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
498 % %
499 % %
500 % %
501 % G e t C o d e r I n f o L i s t %
502 % %
503 % %
504 % %
505 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
506 %
507 % GetCoderInfoList() returns any coder_map that match the specified pattern.
508 % The format of the GetCoderInfoList function is:
509 %
510 % const CoderInfo **GetCoderInfoList(const char *pattern,
511 % size_t *number_coders,ExceptionInfo *exception)
512 %
513 % A description of each parameter follows:
514 %
515 % o pattern: Specifies a pointer to a text string containing a pattern.
516 %
517 % o number_coders: This integer returns the number of coders in the list.
518 %
519 % o exception: return any errors or warnings in this structure.
520 %
521 */
522
CoderInfoCompare(const void * x,const void * y)523 static int CoderInfoCompare(const void *x,const void *y)
524 {
525 const CoderInfo
526 **p,
527 **q;
528
529 p=(const CoderInfo **) x,
530 q=(const CoderInfo **) y;
531 if (LocaleCompare((*p)->path,(*q)->path) == 0)
532 return(LocaleCompare((*p)->name,(*q)->name));
533 return(LocaleCompare((*p)->path,(*q)->path));
534 }
535
GetCoderInfoList(const char * pattern,size_t * number_coders,ExceptionInfo * exception)536 MagickExport const CoderInfo **GetCoderInfoList(const char *pattern,
537 size_t *number_coders,ExceptionInfo *exception)
538 {
539 const CoderInfo
540 **coder_map;
541
542 register const CoderInfo
543 *p;
544
545 register ssize_t
546 i;
547
548 /*
549 Allocate coder list.
550 */
551 assert(pattern != (char *) NULL);
552 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
553 assert(number_coders != (size_t *) NULL);
554 *number_coders=0;
555 p=GetCoderInfo("*",exception);
556 if (p == (const CoderInfo *) NULL)
557 return((const CoderInfo **) NULL);
558 coder_map=(const CoderInfo **) AcquireQuantumMemory((size_t)
559 GetNumberOfNodesInSplayTree(coder_cache)+1UL,sizeof(*coder_map));
560 if (coder_map == (const CoderInfo **) NULL)
561 return((const CoderInfo **) NULL);
562 /*
563 Generate coder list.
564 */
565 LockSemaphoreInfo(coder_semaphore);
566 ResetSplayTreeIterator(coder_cache);
567 p=(const CoderInfo *) GetNextValueInSplayTree(coder_cache);
568 for (i=0; p != (const CoderInfo *) NULL; )
569 {
570 if ((p->stealth == MagickFalse) &&
571 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
572 coder_map[i++]=p;
573 p=(const CoderInfo *) GetNextValueInSplayTree(coder_cache);
574 }
575 UnlockSemaphoreInfo(coder_semaphore);
576 qsort((void *) coder_map,(size_t) i,sizeof(*coder_map),CoderInfoCompare);
577 coder_map[i]=(CoderInfo *) NULL;
578 *number_coders=(size_t) i;
579 return(coder_map);
580 }
581
582 /*
583 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
584 % %
585 % %
586 % %
587 % G e t C o d e r L i s t %
588 % %
589 % %
590 % %
591 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
592 %
593 % GetCoderList() returns any coder_map that match the specified pattern.
594 %
595 % The format of the GetCoderList function is:
596 %
597 % char **GetCoderList(const char *pattern,size_t *number_coders,
598 % ExceptionInfo *exception)
599 %
600 % A description of each parameter follows:
601 %
602 % o pattern: Specifies a pointer to a text string containing a pattern.
603 %
604 % o number_coders: This integer returns the number of coders in the list.
605 %
606 % o exception: return any errors or warnings in this structure.
607 %
608 */
609
CoderCompare(const void * x,const void * y)610 static int CoderCompare(const void *x,const void *y)
611 {
612 register const char
613 **p,
614 **q;
615
616 p=(const char **) x;
617 q=(const char **) y;
618 return(LocaleCompare(*p,*q));
619 }
620
GetCoderList(const char * pattern,size_t * number_coders,ExceptionInfo * exception)621 MagickExport char **GetCoderList(const char *pattern,
622 size_t *number_coders,ExceptionInfo *exception)
623 {
624 char
625 **coder_map;
626
627 register const CoderInfo
628 *p;
629
630 register ssize_t
631 i;
632
633 /*
634 Allocate coder list.
635 */
636 assert(pattern != (char *) NULL);
637 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
638 assert(number_coders != (size_t *) NULL);
639 *number_coders=0;
640 p=GetCoderInfo("*",exception);
641 if (p == (const CoderInfo *) NULL)
642 return((char **) NULL);
643 coder_map=(char **) AcquireQuantumMemory((size_t)
644 GetNumberOfNodesInSplayTree(coder_cache)+1UL,sizeof(*coder_map));
645 if (coder_map == (char **) NULL)
646 return((char **) NULL);
647 /*
648 Generate coder list.
649 */
650 LockSemaphoreInfo(coder_semaphore);
651 ResetSplayTreeIterator(coder_cache);
652 p=(const CoderInfo *) GetNextValueInSplayTree(coder_cache);
653 for (i=0; p != (const CoderInfo *) NULL; )
654 {
655 if ((p->stealth == MagickFalse) &&
656 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
657 coder_map[i++]=ConstantString(p->name);
658 p=(const CoderInfo *) GetNextValueInSplayTree(coder_cache);
659 }
660 UnlockSemaphoreInfo(coder_semaphore);
661 qsort((void *) coder_map,(size_t) i,sizeof(*coder_map),CoderCompare);
662 coder_map[i]=(char *) NULL;
663 *number_coders=(size_t) i;
664 return(coder_map);
665 }
666
667 /*
668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
669 % %
670 % %
671 % %
672 + I s C o d e r T r e e I n s t a n t i a t e d %
673 % %
674 % %
675 % %
676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
677 %
678 % IsCoderTreeInstantiated() determines if the coder tree is instantiated. If
679 % not, it instantiates the tree and returns it.
680 %
681 % The format of the IsCoderInstantiated method is:
682 %
683 % MagickBooleanType IsCoderTreeInstantiated(ExceptionInfo *exception)
684 %
685 % A description of each parameter follows.
686 %
687 % o exception: return any errors or warnings in this structure.
688 %
689 */
IsCoderTreeInstantiated(ExceptionInfo * exception)690 static MagickBooleanType IsCoderTreeInstantiated(ExceptionInfo *exception)
691 {
692 if (coder_cache == (SplayTreeInfo *) NULL)
693 {
694 if (coder_semaphore == (SemaphoreInfo *) NULL)
695 ActivateSemaphoreInfo(&coder_semaphore);
696 LockSemaphoreInfo(coder_semaphore);
697 if (coder_cache == (SplayTreeInfo *) NULL)
698 coder_cache=AcquireCoderCache(MagickCoderFilename,exception);
699 UnlockSemaphoreInfo(coder_semaphore);
700 }
701 return(coder_cache != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
702 }
703
704 /*
705 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
706 % %
707 % %
708 % %
709 % L i s t C o d e r I n f o %
710 % %
711 % %
712 % %
713 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
714 %
715 % ListCoderInfo() lists the coder info to a file.
716 %
717 % The format of the ListCoderInfo coder is:
718 %
719 % MagickBooleanType ListCoderInfo(FILE *file,ExceptionInfo *exception)
720 %
721 % A description of each parameter follows.
722 %
723 % o file: An pointer to a FILE.
724 %
725 % o exception: return any errors or warnings in this structure.
726 %
727 */
ListCoderInfo(FILE * file,ExceptionInfo * exception)728 MagickExport MagickBooleanType ListCoderInfo(FILE *file,
729 ExceptionInfo *exception)
730 {
731 const char
732 *path;
733
734 const CoderInfo
735 **coder_info;
736
737 register ssize_t
738 i;
739
740 size_t
741 number_coders;
742
743 ssize_t
744 j;
745
746 if (file == (const FILE *) NULL)
747 file=stdout;
748 coder_info=GetCoderInfoList("*",&number_coders,exception);
749 if (coder_info == (const CoderInfo **) NULL)
750 return(MagickFalse);
751 path=(const char *) NULL;
752 for (i=0; i < (ssize_t) number_coders; i++)
753 {
754 if (coder_info[i]->stealth != MagickFalse)
755 continue;
756 if ((path == (const char *) NULL) ||
757 (LocaleCompare(path,coder_info[i]->path) != 0))
758 {
759 if (coder_info[i]->path != (char *) NULL)
760 (void) FormatLocaleFile(file,"\nPath: %s\n\n",coder_info[i]->path);
761 (void) FormatLocaleFile(file,"Magick Coder\n");
762 (void) FormatLocaleFile(file,
763 "-------------------------------------------------"
764 "------------------------------\n");
765 }
766 path=coder_info[i]->path;
767 (void) FormatLocaleFile(file,"%s",coder_info[i]->magick);
768 for (j=(ssize_t) strlen(coder_info[i]->magick); j <= 11; j++)
769 (void) FormatLocaleFile(file," ");
770 if (coder_info[i]->name != (char *) NULL)
771 (void) FormatLocaleFile(file,"%s",coder_info[i]->name);
772 (void) FormatLocaleFile(file,"\n");
773 }
774 coder_info=(const CoderInfo **) RelinquishMagickMemory((void *) coder_info);
775 (void) fflush(file);
776 return(MagickTrue);
777 }
778
779 /*
780 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
781 % %
782 % %
783 % %
784 + L o a d C o d e r C a c h e %
785 % %
786 % %
787 % %
788 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
789 %
790 % LoadCoderCache() loads the coder configurations which provides a
791 % mapping between coder attributes and a coder name.
792 %
793 % The format of the LoadCoderCache coder is:
794 %
795 % MagickBooleanType LoadCoderCache(SplayTreeInfo *cache,const char *xml,
796 % const char *filename,const size_t depth,ExceptionInfo *exception)
797 %
798 % A description of each parameter follows:
799 %
800 % o xml: The coder list in XML format.
801 %
802 % o filename: The coder list filename.
803 %
804 % o depth: depth of <include /> statements.
805 %
806 % o exception: return any errors or warnings in this structure.
807 %
808 */
LoadCoderCache(SplayTreeInfo * cache,const char * xml,const char * filename,const size_t depth,ExceptionInfo * exception)809 static MagickBooleanType LoadCoderCache(SplayTreeInfo *cache,const char *xml,
810 const char *filename,const size_t depth,ExceptionInfo *exception)
811 {
812 char
813 keyword[MagickPathExtent],
814 *token;
815
816 const char
817 *q;
818
819 CoderInfo
820 *coder_info;
821
822 MagickStatusType
823 status;
824
825 size_t
826 extent;
827
828 /*
829 Load the coder map file.
830 */
831 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
832 "Loading coder configuration file \"%s\" ...",filename);
833 if (xml == (const char *) NULL)
834 return(MagickFalse);
835 status=MagickTrue;
836 coder_info=(CoderInfo *) NULL;
837 token=AcquireString(xml);
838 extent=strlen(token)+MagickPathExtent;
839 for (q=(char *) xml; *q != '\0'; )
840 {
841 /*
842 Interpret XML.
843 */
844 GetNextToken(q,&q,extent,token);
845 if (*token == '\0')
846 break;
847 (void) CopyMagickString(keyword,token,MagickPathExtent);
848 if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
849 {
850 /*
851 Doctype element.
852 */
853 while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
854 GetNextToken(q,&q,extent,token);
855 continue;
856 }
857 if (LocaleNCompare(keyword,"<!--",4) == 0)
858 {
859 /*
860 Comment element.
861 */
862 while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
863 GetNextToken(q,&q,extent,token);
864 continue;
865 }
866 if (LocaleCompare(keyword,"<include") == 0)
867 {
868 /*
869 Include element.
870 */
871 while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
872 {
873 (void) CopyMagickString(keyword,token,MagickPathExtent);
874 GetNextToken(q,&q,extent,token);
875 if (*token != '=')
876 continue;
877 GetNextToken(q,&q,extent,token);
878 if (LocaleCompare(keyword,"file") == 0)
879 {
880 if (depth > 200)
881 (void) ThrowMagickException(exception,GetMagickModule(),
882 ConfigureError,"IncludeNodeNestedTooDeeply","`%s'",token);
883 else
884 {
885 char
886 path[MagickPathExtent],
887 *file_xml;
888
889 GetPathComponent(filename,HeadPath,path);
890 if (*path != '\0')
891 (void) ConcatenateMagickString(path,DirectorySeparator,
892 MagickPathExtent);
893 if (*token == *DirectorySeparator)
894 (void) CopyMagickString(path,token,MagickPathExtent);
895 else
896 (void) ConcatenateMagickString(path,token,MagickPathExtent);
897 file_xml=FileToXML(path,~0UL);
898 if (file_xml != (char *) NULL)
899 {
900 status&=LoadCoderCache(cache,file_xml,path,depth+1,
901 exception);
902 file_xml=DestroyString(file_xml);
903 }
904 }
905 }
906 }
907 continue;
908 }
909 if (LocaleCompare(keyword,"<coder") == 0)
910 {
911 /*
912 Coder element.
913 */
914 coder_info=(CoderInfo *) AcquireMagickMemory(sizeof(*coder_info));
915 if (coder_info == (CoderInfo *) NULL)
916 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
917 (void) ResetMagickMemory(coder_info,0,sizeof(*coder_info));
918 coder_info->path=ConstantString(filename);
919 coder_info->exempt=MagickFalse;
920 coder_info->signature=MagickCoreSignature;
921 continue;
922 }
923 if (coder_info == (CoderInfo *) NULL)
924 continue;
925 if (LocaleCompare(keyword,"/>") == 0)
926 {
927 status=AddValueToSplayTree(cache,ConstantString(coder_info->magick),
928 coder_info);
929 if (status == MagickFalse)
930 (void) ThrowMagickException(exception,GetMagickModule(),
931 ResourceLimitError,"MemoryAllocationFailed","`%s'",
932 coder_info->magick);
933 coder_info=(CoderInfo *) NULL;
934 continue;
935 }
936 GetNextToken(q,(const char **) NULL,extent,token);
937 if (*token != '=')
938 continue;
939 GetNextToken(q,&q,extent,token);
940 GetNextToken(q,&q,extent,token);
941 switch (*keyword)
942 {
943 case 'M':
944 case 'm':
945 {
946 if (LocaleCompare((char *) keyword,"magick") == 0)
947 {
948 coder_info->magick=ConstantString(token);
949 break;
950 }
951 break;
952 }
953 case 'N':
954 case 'n':
955 {
956 if (LocaleCompare((char *) keyword,"name") == 0)
957 {
958 coder_info->name=ConstantString(token);
959 break;
960 }
961 break;
962 }
963 case 'S':
964 case 's':
965 {
966 if (LocaleCompare((char *) keyword,"stealth") == 0)
967 {
968 coder_info->stealth=IsStringTrue(token);
969 break;
970 }
971 break;
972 }
973 default:
974 break;
975 }
976 }
977 token=(char *) RelinquishMagickMemory(token);
978 return(status != 0 ? MagickTrue : MagickFalse);
979 }
980