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-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 "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/log.h"
52 #include "MagickCore/memory_.h"
53 #include "MagickCore/memory-private.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 "coders/coders.h"
62 
63 /*
64   Define declarations.
65 */
66 #define AddMagickCoder(coder) Magick ## coder ## Aliases
67 
68 /*
69   Typedef declarations.
70 */
71 typedef struct _CoderMapInfo
72 {
73   const char
74     *magick,
75     *name;
76 } CoderMapInfo;
77 
78 /*
79   Static declarations.
80 */
81 static const CoderMapInfo
82   CoderMap[] =
83   {
84     #include "coders/coders-list.h"
85   };
86 
87 static SemaphoreInfo
88   *coder_semaphore = (SemaphoreInfo *) NULL;
89 
90 static SplayTreeInfo
91   *coder_cache = (SplayTreeInfo *) NULL;
92 
93 /*
94   Forward declarations.
95 */
96 static MagickBooleanType
97   IsCoderTreeInstantiated(ExceptionInfo *);
98 
99 /*
100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
101 %                                                                             %
102 %                                                                             %
103 %                                                                             %
104 +  A c q u i r e C o d e r C a c h e                                          %
105 %                                                                             %
106 %                                                                             %
107 %                                                                             %
108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
109 %
110 %  AcquireCoderCache() caches one or more coder configurations which provides a
111 %  mapping between coder attributes and a coder name.
112 %
113 %  The format of the AcquireCoderCache coder is:
114 %
115 %      SplayTreeInfo *AcquireCoderCache(ExceptionInfo *exception)
116 %
117 %  A description of each parameter follows:
118 %
119 %    o exception: return any errors or warnings in this structure.
120 %
121 */
122 
DestroyCoderNode(void * coder_info)123 static void *DestroyCoderNode(void *coder_info)
124 {
125   CoderInfo
126     *p;
127 
128   p=(CoderInfo *) coder_info;
129   if (p->exempt == MagickFalse)
130     {
131       if (p->path != (char *) NULL)
132         p->path=DestroyString(p->path);
133       if (p->name != (char *) NULL)
134         p->name=DestroyString(p->name);
135       if (p->magick != (char *) NULL)
136         p->magick=DestroyString(p->magick);
137     }
138   return(RelinquishMagickMemory(p));
139 }
140 
AcquireCoderCache(ExceptionInfo * exception)141 static SplayTreeInfo *AcquireCoderCache(ExceptionInfo *exception)
142 {
143   MagickStatusType
144     status;
145 
146   ssize_t
147     i;
148 
149   SplayTreeInfo
150     *cache;
151 
152   /*
153     Load built-in coder map.
154   */
155   cache=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
156     DestroyCoderNode);
157   status=MagickTrue;
158   for (i=0; i < (ssize_t) (sizeof(CoderMap)/sizeof(*CoderMap)); i++)
159   {
160     CoderInfo
161       *coder_info;
162 
163     const CoderMapInfo
164       *p;
165 
166     p=CoderMap+i;
167     coder_info=(CoderInfo *) AcquireMagickMemory(sizeof(*coder_info));
168     if (coder_info == (CoderInfo *) NULL)
169       {
170         (void) ThrowMagickException(exception,GetMagickModule(),
171           ResourceLimitError,"MemoryAllocationFailed","`%s'",p->name);
172         continue;
173       }
174     (void) memset(coder_info,0,sizeof(*coder_info));
175     coder_info->path=(char *) "[built-in]";
176     coder_info->magick=(char *) p->magick;
177     coder_info->name=(char *) p->name;
178     coder_info->exempt=MagickTrue;
179     coder_info->signature=MagickCoreSignature;
180     status&=AddValueToSplayTree(cache,ConstantString(coder_info->magick),
181       coder_info);
182     if (status == MagickFalse)
183       (void) ThrowMagickException(exception,GetMagickModule(),
184         ResourceLimitError,"MemoryAllocationFailed","`%s'",coder_info->name);
185   }
186   return(cache);
187 }
188 
189 /*
190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
191 %                                                                             %
192 %                                                                             %
193 %                                                                             %
194 +   C o d e r C o m p o n e n t G e n e s i s                                 %
195 %                                                                             %
196 %                                                                             %
197 %                                                                             %
198 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
199 %
200 %  CoderComponentGenesis() instantiates the coder component.
201 %
202 %  The format of the CoderComponentGenesis method is:
203 %
204 %      MagickBooleanType CoderComponentGenesis(void)
205 %
206 */
CoderComponentGenesis(void)207 MagickPrivate MagickBooleanType CoderComponentGenesis(void)
208 {
209   if (coder_semaphore == (SemaphoreInfo *) NULL)
210     coder_semaphore=AcquireSemaphoreInfo();
211   return(MagickTrue);
212 }
213 
214 /*
215 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
216 %                                                                             %
217 %                                                                             %
218 %                                                                             %
219 +   C o d e r C o m p o n e n t T e r m i n u s                               %
220 %                                                                             %
221 %                                                                             %
222 %                                                                             %
223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
224 %
225 %  CoderComponentTerminus() destroys the coder component.
226 %
227 %  The format of the CoderComponentTerminus method is:
228 %
229 %      CoderComponentTerminus(void)
230 %
231 */
CoderComponentTerminus(void)232 MagickPrivate void CoderComponentTerminus(void)
233 {
234   if (coder_semaphore == (SemaphoreInfo *) NULL)
235     ActivateSemaphoreInfo(&coder_semaphore);
236   LockSemaphoreInfo(coder_semaphore);
237   if (coder_cache != (SplayTreeInfo *) NULL)
238     coder_cache=DestroySplayTree(coder_cache);
239   UnlockSemaphoreInfo(coder_semaphore);
240   RelinquishSemaphoreInfo(&coder_semaphore);
241 }
242 
243 /*
244 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
245 %                                                                             %
246 %                                                                             %
247 %                                                                             %
248 +   G e t C o d e r I n f o                                                   %
249 %                                                                             %
250 %                                                                             %
251 %                                                                             %
252 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
253 %
254 %  GetCoderInfo searches the coder list for the specified name and if found
255 %  returns attributes for that coder.
256 %
257 %  The format of the GetCoderInfo method is:
258 %
259 %      const CoderInfo *GetCoderInfo(const char *name,ExceptionInfo *exception)
260 %
261 %  A description of each parameter follows:
262 %
263 %    o name: the coder name.
264 %
265 %    o exception: return any errors or warnings in this structure.
266 %
267 */
GetCoderInfo(const char * name,ExceptionInfo * exception)268 MagickExport const CoderInfo *GetCoderInfo(const char *name,
269   ExceptionInfo *exception)
270 {
271   assert(exception != (ExceptionInfo *) NULL);
272   if (IsCoderTreeInstantiated(exception) == MagickFalse)
273     return((const CoderInfo *) NULL);
274   if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
275     return((const CoderInfo *) GetRootValueFromSplayTree(coder_cache));
276   return((const CoderInfo *) GetValueFromSplayTree(coder_cache,name));
277 }
278 
279 /*
280 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
281 %                                                                             %
282 %                                                                             %
283 %                                                                             %
284 %   G e t C o d e r I n f o L i s t                                           %
285 %                                                                             %
286 %                                                                             %
287 %                                                                             %
288 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
289 %
290 %  GetCoderInfoList() returns any coder_map that match the specified pattern.
291 %  The format of the GetCoderInfoList function is:
292 %
293 %      const CoderInfo **GetCoderInfoList(const char *pattern,
294 %        size_t *number_coders,ExceptionInfo *exception)
295 %
296 %  A description of each parameter follows:
297 %
298 %    o pattern: Specifies a pointer to a text string containing a pattern.
299 %
300 %    o number_coders:  This integer returns the number of coders in the list.
301 %
302 %    o exception: return any errors or warnings in this structure.
303 %
304 */
305 
CoderInfoCompare(const void * x,const void * y)306 static int CoderInfoCompare(const void *x,const void *y)
307 {
308   const CoderInfo
309     **p,
310     **q;
311 
312   p=(const CoderInfo **) x,
313   q=(const CoderInfo **) y;
314   if (LocaleCompare((*p)->path,(*q)->path) == 0)
315     return(LocaleCompare((*p)->name,(*q)->name));
316   return(LocaleCompare((*p)->path,(*q)->path));
317 }
318 
GetCoderInfoList(const char * pattern,size_t * number_coders,ExceptionInfo * exception)319 MagickExport const CoderInfo **GetCoderInfoList(const char *pattern,
320   size_t *number_coders,ExceptionInfo *exception)
321 {
322   const CoderInfo
323     **coder_map;
324 
325   const CoderInfo
326     *p;
327 
328   ssize_t
329     i;
330 
331   /*
332     Allocate coder list.
333   */
334   assert(pattern != (char *) NULL);
335   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
336   assert(number_coders != (size_t *) NULL);
337   *number_coders=0;
338   p=GetCoderInfo("*",exception);
339   if (p == (const CoderInfo *) NULL)
340     return((const CoderInfo **) NULL);
341   coder_map=(const CoderInfo **) AcquireQuantumMemory((size_t)
342     GetNumberOfNodesInSplayTree(coder_cache)+1UL,sizeof(*coder_map));
343   if (coder_map == (const CoderInfo **) NULL)
344     return((const CoderInfo **) NULL);
345   /*
346     Generate coder list.
347   */
348   LockSemaphoreInfo(coder_semaphore);
349   ResetSplayTreeIterator(coder_cache);
350   p=(const CoderInfo *) GetNextValueInSplayTree(coder_cache);
351   for (i=0; p != (const CoderInfo *) NULL; )
352   {
353     if ((p->stealth == MagickFalse) &&
354         (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
355       coder_map[i++]=p;
356     p=(const CoderInfo *) GetNextValueInSplayTree(coder_cache);
357   }
358   UnlockSemaphoreInfo(coder_semaphore);
359   qsort((void *) coder_map,(size_t) i,sizeof(*coder_map),CoderInfoCompare);
360   coder_map[i]=(CoderInfo *) NULL;
361   *number_coders=(size_t) i;
362   return(coder_map);
363 }
364 
365 /*
366 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
367 %                                                                             %
368 %                                                                             %
369 %                                                                             %
370 %   G e t C o d e r L i s t                                                   %
371 %                                                                             %
372 %                                                                             %
373 %                                                                             %
374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
375 %
376 %  GetCoderList() returns any coder_map that match the specified pattern.
377 %
378 %  The format of the GetCoderList function is:
379 %
380 %      char **GetCoderList(const char *pattern,size_t *number_coders,
381 %        ExceptionInfo *exception)
382 %
383 %  A description of each parameter follows:
384 %
385 %    o pattern: Specifies a pointer to a text string containing a pattern.
386 %
387 %    o number_coders:  This integer returns the number of coders in the list.
388 %
389 %    o exception: return any errors or warnings in this structure.
390 %
391 */
392 
CoderCompare(const void * x,const void * y)393 static int CoderCompare(const void *x,const void *y)
394 {
395   const char
396     **p,
397     **q;
398 
399   p=(const char **) x;
400   q=(const char **) y;
401   return(LocaleCompare(*p,*q));
402 }
403 
GetCoderList(const char * pattern,size_t * number_coders,ExceptionInfo * exception)404 MagickExport char **GetCoderList(const char *pattern,
405   size_t *number_coders,ExceptionInfo *exception)
406 {
407   char
408     **coder_map;
409 
410   const CoderInfo
411     *p;
412 
413   ssize_t
414     i;
415 
416   /*
417     Allocate coder list.
418   */
419   assert(pattern != (char *) NULL);
420   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
421   assert(number_coders != (size_t *) NULL);
422   *number_coders=0;
423   p=GetCoderInfo("*",exception);
424   if (p == (const CoderInfo *) NULL)
425     return((char **) NULL);
426   coder_map=(char **) AcquireQuantumMemory((size_t)
427     GetNumberOfNodesInSplayTree(coder_cache)+1UL,sizeof(*coder_map));
428   if (coder_map == (char **) NULL)
429     return((char **) NULL);
430   /*
431     Generate coder list.
432   */
433   LockSemaphoreInfo(coder_semaphore);
434   ResetSplayTreeIterator(coder_cache);
435   p=(const CoderInfo *) GetNextValueInSplayTree(coder_cache);
436   for (i=0; p != (const CoderInfo *) NULL; )
437   {
438     if ((p->stealth == MagickFalse) &&
439         (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
440       coder_map[i++]=ConstantString(p->name);
441     p=(const CoderInfo *) GetNextValueInSplayTree(coder_cache);
442   }
443   UnlockSemaphoreInfo(coder_semaphore);
444   qsort((void *) coder_map,(size_t) i,sizeof(*coder_map),CoderCompare);
445   coder_map[i]=(char *) NULL;
446   *number_coders=(size_t) i;
447   return(coder_map);
448 }
449 
450 /*
451 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
452 %                                                                             %
453 %                                                                             %
454 %                                                                             %
455 +   I s C o d e r T r e e I n s t a n t i a t e d                             %
456 %                                                                             %
457 %                                                                             %
458 %                                                                             %
459 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
460 %
461 %  IsCoderTreeInstantiated() determines if the coder tree is instantiated.  If
462 %  not, it instantiates the tree and returns it.
463 %
464 %  The format of the IsCoderInstantiated method is:
465 %
466 %      MagickBooleanType IsCoderTreeInstantiated(ExceptionInfo *exception)
467 %
468 %  A description of each parameter follows.
469 %
470 %    o exception: return any errors or warnings in this structure.
471 %
472 */
IsCoderTreeInstantiated(ExceptionInfo * exception)473 static MagickBooleanType IsCoderTreeInstantiated(ExceptionInfo *exception)
474 {
475   if (coder_cache == (SplayTreeInfo *) NULL)
476     {
477       if (coder_semaphore == (SemaphoreInfo *) NULL)
478         ActivateSemaphoreInfo(&coder_semaphore);
479       LockSemaphoreInfo(coder_semaphore);
480       if (coder_cache == (SplayTreeInfo *) NULL)
481         coder_cache=AcquireCoderCache(exception);
482       UnlockSemaphoreInfo(coder_semaphore);
483     }
484   return(coder_cache != (SplayTreeInfo *) NULL ? MagickTrue : MagickFalse);
485 }
486 
487 /*
488 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
489 %                                                                             %
490 %                                                                             %
491 %                                                                             %
492 %  L i s t C o d e r I n f o                                                  %
493 %                                                                             %
494 %                                                                             %
495 %                                                                             %
496 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
497 %
498 %  ListCoderInfo() lists the coder info to a file.
499 %
500 %  The format of the ListCoderInfo coder is:
501 %
502 %      MagickBooleanType ListCoderInfo(FILE *file,ExceptionInfo *exception)
503 %
504 %  A description of each parameter follows.
505 %
506 %    o file:  An pointer to a FILE.
507 %
508 %    o exception: return any errors or warnings in this structure.
509 %
510 */
ListCoderInfo(FILE * file,ExceptionInfo * exception)511 MagickExport MagickBooleanType ListCoderInfo(FILE *file,
512   ExceptionInfo *exception)
513 {
514   const char
515     *path;
516 
517   const CoderInfo
518     **coder_info;
519 
520   ssize_t
521     i;
522 
523   size_t
524     number_coders;
525 
526   ssize_t
527     j;
528 
529   if (file == (const FILE *) NULL)
530     file=stdout;
531   coder_info=GetCoderInfoList("*",&number_coders,exception);
532   if (coder_info == (const CoderInfo **) NULL)
533     return(MagickFalse);
534   path=(const char *) NULL;
535   for (i=0; i < (ssize_t) number_coders; i++)
536   {
537     if (coder_info[i]->stealth != MagickFalse)
538       continue;
539     if ((path == (const char *) NULL) ||
540         (LocaleCompare(path,coder_info[i]->path) != 0))
541       {
542         if (coder_info[i]->path != (char *) NULL)
543           (void) FormatLocaleFile(file,"\nPath: %s\n\n",coder_info[i]->path);
544         (void) FormatLocaleFile(file,"Magick          Coder\n");
545         (void) FormatLocaleFile(file,
546           "-------------------------------------------------"
547           "------------------------------\n");
548       }
549     path=coder_info[i]->path;
550     (void) FormatLocaleFile(file,"%s",coder_info[i]->magick);
551     for (j=(ssize_t) strlen(coder_info[i]->magick); j <= 15; j++)
552       (void) FormatLocaleFile(file," ");
553     if (coder_info[i]->name != (char *) NULL)
554       (void) FormatLocaleFile(file,"%s",coder_info[i]->name);
555     (void) FormatLocaleFile(file,"\n");
556   }
557   coder_info=(const CoderInfo **) RelinquishMagickMemory((void *) coder_info);
558   (void) fflush(file);
559   return(MagickTrue);
560 }
561