blob: fb3d62a94be500d0a62a6b8db1709aa1cb243020 [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
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 %
cristyde984cd2013-12-01 14:49:27 +000016% Cristy %
cristy3ed852e2009-09-05 21:47:34 +000017% May 2001 %
18% %
19% %
Cristy93b707b2017-12-06 07:05:51 -050020% Copyright 1999-2018 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% 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% %
Cristy9ddfcca2018-09-09 19:46:34 -040026% https://imagemagick.org/script/license.php %
cristy3ed852e2009-09-05 21:47:34 +000027% %
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*/
cristy4c08aed2011-07-01 19:47:50 +000042#include "MagickCore/studio.h"
43#include "MagickCore/blob.h"
44#include "MagickCore/client.h"
45#include "MagickCore/coder.h"
cristy5ff4eaf2011-09-03 01:38:02 +000046#include "MagickCore/coder-private.h"
cristy4c08aed2011-07-01 19:47:50 +000047#include "MagickCore/configure.h"
48#include "MagickCore/draw.h"
49#include "MagickCore/exception.h"
50#include "MagickCore/exception-private.h"
dirkabed7e22016-01-31 17:10:21 +010051#include "MagickCore/linked-list.h"
cristy4c08aed2011-07-01 19:47:50 +000052#include "MagickCore/log.h"
53#include "MagickCore/memory_.h"
Dirk Lemstra06344a02017-10-15 10:10:01 +020054#include "MagickCore/memory-private.h"
cristy4c08aed2011-07-01 19:47:50 +000055#include "MagickCore/option.h"
56#include "MagickCore/semaphore.h"
57#include "MagickCore/string_.h"
58#include "MagickCore/splay-tree.h"
59#include "MagickCore/token.h"
60#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000061#include "MagickCore/utility-private.h"
cristy4c08aed2011-07-01 19:47:50 +000062#include "MagickCore/xml-tree.h"
cristy3291f512014-03-16 22:16:22 +000063#include "MagickCore/xml-tree-private.h"
Dirk Lemstra826cbeb2018-10-05 00:12:46 +020064#include "coders/coders.h"
65
66/*
67 Define declarations.
68*/
69#define AddMagickCoder(coder) Magick ## coder ## Aliases
cristy3ed852e2009-09-05 21:47:34 +000070
71/*
cristy54a531d2009-10-21 17:58:01 +000072 Typedef declarations.
cristy3ed852e2009-09-05 21:47:34 +000073*/
cristye3e77a12009-10-16 00:47:21 +000074typedef struct _CoderMapInfo
75{
76 const char
77 *magick,
78 *name;
79} CoderMapInfo;
cristy54a531d2009-10-21 17:58:01 +000080
81/*
82 Static declarations.
83*/
cristye3e77a12009-10-16 00:47:21 +000084static const CoderMapInfo
85 CoderMap[] =
86 {
Dirk Lemstra826cbeb2018-10-05 00:12:46 +020087 #include "coders/coders-list.h"
cristye3e77a12009-10-16 00:47:21 +000088 };
89
cristy3ed852e2009-09-05 21:47:34 +000090static SemaphoreInfo
91 *coder_semaphore = (SemaphoreInfo *) NULL;
92
93static SplayTreeInfo
cristy86e5ac92014-03-16 19:27:39 +000094 *coder_cache = (SplayTreeInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +000095
96/*
97 Forward declarations.
98*/
99static MagickBooleanType
Dirk Lemstrae2939a42018-10-04 23:20:08 +0200100 IsCoderTreeInstantiated(ExceptionInfo *);
cristy86e5ac92014-03-16 19:27:39 +0000101
102/*
103%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
104% %
105% %
106% %
cristy6c6322e2014-09-09 22:39:21 +0000107+ A c q u i r e C o d e r C a c h e %
cristy86e5ac92014-03-16 19:27:39 +0000108% %
109% %
110% %
111%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
112%
cristy6c6322e2014-09-09 22:39:21 +0000113% AcquireCoderCache() caches one or more coder configurations which provides a
114% mapping between coder attributes and a coder name.
cristy86e5ac92014-03-16 19:27:39 +0000115%
116% The format of the AcquireCoderCache coder is:
117%
118% SplayTreeInfo *AcquireCoderCache(const char *filename,
119% ExceptionInfo *exception)
120%
121% A description of each parameter follows:
122%
123% o filename: the font file name.
124%
125% o exception: return any errors or warnings in this structure.
126%
127*/
128
129static void *DestroyCoderNode(void *coder_info)
130{
131 register CoderInfo
132 *p;
133
134 p=(CoderInfo *) coder_info;
135 if (p->exempt == MagickFalse)
136 {
137 if (p->path != (char *) NULL)
138 p->path=DestroyString(p->path);
139 if (p->name != (char *) NULL)
140 p->name=DestroyString(p->name);
141 if (p->magick != (char *) NULL)
142 p->magick=DestroyString(p->magick);
143 }
144 return(RelinquishMagickMemory(p));
145}
146
Dirk Lemstrae2939a42018-10-04 23:20:08 +0200147static SplayTreeInfo *AcquireCoderCache(ExceptionInfo *exception)
cristy86e5ac92014-03-16 19:27:39 +0000148{
cristy86e5ac92014-03-16 19:27:39 +0000149 MagickStatusType
150 status;
151
152 register ssize_t
153 i;
154
155 SplayTreeInfo
dirkb18d8642016-07-17 19:32:43 +0200156 *cache;
cristy86e5ac92014-03-16 19:27:39 +0000157
158 /*
Dirk Lemstrae2939a42018-10-04 23:20:08 +0200159 Load built-in coder map.
cristy86e5ac92014-03-16 19:27:39 +0000160 */
dirkb18d8642016-07-17 19:32:43 +0200161 cache=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
cristy86e5ac92014-03-16 19:27:39 +0000162 DestroyCoderNode);
cristy86e5ac92014-03-16 19:27:39 +0000163 status=MagickTrue;
cristy86e5ac92014-03-16 19:27:39 +0000164 for (i=0; i < (ssize_t) (sizeof(CoderMap)/sizeof(*CoderMap)); i++)
165 {
166 CoderInfo
167 *coder_info;
168
169 register const CoderMapInfo
170 *p;
171
172 p=CoderMap+i;
173 coder_info=(CoderInfo *) AcquireMagickMemory(sizeof(*coder_info));
174 if (coder_info == (CoderInfo *) NULL)
175 {
176 (void) ThrowMagickException(exception,GetMagickModule(),
177 ResourceLimitError,"MemoryAllocationFailed","`%s'",p->name);
178 continue;
179 }
Cristy81bfff22018-03-10 07:58:31 -0500180 (void) memset(coder_info,0,sizeof(*coder_info));
cristy86e5ac92014-03-16 19:27:39 +0000181 coder_info->path=(char *) "[built-in]";
182 coder_info->magick=(char *) p->magick;
183 coder_info->name=(char *) p->name;
184 coder_info->exempt=MagickTrue;
cristye1c94d92015-06-28 12:16:33 +0000185 coder_info->signature=MagickCoreSignature;
dirkb18d8642016-07-17 19:32:43 +0200186 status&=AddValueToSplayTree(cache,ConstantString(coder_info->magick),
cristy86e5ac92014-03-16 19:27:39 +0000187 coder_info);
188 if (status == MagickFalse)
189 (void) ThrowMagickException(exception,GetMagickModule(),
190 ResourceLimitError,"MemoryAllocationFailed","`%s'",coder_info->name);
191 }
dirkb18d8642016-07-17 19:32:43 +0200192 return(cache);
cristy86e5ac92014-03-16 19:27:39 +0000193}
cristy3ed852e2009-09-05 21:47:34 +0000194
195/*
196%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
197% %
198% %
199% %
cristyf34a1452009-10-24 22:29:27 +0000200+ C o d e r C o m p o n e n t G e n e s i s %
cristy3ed852e2009-09-05 21:47:34 +0000201% %
202% %
203% %
204%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
205%
cristyf34a1452009-10-24 22:29:27 +0000206% CoderComponentGenesis() instantiates the coder component.
cristy3ed852e2009-09-05 21:47:34 +0000207%
cristyf34a1452009-10-24 22:29:27 +0000208% The format of the CoderComponentGenesis method is:
cristy3ed852e2009-09-05 21:47:34 +0000209%
cristyf34a1452009-10-24 22:29:27 +0000210% MagickBooleanType CoderComponentGenesis(void)
cristy3ed852e2009-09-05 21:47:34 +0000211%
212*/
cristy5ff4eaf2011-09-03 01:38:02 +0000213MagickPrivate MagickBooleanType CoderComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +0000214{
cristy7c977062014-04-04 14:05:53 +0000215 if (coder_semaphore == (SemaphoreInfo *) NULL)
216 coder_semaphore=AcquireSemaphoreInfo();
cristyf34a1452009-10-24 22:29:27 +0000217 return(MagickTrue);
218}
219
220/*
221%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
222% %
223% %
224% %
225+ C o d e r C o m p o n e n t T e r m i n u s %
226% %
227% %
228% %
229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
230%
231% CoderComponentTerminus() destroys the coder component.
232%
233% The format of the CoderComponentTerminus method is:
234%
235% CoderComponentTerminus(void)
236%
237*/
cristy5ff4eaf2011-09-03 01:38:02 +0000238MagickPrivate void CoderComponentTerminus(void)
cristy3ed852e2009-09-05 21:47:34 +0000239{
cristy18b17442009-10-25 18:36:48 +0000240 if (coder_semaphore == (SemaphoreInfo *) NULL)
cristy04b11db2014-02-16 15:10:39 +0000241 ActivateSemaphoreInfo(&coder_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000242 LockSemaphoreInfo(coder_semaphore);
cristy86e5ac92014-03-16 19:27:39 +0000243 if (coder_cache != (SplayTreeInfo *) NULL)
244 coder_cache=DestroySplayTree(coder_cache);
cristyf84a1932010-01-03 18:00:18 +0000245 UnlockSemaphoreInfo(coder_semaphore);
cristy3d162a92014-02-16 14:05:06 +0000246 RelinquishSemaphoreInfo(&coder_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000247}
248
249/*
250%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
251% %
252% %
253% %
254+ G e t C o d e r I n f o %
255% %
256% %
257% %
258%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
259%
260% GetCoderInfo searches the coder list for the specified name and if found
261% returns attributes for that coder.
262%
263% The format of the GetCoderInfo method is:
264%
265% const CoderInfo *GetCoderInfo(const char *name,ExceptionInfo *exception)
266%
267% A description of each parameter follows:
268%
269% o name: the coder name.
270%
271% o exception: return any errors or warnings in this structure.
272%
273*/
274MagickExport const CoderInfo *GetCoderInfo(const char *name,
275 ExceptionInfo *exception)
276{
277 assert(exception != (ExceptionInfo *) NULL);
cristy904e5912014-03-15 19:53:14 +0000278 if (IsCoderTreeInstantiated(exception) == MagickFalse)
279 return((const CoderInfo *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000280 if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
Cristy1d8b1f12017-09-16 10:13:23 -0400281 return((const CoderInfo *) GetRootValueFromSplayTree(coder_cache));
282 return((const CoderInfo *) GetValueFromSplayTree(coder_cache,name));
cristy3ed852e2009-09-05 21:47:34 +0000283}
284
285/*
286%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
287% %
288% %
289% %
290% G e t C o d e r I n f o L i s t %
291% %
292% %
293% %
294%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
295%
296% GetCoderInfoList() returns any coder_map that match the specified pattern.
297% The format of the GetCoderInfoList function is:
298%
299% const CoderInfo **GetCoderInfoList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000300% size_t *number_coders,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000301%
302% A description of each parameter follows:
303%
304% o pattern: Specifies a pointer to a text string containing a pattern.
305%
306% o number_coders: This integer returns the number of coders in the list.
307%
308% o exception: return any errors or warnings in this structure.
309%
310*/
311
312static int CoderInfoCompare(const void *x,const void *y)
313{
314 const CoderInfo
315 **p,
316 **q;
317
318 p=(const CoderInfo **) x,
319 q=(const CoderInfo **) y;
320 if (LocaleCompare((*p)->path,(*q)->path) == 0)
321 return(LocaleCompare((*p)->name,(*q)->name));
322 return(LocaleCompare((*p)->path,(*q)->path));
323}
324
325MagickExport const CoderInfo **GetCoderInfoList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000326 size_t *number_coders,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000327{
328 const CoderInfo
329 **coder_map;
330
331 register const CoderInfo
332 *p;
333
cristybb503372010-05-27 20:51:26 +0000334 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000335 i;
336
337 /*
338 Allocate coder list.
339 */
340 assert(pattern != (char *) NULL);
341 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
cristybb503372010-05-27 20:51:26 +0000342 assert(number_coders != (size_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000343 *number_coders=0;
344 p=GetCoderInfo("*",exception);
345 if (p == (const CoderInfo *) NULL)
346 return((const CoderInfo **) NULL);
347 coder_map=(const CoderInfo **) AcquireQuantumMemory((size_t)
cristy86e5ac92014-03-16 19:27:39 +0000348 GetNumberOfNodesInSplayTree(coder_cache)+1UL,sizeof(*coder_map));
cristy3ed852e2009-09-05 21:47:34 +0000349 if (coder_map == (const CoderInfo **) NULL)
350 return((const CoderInfo **) NULL);
351 /*
352 Generate coder list.
353 */
cristyf84a1932010-01-03 18:00:18 +0000354 LockSemaphoreInfo(coder_semaphore);
cristy86e5ac92014-03-16 19:27:39 +0000355 ResetSplayTreeIterator(coder_cache);
356 p=(const CoderInfo *) GetNextValueInSplayTree(coder_cache);
cristy3ed852e2009-09-05 21:47:34 +0000357 for (i=0; p != (const CoderInfo *) NULL; )
358 {
359 if ((p->stealth == MagickFalse) &&
360 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
361 coder_map[i++]=p;
cristy86e5ac92014-03-16 19:27:39 +0000362 p=(const CoderInfo *) GetNextValueInSplayTree(coder_cache);
cristy3ed852e2009-09-05 21:47:34 +0000363 }
cristyf84a1932010-01-03 18:00:18 +0000364 UnlockSemaphoreInfo(coder_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000365 qsort((void *) coder_map,(size_t) i,sizeof(*coder_map),CoderInfoCompare);
366 coder_map[i]=(CoderInfo *) NULL;
cristybb503372010-05-27 20:51:26 +0000367 *number_coders=(size_t) i;
cristy3ed852e2009-09-05 21:47:34 +0000368 return(coder_map);
369}
370
371/*
372%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
373% %
374% %
375% %
376% G e t C o d e r L i s t %
377% %
378% %
379% %
380%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
381%
382% GetCoderList() returns any coder_map that match the specified pattern.
383%
384% The format of the GetCoderList function is:
385%
cristybb503372010-05-27 20:51:26 +0000386% char **GetCoderList(const char *pattern,size_t *number_coders,
cristy3ed852e2009-09-05 21:47:34 +0000387% ExceptionInfo *exception)
388%
389% A description of each parameter follows:
390%
391% o pattern: Specifies a pointer to a text string containing a pattern.
392%
393% o number_coders: This integer returns the number of coders in the list.
394%
395% o exception: return any errors or warnings in this structure.
396%
397*/
398
399static int CoderCompare(const void *x,const void *y)
400{
401 register const char
402 **p,
403 **q;
404
405 p=(const char **) x;
406 q=(const char **) y;
407 return(LocaleCompare(*p,*q));
408}
409
410MagickExport char **GetCoderList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000411 size_t *number_coders,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000412{
413 char
414 **coder_map;
415
416 register const CoderInfo
417 *p;
418
cristybb503372010-05-27 20:51:26 +0000419 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000420 i;
421
422 /*
423 Allocate coder list.
424 */
425 assert(pattern != (char *) NULL);
426 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
cristybb503372010-05-27 20:51:26 +0000427 assert(number_coders != (size_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000428 *number_coders=0;
429 p=GetCoderInfo("*",exception);
430 if (p == (const CoderInfo *) NULL)
431 return((char **) NULL);
432 coder_map=(char **) AcquireQuantumMemory((size_t)
cristy86e5ac92014-03-16 19:27:39 +0000433 GetNumberOfNodesInSplayTree(coder_cache)+1UL,sizeof(*coder_map));
cristy3ed852e2009-09-05 21:47:34 +0000434 if (coder_map == (char **) NULL)
435 return((char **) NULL);
436 /*
437 Generate coder list.
438 */
cristyf84a1932010-01-03 18:00:18 +0000439 LockSemaphoreInfo(coder_semaphore);
cristy86e5ac92014-03-16 19:27:39 +0000440 ResetSplayTreeIterator(coder_cache);
441 p=(const CoderInfo *) GetNextValueInSplayTree(coder_cache);
cristy3ed852e2009-09-05 21:47:34 +0000442 for (i=0; p != (const CoderInfo *) NULL; )
443 {
444 if ((p->stealth == MagickFalse) &&
445 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
446 coder_map[i++]=ConstantString(p->name);
cristy86e5ac92014-03-16 19:27:39 +0000447 p=(const CoderInfo *) GetNextValueInSplayTree(coder_cache);
cristy3ed852e2009-09-05 21:47:34 +0000448 }
cristyf84a1932010-01-03 18:00:18 +0000449 UnlockSemaphoreInfo(coder_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000450 qsort((void *) coder_map,(size_t) i,sizeof(*coder_map),CoderCompare);
451 coder_map[i]=(char *) NULL;
cristybb503372010-05-27 20:51:26 +0000452 *number_coders=(size_t) i;
cristy3ed852e2009-09-05 21:47:34 +0000453 return(coder_map);
454}
455
456/*
457%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
458% %
459% %
460% %
cristy904e5912014-03-15 19:53:14 +0000461+ I s C o d e r T r e e I n s t a n t i a t e d %
cristy3ed852e2009-09-05 21:47:34 +0000462% %
463% %
464% %
465%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
466%
cristycd2cd182014-03-18 12:10:55 +0000467% IsCoderTreeInstantiated() determines if the coder tree is instantiated. If
468% not, it instantiates the tree and returns it.
cristy3ed852e2009-09-05 21:47:34 +0000469%
cristy904e5912014-03-15 19:53:14 +0000470% The format of the IsCoderInstantiated method is:
cristy3ed852e2009-09-05 21:47:34 +0000471%
cristy904e5912014-03-15 19:53:14 +0000472% MagickBooleanType IsCoderTreeInstantiated(ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000473%
474% A description of each parameter follows.
475%
476% o exception: return any errors or warnings in this structure.
477%
478*/
cristy904e5912014-03-15 19:53:14 +0000479static MagickBooleanType IsCoderTreeInstantiated(ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000480{
cristy86e5ac92014-03-16 19:27:39 +0000481 if (coder_cache == (SplayTreeInfo *) NULL)
482 {
483 if (coder_semaphore == (SemaphoreInfo *) NULL)
484 ActivateSemaphoreInfo(&coder_semaphore);
485 LockSemaphoreInfo(coder_semaphore);
486 if (coder_cache == (SplayTreeInfo *) NULL)
Dirk Lemstrae2939a42018-10-04 23:20:08 +0200487 coder_cache=AcquireCoderCache(exception);
cristy86e5ac92014-03-16 19:27:39 +0000488 UnlockSemaphoreInfo(coder_semaphore);
489 }
490 return(coder_cache != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000491}
492
493/*
494%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
495% %
496% %
497% %
498% L i s t C o d e r I n f o %
499% %
500% %
501% %
502%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
503%
504% ListCoderInfo() lists the coder info to a file.
505%
506% The format of the ListCoderInfo coder is:
507%
508% MagickBooleanType ListCoderInfo(FILE *file,ExceptionInfo *exception)
509%
510% A description of each parameter follows.
511%
512% o file: An pointer to a FILE.
513%
514% o exception: return any errors or warnings in this structure.
515%
516*/
517MagickExport MagickBooleanType ListCoderInfo(FILE *file,
518 ExceptionInfo *exception)
519{
520 const char
521 *path;
522
523 const CoderInfo
524 **coder_info;
525
cristybb503372010-05-27 20:51:26 +0000526 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000527 i;
528
cristybb503372010-05-27 20:51:26 +0000529 size_t
cristy3ed852e2009-09-05 21:47:34 +0000530 number_coders;
531
cristy9d314ff2011-03-09 01:30:28 +0000532 ssize_t
533 j;
534
cristy3ed852e2009-09-05 21:47:34 +0000535 if (file == (const FILE *) NULL)
536 file=stdout;
537 coder_info=GetCoderInfoList("*",&number_coders,exception);
538 if (coder_info == (const CoderInfo **) NULL)
539 return(MagickFalse);
540 path=(const char *) NULL;
cristybb503372010-05-27 20:51:26 +0000541 for (i=0; i < (ssize_t) number_coders; i++)
cristy3ed852e2009-09-05 21:47:34 +0000542 {
543 if (coder_info[i]->stealth != MagickFalse)
544 continue;
545 if ((path == (const char *) NULL) ||
546 (LocaleCompare(path,coder_info[i]->path) != 0))
547 {
548 if (coder_info[i]->path != (char *) NULL)
cristyb51dff52011-05-19 16:55:47 +0000549 (void) FormatLocaleFile(file,"\nPath: %s\n\n",coder_info[i]->path);
550 (void) FormatLocaleFile(file,"Magick Coder\n");
cristy1e604812011-05-19 18:07:50 +0000551 (void) FormatLocaleFile(file,
552 "-------------------------------------------------"
cristy3ed852e2009-09-05 21:47:34 +0000553 "------------------------------\n");
554 }
555 path=coder_info[i]->path;
cristyb51dff52011-05-19 16:55:47 +0000556 (void) FormatLocaleFile(file,"%s",coder_info[i]->magick);
cristybb503372010-05-27 20:51:26 +0000557 for (j=(ssize_t) strlen(coder_info[i]->magick); j <= 11; j++)
cristyb51dff52011-05-19 16:55:47 +0000558 (void) FormatLocaleFile(file," ");
cristy3ed852e2009-09-05 21:47:34 +0000559 if (coder_info[i]->name != (char *) NULL)
cristyb51dff52011-05-19 16:55:47 +0000560 (void) FormatLocaleFile(file,"%s",coder_info[i]->name);
561 (void) FormatLocaleFile(file,"\n");
cristy3ed852e2009-09-05 21:47:34 +0000562 }
563 coder_info=(const CoderInfo **) RelinquishMagickMemory((void *) coder_info);
564 (void) fflush(file);
565 return(MagickTrue);
566}