blob: 8b0abaf8d63512f13dafaac739e145d696d186b6 [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% %
Cristyf775a5c2019-11-26 14:27:47 -050020% Copyright 1999-2020 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"
cristy4c08aed2011-07-01 19:47:50 +000051#include "MagickCore/log.h"
52#include "MagickCore/memory_.h"
Dirk Lemstra06344a02017-10-15 10:10:01 +020053#include "MagickCore/memory-private.h"
cristy4c08aed2011-07-01 19:47:50 +000054#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"
cristyd1dd6e42011-09-04 01:46:08 +000060#include "MagickCore/utility-private.h"
Dirk Lemstra826cbeb2018-10-05 00:12:46 +020061#include "coders/coders.h"
62
63/*
64 Define declarations.
65*/
66#define AddMagickCoder(coder) Magick ## coder ## Aliases
cristy3ed852e2009-09-05 21:47:34 +000067
68/*
cristy54a531d2009-10-21 17:58:01 +000069 Typedef declarations.
cristy3ed852e2009-09-05 21:47:34 +000070*/
cristye3e77a12009-10-16 00:47:21 +000071typedef struct _CoderMapInfo
72{
73 const char
74 *magick,
75 *name;
76} CoderMapInfo;
cristy54a531d2009-10-21 17:58:01 +000077
78/*
79 Static declarations.
80*/
cristye3e77a12009-10-16 00:47:21 +000081static const CoderMapInfo
82 CoderMap[] =
83 {
Dirk Lemstra826cbeb2018-10-05 00:12:46 +020084 #include "coders/coders-list.h"
Dirk Lemstra7ad38d12018-10-05 07:52:22 +020085 };
cristye3e77a12009-10-16 00:47:21 +000086
cristy3ed852e2009-09-05 21:47:34 +000087static SemaphoreInfo
88 *coder_semaphore = (SemaphoreInfo *) NULL;
89
90static SplayTreeInfo
cristy86e5ac92014-03-16 19:27:39 +000091 *coder_cache = (SplayTreeInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +000092
93/*
94 Forward declarations.
95*/
96static MagickBooleanType
Dirk Lemstrae2939a42018-10-04 23:20:08 +020097 IsCoderTreeInstantiated(ExceptionInfo *);
cristy86e5ac92014-03-16 19:27:39 +000098
99/*
100%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
101% %
102% %
103% %
cristy6c6322e2014-09-09 22:39:21 +0000104+ A c q u i r e C o d e r C a c h e %
cristy86e5ac92014-03-16 19:27:39 +0000105% %
106% %
107% %
108%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
109%
cristy6c6322e2014-09-09 22:39:21 +0000110% AcquireCoderCache() caches one or more coder configurations which provides a
111% mapping between coder attributes and a coder name.
cristy86e5ac92014-03-16 19:27:39 +0000112%
113% The format of the AcquireCoderCache coder is:
114%
115% SplayTreeInfo *AcquireCoderCache(const char *filename,
116% ExceptionInfo *exception)
117%
118% A description of each parameter follows:
119%
120% o filename: the font file name.
121%
122% o exception: return any errors or warnings in this structure.
123%
124*/
125
126static void *DestroyCoderNode(void *coder_info)
127{
128 register CoderInfo
129 *p;
130
131 p=(CoderInfo *) coder_info;
132 if (p->exempt == MagickFalse)
133 {
134 if (p->path != (char *) NULL)
135 p->path=DestroyString(p->path);
136 if (p->name != (char *) NULL)
137 p->name=DestroyString(p->name);
138 if (p->magick != (char *) NULL)
139 p->magick=DestroyString(p->magick);
140 }
141 return(RelinquishMagickMemory(p));
142}
143
Dirk Lemstrae2939a42018-10-04 23:20:08 +0200144static SplayTreeInfo *AcquireCoderCache(ExceptionInfo *exception)
cristy86e5ac92014-03-16 19:27:39 +0000145{
cristy86e5ac92014-03-16 19:27:39 +0000146 MagickStatusType
147 status;
148
149 register ssize_t
150 i;
151
152 SplayTreeInfo
dirkb18d8642016-07-17 19:32:43 +0200153 *cache;
cristy86e5ac92014-03-16 19:27:39 +0000154
155 /*
Dirk Lemstrae2939a42018-10-04 23:20:08 +0200156 Load built-in coder map.
cristy86e5ac92014-03-16 19:27:39 +0000157 */
dirkb18d8642016-07-17 19:32:43 +0200158 cache=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
cristy86e5ac92014-03-16 19:27:39 +0000159 DestroyCoderNode);
cristy86e5ac92014-03-16 19:27:39 +0000160 status=MagickTrue;
cristy86e5ac92014-03-16 19:27:39 +0000161 for (i=0; i < (ssize_t) (sizeof(CoderMap)/sizeof(*CoderMap)); i++)
162 {
163 CoderInfo
164 *coder_info;
165
166 register const CoderMapInfo
167 *p;
168
169 p=CoderMap+i;
170 coder_info=(CoderInfo *) AcquireMagickMemory(sizeof(*coder_info));
171 if (coder_info == (CoderInfo *) NULL)
172 {
173 (void) ThrowMagickException(exception,GetMagickModule(),
174 ResourceLimitError,"MemoryAllocationFailed","`%s'",p->name);
175 continue;
176 }
Cristy81bfff22018-03-10 07:58:31 -0500177 (void) memset(coder_info,0,sizeof(*coder_info));
cristy86e5ac92014-03-16 19:27:39 +0000178 coder_info->path=(char *) "[built-in]";
179 coder_info->magick=(char *) p->magick;
180 coder_info->name=(char *) p->name;
181 coder_info->exempt=MagickTrue;
cristye1c94d92015-06-28 12:16:33 +0000182 coder_info->signature=MagickCoreSignature;
dirkb18d8642016-07-17 19:32:43 +0200183 status&=AddValueToSplayTree(cache,ConstantString(coder_info->magick),
cristy86e5ac92014-03-16 19:27:39 +0000184 coder_info);
185 if (status == MagickFalse)
186 (void) ThrowMagickException(exception,GetMagickModule(),
187 ResourceLimitError,"MemoryAllocationFailed","`%s'",coder_info->name);
188 }
dirkb18d8642016-07-17 19:32:43 +0200189 return(cache);
cristy86e5ac92014-03-16 19:27:39 +0000190}
cristy3ed852e2009-09-05 21:47:34 +0000191
192/*
193%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
194% %
195% %
196% %
cristyf34a1452009-10-24 22:29:27 +0000197+ 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 +0000198% %
199% %
200% %
201%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
202%
cristyf34a1452009-10-24 22:29:27 +0000203% CoderComponentGenesis() instantiates the coder component.
cristy3ed852e2009-09-05 21:47:34 +0000204%
cristyf34a1452009-10-24 22:29:27 +0000205% The format of the CoderComponentGenesis method is:
cristy3ed852e2009-09-05 21:47:34 +0000206%
cristyf34a1452009-10-24 22:29:27 +0000207% MagickBooleanType CoderComponentGenesis(void)
cristy3ed852e2009-09-05 21:47:34 +0000208%
209*/
cristy5ff4eaf2011-09-03 01:38:02 +0000210MagickPrivate MagickBooleanType CoderComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +0000211{
cristy7c977062014-04-04 14:05:53 +0000212 if (coder_semaphore == (SemaphoreInfo *) NULL)
213 coder_semaphore=AcquireSemaphoreInfo();
cristyf34a1452009-10-24 22:29:27 +0000214 return(MagickTrue);
215}
216
217/*
218%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
219% %
220% %
221% %
222+ C o d e r C o m p o n e n t T e r m i n u s %
223% %
224% %
225% %
226%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
227%
228% CoderComponentTerminus() destroys the coder component.
229%
230% The format of the CoderComponentTerminus method is:
231%
232% CoderComponentTerminus(void)
233%
234*/
cristy5ff4eaf2011-09-03 01:38:02 +0000235MagickPrivate void CoderComponentTerminus(void)
cristy3ed852e2009-09-05 21:47:34 +0000236{
cristy18b17442009-10-25 18:36:48 +0000237 if (coder_semaphore == (SemaphoreInfo *) NULL)
cristy04b11db2014-02-16 15:10:39 +0000238 ActivateSemaphoreInfo(&coder_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000239 LockSemaphoreInfo(coder_semaphore);
cristy86e5ac92014-03-16 19:27:39 +0000240 if (coder_cache != (SplayTreeInfo *) NULL)
241 coder_cache=DestroySplayTree(coder_cache);
cristyf84a1932010-01-03 18:00:18 +0000242 UnlockSemaphoreInfo(coder_semaphore);
cristy3d162a92014-02-16 14:05:06 +0000243 RelinquishSemaphoreInfo(&coder_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000244}
245
246/*
247%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
248% %
249% %
250% %
251+ G e t C o d e r I n f o %
252% %
253% %
254% %
255%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
256%
257% GetCoderInfo searches the coder list for the specified name and if found
258% returns attributes for that coder.
259%
260% The format of the GetCoderInfo method is:
261%
262% const CoderInfo *GetCoderInfo(const char *name,ExceptionInfo *exception)
263%
264% A description of each parameter follows:
265%
266% o name: the coder name.
267%
268% o exception: return any errors or warnings in this structure.
269%
270*/
271MagickExport const CoderInfo *GetCoderInfo(const char *name,
272 ExceptionInfo *exception)
273{
274 assert(exception != (ExceptionInfo *) NULL);
cristy904e5912014-03-15 19:53:14 +0000275 if (IsCoderTreeInstantiated(exception) == MagickFalse)
276 return((const CoderInfo *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000277 if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
Cristy1d8b1f12017-09-16 10:13:23 -0400278 return((const CoderInfo *) GetRootValueFromSplayTree(coder_cache));
279 return((const CoderInfo *) GetValueFromSplayTree(coder_cache,name));
cristy3ed852e2009-09-05 21:47:34 +0000280}
281
282/*
283%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
284% %
285% %
286% %
287% G e t C o d e r I n f o L i s t %
288% %
289% %
290% %
291%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
292%
293% GetCoderInfoList() returns any coder_map that match the specified pattern.
294% The format of the GetCoderInfoList function is:
295%
296% const CoderInfo **GetCoderInfoList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000297% size_t *number_coders,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000298%
299% A description of each parameter follows:
300%
301% o pattern: Specifies a pointer to a text string containing a pattern.
302%
303% o number_coders: This integer returns the number of coders in the list.
304%
305% o exception: return any errors or warnings in this structure.
306%
307*/
308
309static int CoderInfoCompare(const void *x,const void *y)
310{
311 const CoderInfo
312 **p,
313 **q;
314
315 p=(const CoderInfo **) x,
316 q=(const CoderInfo **) y;
317 if (LocaleCompare((*p)->path,(*q)->path) == 0)
318 return(LocaleCompare((*p)->name,(*q)->name));
319 return(LocaleCompare((*p)->path,(*q)->path));
320}
321
322MagickExport const CoderInfo **GetCoderInfoList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000323 size_t *number_coders,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000324{
325 const CoderInfo
326 **coder_map;
327
328 register const CoderInfo
329 *p;
330
cristybb503372010-05-27 20:51:26 +0000331 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000332 i;
333
334 /*
335 Allocate coder list.
336 */
337 assert(pattern != (char *) NULL);
338 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
cristybb503372010-05-27 20:51:26 +0000339 assert(number_coders != (size_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000340 *number_coders=0;
341 p=GetCoderInfo("*",exception);
342 if (p == (const CoderInfo *) NULL)
343 return((const CoderInfo **) NULL);
344 coder_map=(const CoderInfo **) AcquireQuantumMemory((size_t)
cristy86e5ac92014-03-16 19:27:39 +0000345 GetNumberOfNodesInSplayTree(coder_cache)+1UL,sizeof(*coder_map));
cristy3ed852e2009-09-05 21:47:34 +0000346 if (coder_map == (const CoderInfo **) NULL)
347 return((const CoderInfo **) NULL);
348 /*
349 Generate coder list.
350 */
cristyf84a1932010-01-03 18:00:18 +0000351 LockSemaphoreInfo(coder_semaphore);
cristy86e5ac92014-03-16 19:27:39 +0000352 ResetSplayTreeIterator(coder_cache);
353 p=(const CoderInfo *) GetNextValueInSplayTree(coder_cache);
cristy3ed852e2009-09-05 21:47:34 +0000354 for (i=0; p != (const CoderInfo *) NULL; )
355 {
356 if ((p->stealth == MagickFalse) &&
357 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
358 coder_map[i++]=p;
cristy86e5ac92014-03-16 19:27:39 +0000359 p=(const CoderInfo *) GetNextValueInSplayTree(coder_cache);
cristy3ed852e2009-09-05 21:47:34 +0000360 }
cristyf84a1932010-01-03 18:00:18 +0000361 UnlockSemaphoreInfo(coder_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000362 qsort((void *) coder_map,(size_t) i,sizeof(*coder_map),CoderInfoCompare);
363 coder_map[i]=(CoderInfo *) NULL;
cristybb503372010-05-27 20:51:26 +0000364 *number_coders=(size_t) i;
cristy3ed852e2009-09-05 21:47:34 +0000365 return(coder_map);
366}
367
368/*
369%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
370% %
371% %
372% %
373% G e t C o d e r L i s t %
374% %
375% %
376% %
377%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
378%
379% GetCoderList() returns any coder_map that match the specified pattern.
380%
381% The format of the GetCoderList function is:
382%
cristybb503372010-05-27 20:51:26 +0000383% char **GetCoderList(const char *pattern,size_t *number_coders,
cristy3ed852e2009-09-05 21:47:34 +0000384% ExceptionInfo *exception)
385%
386% A description of each parameter follows:
387%
388% o pattern: Specifies a pointer to a text string containing a pattern.
389%
390% o number_coders: This integer returns the number of coders in the list.
391%
392% o exception: return any errors or warnings in this structure.
393%
394*/
395
396static int CoderCompare(const void *x,const void *y)
397{
398 register const char
399 **p,
400 **q;
401
402 p=(const char **) x;
403 q=(const char **) y;
404 return(LocaleCompare(*p,*q));
405}
406
407MagickExport char **GetCoderList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000408 size_t *number_coders,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000409{
410 char
411 **coder_map;
412
413 register const CoderInfo
414 *p;
415
cristybb503372010-05-27 20:51:26 +0000416 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000417 i;
418
419 /*
420 Allocate coder list.
421 */
422 assert(pattern != (char *) NULL);
423 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
cristybb503372010-05-27 20:51:26 +0000424 assert(number_coders != (size_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000425 *number_coders=0;
426 p=GetCoderInfo("*",exception);
427 if (p == (const CoderInfo *) NULL)
428 return((char **) NULL);
429 coder_map=(char **) AcquireQuantumMemory((size_t)
cristy86e5ac92014-03-16 19:27:39 +0000430 GetNumberOfNodesInSplayTree(coder_cache)+1UL,sizeof(*coder_map));
cristy3ed852e2009-09-05 21:47:34 +0000431 if (coder_map == (char **) NULL)
432 return((char **) NULL);
433 /*
434 Generate coder list.
435 */
cristyf84a1932010-01-03 18:00:18 +0000436 LockSemaphoreInfo(coder_semaphore);
cristy86e5ac92014-03-16 19:27:39 +0000437 ResetSplayTreeIterator(coder_cache);
438 p=(const CoderInfo *) GetNextValueInSplayTree(coder_cache);
cristy3ed852e2009-09-05 21:47:34 +0000439 for (i=0; p != (const CoderInfo *) NULL; )
440 {
441 if ((p->stealth == MagickFalse) &&
442 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
443 coder_map[i++]=ConstantString(p->name);
cristy86e5ac92014-03-16 19:27:39 +0000444 p=(const CoderInfo *) GetNextValueInSplayTree(coder_cache);
cristy3ed852e2009-09-05 21:47:34 +0000445 }
cristyf84a1932010-01-03 18:00:18 +0000446 UnlockSemaphoreInfo(coder_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000447 qsort((void *) coder_map,(size_t) i,sizeof(*coder_map),CoderCompare);
448 coder_map[i]=(char *) NULL;
cristybb503372010-05-27 20:51:26 +0000449 *number_coders=(size_t) i;
cristy3ed852e2009-09-05 21:47:34 +0000450 return(coder_map);
451}
452
453/*
454%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
455% %
456% %
457% %
cristy904e5912014-03-15 19:53:14 +0000458+ 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 +0000459% %
460% %
461% %
462%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
463%
cristycd2cd182014-03-18 12:10:55 +0000464% IsCoderTreeInstantiated() determines if the coder tree is instantiated. If
465% not, it instantiates the tree and returns it.
cristy3ed852e2009-09-05 21:47:34 +0000466%
cristy904e5912014-03-15 19:53:14 +0000467% The format of the IsCoderInstantiated method is:
cristy3ed852e2009-09-05 21:47:34 +0000468%
cristy904e5912014-03-15 19:53:14 +0000469% MagickBooleanType IsCoderTreeInstantiated(ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000470%
471% A description of each parameter follows.
472%
473% o exception: return any errors or warnings in this structure.
474%
475*/
cristy904e5912014-03-15 19:53:14 +0000476static MagickBooleanType IsCoderTreeInstantiated(ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000477{
cristy86e5ac92014-03-16 19:27:39 +0000478 if (coder_cache == (SplayTreeInfo *) NULL)
479 {
480 if (coder_semaphore == (SemaphoreInfo *) NULL)
481 ActivateSemaphoreInfo(&coder_semaphore);
482 LockSemaphoreInfo(coder_semaphore);
483 if (coder_cache == (SplayTreeInfo *) NULL)
Dirk Lemstrae2939a42018-10-04 23:20:08 +0200484 coder_cache=AcquireCoderCache(exception);
cristy86e5ac92014-03-16 19:27:39 +0000485 UnlockSemaphoreInfo(coder_semaphore);
486 }
487 return(coder_cache != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +0000488}
489
490/*
491%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
492% %
493% %
494% %
495% L i s t C o d e r I n f o %
496% %
497% %
498% %
499%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
500%
501% ListCoderInfo() lists the coder info to a file.
502%
503% The format of the ListCoderInfo coder is:
504%
505% MagickBooleanType ListCoderInfo(FILE *file,ExceptionInfo *exception)
506%
507% A description of each parameter follows.
508%
509% o file: An pointer to a FILE.
510%
511% o exception: return any errors or warnings in this structure.
512%
513*/
514MagickExport MagickBooleanType ListCoderInfo(FILE *file,
515 ExceptionInfo *exception)
516{
517 const char
518 *path;
519
520 const CoderInfo
521 **coder_info;
522
cristybb503372010-05-27 20:51:26 +0000523 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000524 i;
525
cristybb503372010-05-27 20:51:26 +0000526 size_t
cristy3ed852e2009-09-05 21:47:34 +0000527 number_coders;
528
cristy9d314ff2011-03-09 01:30:28 +0000529 ssize_t
530 j;
531
cristy3ed852e2009-09-05 21:47:34 +0000532 if (file == (const FILE *) NULL)
533 file=stdout;
534 coder_info=GetCoderInfoList("*",&number_coders,exception);
535 if (coder_info == (const CoderInfo **) NULL)
536 return(MagickFalse);
537 path=(const char *) NULL;
cristybb503372010-05-27 20:51:26 +0000538 for (i=0; i < (ssize_t) number_coders; i++)
cristy3ed852e2009-09-05 21:47:34 +0000539 {
540 if (coder_info[i]->stealth != MagickFalse)
541 continue;
542 if ((path == (const char *) NULL) ||
543 (LocaleCompare(path,coder_info[i]->path) != 0))
544 {
545 if (coder_info[i]->path != (char *) NULL)
cristyb51dff52011-05-19 16:55:47 +0000546 (void) FormatLocaleFile(file,"\nPath: %s\n\n",coder_info[i]->path);
Dirk Lemstrac1e154d2018-10-30 18:30:25 +0100547 (void) FormatLocaleFile(file,"Magick Coder\n");
cristy1e604812011-05-19 18:07:50 +0000548 (void) FormatLocaleFile(file,
549 "-------------------------------------------------"
cristy3ed852e2009-09-05 21:47:34 +0000550 "------------------------------\n");
551 }
552 path=coder_info[i]->path;
cristyb51dff52011-05-19 16:55:47 +0000553 (void) FormatLocaleFile(file,"%s",coder_info[i]->magick);
Dirk Lemstrac1e154d2018-10-30 18:30:25 +0100554 for (j=(ssize_t) strlen(coder_info[i]->magick); j <= 15; j++)
cristyb51dff52011-05-19 16:55:47 +0000555 (void) FormatLocaleFile(file," ");
cristy3ed852e2009-09-05 21:47:34 +0000556 if (coder_info[i]->name != (char *) NULL)
cristyb51dff52011-05-19 16:55:47 +0000557 (void) FormatLocaleFile(file,"%s",coder_info[i]->name);
558 (void) FormatLocaleFile(file,"\n");
cristy3ed852e2009-09-05 21:47:34 +0000559 }
560 coder_info=(const CoderInfo **) RelinquishMagickMemory((void *) coder_info);
561 (void) fflush(file);
562 return(MagickTrue);
563}