Coverage Report

Created: 2026-09-06 07:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/graphicsmagick/magick/magick.c
Line
Count
Source
1
/*
2
% Copyright (C) 2003-2026 GraphicsMagick Group
3
% Copyright (C) 2002 ImageMagick Studio
4
% Copyright 1991-1999 E. I. du Pont de Nemours and Company
5
%
6
% This program is covered by multiple licenses, which are described in
7
% Copyright.txt. You should have received a copy of Copyright.txt with this
8
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
9
%
10
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11
%                                                                             %
12
%                                                                             %
13
%                                                                             %
14
%                  M   M   AAA    GGGG  IIIII   CCCC  K   K                   %
15
%                  MM MM  A   A  G        I    C      K  K                    %
16
%                  M M M  AAAAA  G GGG    I    C      KKK                     %
17
%                  M   M  A   A  G   G    I    C      K  K                    %
18
%                  M   M  A   A   GGGG  IIIII   CCCC  K   K                   %
19
%                                                                             %
20
%                                                                             %
21
%            Methods to Read or List GraphicsMagick Image formats             %
22
%                                                                             %
23
%                                                                             %
24
%                            Software Design                                  %
25
%                            Bob Friesenhahn                                  %
26
%                              John Cristy                                    %
27
%                             November 1998                                   %
28
%                                                                             %
29
%                                                                             %
30
%                                                                             %
31
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
32
%
33
%
34
*/
35

36
/*
37
  Include declarations.
38
*/
39
#include "magick/studio.h"
40
#if defined(USE_GLIBC_MTRACE) && USE_GLIBC_MTRACE
41
#  include <mcheck.h>
42
#endif /* if defined(USE_GLIBC_MTRACE) && USE_GLIBC_MTRACE */
43
#if defined(MSWINDOWS) || defined(__CYGWIN__)
44
# include "magick/nt_feature.h"
45
#endif
46
#include "magick/blob.h"
47
#include "magick/color_lookup.h"
48
#include "magick/command.h"
49
#include "magick/constitute.h"
50
#include "magick/delegate.h"
51
#include "magick/log.h"
52
#include "magick/magic.h"
53
#include "magick/magick.h"
54
#include "magick/module.h"
55
#include "magick/monitor.h"
56
#include "magick/pixel_cache.h"
57
#include "magick/random.h"
58
#include "magick/registry.h"
59
#include "magick/resource.h"
60
#include "magick/render.h"
61
#include "magick/semaphore.h"
62
#include "magick/tempfile.h"
63
#include "magick/utility.h"
64
#include "magick/version.h"
65
#if defined(HasX11)
66
#include "magick/xwindow.h"
67
#endif
68
/* watch out here - this include code for simple spinlock semaphore */
69
#include "magick/spinlock.h"
70

71
/*
72
  Global declarations.
73
*/
74
typedef enum  {
75
  InitDefault,
76
  InitUninitialized,
77
  InitInitialized
78
} MagickInitializationState;
79
80
static void
81
  DestroyMagickInfoList(void);
82
83
static SemaphoreInfo
84
  *magick_semaphore = (SemaphoreInfo *) NULL;
85
86
static SemaphoreInfo
87
  *module_semaphore = (SemaphoreInfo *) NULL;
88
89
static MagickInfo
90
  *magick_list = (MagickInfo *) NULL;
91
92
static unsigned int initialize_magick_options = 0;
93
94
static unsigned int panic_signal_handler_call_count = 0;
95
static unsigned int quit_signal_handler_call_count = 0;
96
97
static MagickInitializationState MagickInitialized = InitDefault;
98
static CoderClass MinimumCoderClass = UnstableCoderClass;
99
100
static void DestroyMagickInfo(MagickInfo** magick_info);
101
static void DestroyMagickInfoList(void);
102
103
static MagickPassFail InitializeMagickInfoList(void);
104
105
/*
106
  Block size to use when accessing filesystem.
107
108
  Adjust via MAGICK_IOBUF_SIZE environment variable.
109
*/
110
111
static size_t filesystem_blocksize=16384;
112
113
/*
114
  Get blocksize to use when accessing the filesystem.
115
*/
116
size_t
117
MagickGetFileSystemBlockSize(void)
118
15.9M
{
119
15.9M
  return filesystem_blocksize;
120
15.9M
}
121
122
/*
123
  Set blocksize to use when accessing the filesystem.
124
*/
125
void
126
MagickSetFileSystemBlockSize(const size_t block_size)
127
252
{
128
252
  assert(block_size > 0);
129
252
  filesystem_blocksize=block_size;
130
252
}
131
132

133
/*
134
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
135
%                                                                             %
136
%                                                                             %
137
%                                                                             %
138
%   D e s t r o y M a g i c k                                                 %
139
%                                                                             %
140
%                                                                             %
141
%                                                                             %
142
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
143
%
144
%  DestroyMagick() destroys the GraphicsMagick environment, releasing all
145
%  allocated semaphores, memory, and temporary files.  This function
146
%  should be invoked in the primary (original) thread of the application's
147
%  process while shutting down, and only after any threads which might be
148
%  using GraphicsMagick functions have terminated.  Since GraphicsMagick
149
%  may use threads internally via OpenMP, it is also necessary for any
150
%  function calls into GraphicsMagick to have already returned so that
151
%  OpenMP worker threads are quiesced and won't be accessing any semaphores
152
%  or data structures which are destroyed by this function.
153
%
154
%  The OpenMP implementation (if present) starts/stops any OpenMP worker
155
%  threads and allocates/frees OpenMP resources using its own algorithms.
156
%  This means that OpenMP worker threads and OpenMP resources are likely
157
%  to remain allocated after DestroyMagick() returns.  Since OpenMP 5.0,
158
%  invoking omp_pause_resource_all(omp_pause_hard) will assure that any
159
%  resources allocated by OpenMP (threads, thread-specific memory, etc.)
160
%  are freed, and this may be called after DestroyMagick() has returned.
161
%
162
%  The format of the DestroyMagick function is:
163
%
164
%      DestroyMagick(void)
165
%
166
%
167
*/
168
MagickExport void
169
DestroyMagick(void)
170
0
{
171
  /* Acquire destruction lock */
172
0
  SPINLOCK_WAIT;
173
174
0
  if (MagickInitialized == InitUninitialized)
175
0
    {
176
      /* Release destruction lock */
177
0
      SPINLOCK_RELEASE;
178
0
      return;
179
0
    }
180
181
0
  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
182
0
                        "Destroy Magick");
183
184
0
  MagickDestroyCommandInfo();   /* Command parser */
185
0
  DestroyMagickMonitor();       /* Progress monitor */
186
#if defined(HasX11)
187
  MagickXDestroyX11Resources();
188
#endif
189
0
  DestroyColorInfo();           /* Color database */
190
0
  DestroyDelegateInfo();        /* External delegate information */
191
0
  DestroyTypeInfo();            /* Font information */
192
  /*DestroyMagicInfo();*/       /* File format detection */
193
0
  DestroyMagickInfoList();      /* Coder registrations + modules */
194
0
  DestroyConstitute();          /* Constitute semaphore */
195
0
  DestroyMagickRegistry();      /* Registered images */
196
0
  DestroyMagickResources();     /* Resource semaphore */
197
0
  DestroyMagickRandomGenerator(); /* Random number generator */
198
0
  DestroyTemporaryFiles();      /* Temporary files */
199
#if defined(MSWINDOWS)
200
#if defined(HasGS)
201
  NTGhostscriptUnLoadDLL();     /* Ghostscript DLL */
202
#endif /* if defined(HasGS) */
203
#endif /* defined(MSWINDOWS) */
204
  /*
205
    Destroy logging last since some components log their destruction.
206
  */
207
0
  DestroyLogInfo();             /* Logging configuration */
208
0
  DestroyMagickExceptionHandling(); /* Exception handling */
209
0
  DestroySemaphore();           /* Semaphores framework */
210
211
  /* Now uninitialized */
212
0
  MagickInitialized=InitUninitialized;
213
214
  /* Release destruction lock */
215
0
  SPINLOCK_RELEASE;
216
0
}
217
/*
218
  Destroy MagickInfo structure.
219
*/
220

221
/*
222
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
223
%                                                                             %
224
%                                                                             %
225
%                                                                             %
226
%   D e s t r o y M a g i c k I n f o                                         %
227
%                                                                             %
228
%                                                                             %
229
%                                                                             %
230
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
231
%
232
%  DestroyMagickInfo() destroys a MagickInfo structure.
233
%
234
%  The format of the DestroyMagickInfoList method is:
235
%
236
%      void DestroyMagickInfo(MagickInfo** magick_info)
237
%
238
*/
239
static void
240
DestroyMagickInfo(MagickInfo** magick_info)
241
0
{
242
0
  MagickInfo
243
0
    *p;
244
245
0
  p=*magick_info;
246
0
  if (p)
247
0
    {
248
0
      p->name=0;
249
0
      p->description=0;
250
0
      p->version=0;
251
0
      p->note=0;
252
0
      p->module=0;
253
0
      MagickFreeMemory(p);
254
0
      *magick_info=p;
255
0
    }
256
0
}
257

258
/*
259
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
260
%                                                                             %
261
%                                                                             %
262
%                                                                             %
263
%   D e s t r o y M a g i c k I n f o L i s t                                 %
264
%                                                                             %
265
%                                                                             %
266
%                                                                             %
267
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
268
%
269
%  DestroyMagickInfo() deallocates memory associated with the MagickInfo list.
270
%
271
%  The format of the DestroyMagickInfoList method is:
272
%
273
%      void DestroyMagickInfoList(void)
274
%
275
*/
276
static void
277
DestroyMagickInfoList(void)
278
0
{
279
0
  MagickInfo
280
0
    *magick_info;
281
282
0
  register MagickInfo
283
0
    *p;
284
285
0
  DestroyMagickModules();
286
287
  /*
288
    At this point, the list should be empty, but check for remaining
289
    entries anyway.
290
  */
291
0
  if (magick_list != (MagickInfo *) NULL)
292
0
    (void) printf("Warning: module registrations are still present!\n");
293
0
  for (p=magick_list; p != (MagickInfo *) NULL; )
294
0
  {
295
0
    magick_info=p;
296
0
    p=p->next;
297
298
0
#if !defined(BuildMagickModules)
299
0
    (void) printf("Warning: module registration for \"%s\" from module \"%s\" still present!\n",
300
0
                  magick_info->name, magick_info->module);
301
0
#endif /* !defined(BuildMagickModules) */
302
0
    DestroyMagickInfo(&magick_info);
303
0
  }
304
0
  magick_list=(MagickInfo *) NULL;
305
0
  DestroySemaphoreInfo(&magick_semaphore);
306
307
0
  DestroySemaphoreInfo(&module_semaphore);
308
0
}
309

310
/*
311
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
312
%                                                                             %
313
%                                                                             %
314
%                                                                             %
315
%   G e t I m a g e M a g i c k                                               %
316
%                                                                             %
317
%                                                                             %
318
%                                                                             %
319
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
320
%
321
%  GetImageMagick() searches for an image format that matches the specified
322
%  magick string.  If one is found the name is returned otherwise NULL.
323
%
324
%  The format of the GetImageMagick method is:
325
%
326
%      const char *GetImageMagick(const unsigned char *magick,
327
%        const size_t length)
328
%
329
%  A description of each parameter follows:
330
%
331
%    o magick: The image format we are searching for.
332
%
333
%    o length: The length of the binary string.
334
%
335
%
336
*/
337
MagickExport const char *
338
GetImageMagick(const unsigned char *magick,const size_t length)
339
0
{
340
0
  register MagickInfo
341
0
    *p;
342
343
0
  assert(magick != (const unsigned char *) NULL);
344
0
  LockSemaphoreInfo(magick_semaphore);
345
0
  for (p=magick_list; p != (MagickInfo *) NULL; p=p->next)
346
0
    if (p->magick && p->magick(magick,length))
347
0
      break;
348
0
  UnlockSemaphoreInfo(magick_semaphore);
349
0
  if (p != (MagickInfo *) NULL)
350
0
    return(p->name);
351
0
  return((char *) NULL);
352
0
}
353

354
/*
355
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
356
%                                                                             %
357
%                                                                             %
358
%                                                                             %
359
%   G e t M a g i c k I n f o                                                 %
360
%                                                                             %
361
%                                                                             %
362
%                                                                             %
363
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
364
%
365
%  GetMagickInfo() returns a pointer MagickInfo structure that matches
366
%  the specified name.  If name is NULL, the head of the image format list
367
%  is returned. It is not safe to traverse the list by using the previous and
368
%  next pointers in the MagickInfo structure since the list contents or order
369
%  may be altered while the list is being traversed. If the list must be
370
%  traversed, access it via the GetMagickInfoArray function instead.
371
%
372
%  If GraphicsMagick has not been initialized via InitializeMagick()
373
%  then this function will not work.
374
%
375
%  The format of the GetMagickInfo method is:
376
%
377
%     const MagickInfo *GetMagickInfo(const char *name,ExceptionInfo *exception)
378
%
379
%  A description of each parameter follows:
380
%
381
%    o name: The image format we are looking for.
382
%
383
%    o exception: Return any errors or warnings in this structure.
384
%
385
%
386
*/
387
static MagickInfo *
388
GetMagickInfoEntryLocked(const char *name)
389
18.2M
{
390
18.2M
  register MagickInfo
391
18.2M
    *p;
392
393
18.2M
  LockSemaphoreInfo(magick_semaphore);
394
395
18.2M
  p=magick_list;
396
397
18.2M
  if ((name != (const char *) NULL) && (name[0] != '*'))
398
18.2M
    {
399
33.0M
      for (p=magick_list; p != (MagickInfo *) NULL; p=p->next)
400
33.0M
        if (LocaleCompare(p->name,name) == 0)
401
18.2M
          break;
402
403
18.2M
      if (p != (MagickInfo *) NULL)
404
18.2M
        if (p != magick_list)
405
2.94M
          {
406
            /*
407
              Self-adjusting list.
408
            */
409
2.94M
            if (p->previous != (MagickInfo *) NULL)
410
2.94M
              p->previous->next=p->next;
411
2.94M
            if (p->next != (MagickInfo *) NULL)
412
2.94M
              p->next->previous=p->previous;
413
2.94M
            p->previous=(MagickInfo *) NULL;
414
2.94M
            p->next=magick_list;
415
2.94M
            magick_list->previous=p;
416
2.94M
            magick_list=p;
417
2.94M
          }
418
18.2M
    }
419
420
18.2M
  UnlockSemaphoreInfo(magick_semaphore);
421
422
18.2M
  return p;
423
18.2M
}
424
MagickExport const MagickInfo *
425
GetMagickInfo(const char *name,ExceptionInfo *exception)
426
18.2M
{
427
18.2M
  const MagickInfo
428
18.2M
    *magick_info=(const MagickInfo *) NULL;
429
430
18.2M
  if ((name != (const char *) NULL) &&
431
18.2M
      (name[0] != '\0'))
432
18.2M
    {
433
18.2M
      LockSemaphoreInfo(module_semaphore);
434
18.2M
      if (name[0] == '*')
435
0
        {
436
          /*
437
            If all modules are requested, then use OpenModules to load all
438
            modules.
439
          */
440
0
          (void) OpenModules(exception);
441
0
        }
442
18.2M
      else
443
18.2M
        {
444
18.2M
          magick_info=GetMagickInfoEntryLocked(name);
445
18.2M
          if (magick_info == (const MagickInfo *) NULL)
446
27.2k
            {
447
              /*
448
                Try to load a supporting module.
449
              */
450
27.2k
              (void) OpenModule(name,exception);
451
27.2k
            }
452
18.2M
        }
453
18.2M
      UnlockSemaphoreInfo(module_semaphore);
454
18.2M
    }
455
456
  /*
457
    Return whatever we've got
458
  */
459
18.2M
  if (magick_info == (const MagickInfo *) NULL)
460
27.2k
    magick_info=GetMagickInfoEntryLocked(name);
461
462
18.2M
  return magick_info;
463
18.2M
}
464
/*
465
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
466
%                                                                             %
467
%                                                                             %
468
%                                                                             %
469
%   G e t M a g i c k I n f o A r r a y                                       %
470
%                                                                             %
471
%                                                                             %
472
%                                                                             %
473
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
474
%
475
%  GetMagickInfoArray() returns a sorted null-terminated array of MagickInfo
476
%  pointers corresponding to the available format registrations. If necessarly
477
%  all modules are loaded in order to return a complete list. This function
478
%  should be used to access the entire list rather than GetMagickInfo since
479
%  the list returned by GetMagickInfo may be re-ordered every time it is
480
%  invoked. Once the returned array is no longer needed, the allocated array
481
%  should be deallocated. Do not attempt to deallocate the MagickInfo
482
%  structures based on pointers in the array!
483
%
484
%  The format of the GetMagickList method is:
485
%
486
%      MagickInfo **GetMagickInfoArray(ExceptionInfo *exception)
487
%
488
%  A description of each parameter follows:
489
%
490
%    o exception: Return any errors or warnings in this structure.
491
%
492
%
493
*/
494
/*
495
  Compare two MagickInfo structures based on their name
496
*/
497
static int
498
MagickInfoCompare(const void *x, const void *y)
499
0
{
500
0
  const MagickInfo
501
0
    *xx=*((const MagickInfo **) x),
502
0
    *yy=*((const MagickInfo **) y);
503
504
0
  return (strcmp(xx->name, yy->name));
505
0
}
506
MagickExport MagickInfo **
507
GetMagickInfoArray(ExceptionInfo *exception)
508
0
{
509
0
  MagickInfo
510
0
    **array;
511
512
0
  MagickInfo
513
0
    *p;
514
515
0
  MagickInfo
516
0
    *list;
517
518
0
  size_t
519
0
    entries=0;
520
521
0
  int
522
0
    i;
523
524
  /*
525
    Load all modules and obtain pointer to head of list
526
  */
527
0
  (void) GetMagickInfo("*",exception);
528
529
0
  LockSemaphoreInfo(magick_semaphore);
530
0
  if (!magick_list)
531
0
    {
532
0
      UnlockSemaphoreInfo(magick_semaphore);
533
0
      return ((MagickInfo **) NULL);
534
0
    }
535
536
0
  list=magick_list;
537
538
  /*
539
    Count number of list entries
540
  */
541
0
  for (p=list; p != 0; p=p->next)
542
0
    entries++;
543
544
  /*
545
    Allocate array memory
546
  */
547
0
  array=MagickAllocateArray(MagickInfo **,(entries+1),sizeof(MagickInfo *));
548
0
  if (!array)
549
0
    {
550
0
      UnlockSemaphoreInfo(magick_semaphore);
551
0
      ThrowException(exception,ResourceLimitError,MemoryAllocationFailed,0);
552
0
      return ((MagickInfo **) NULL);
553
0
    }
554
555
  /*
556
    Add entries to array
557
  */
558
0
  i=0;
559
0
  for (p=list; p != 0; p=p->next)
560
0
    array[i++]=p;
561
0
  array[i]=(MagickInfo *) NULL;
562
563
0
  UnlockSemaphoreInfo(magick_semaphore);
564
565
  /*
566
    Sort array entries
567
  */
568
0
  qsort((void *) array, entries, sizeof(MagickInfo *), MagickInfoCompare);
569
570
0
  return (array);
571
0
}
572

573
/*
574
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
575
%                                                                             %
576
%                                                                             %
577
%                                                                             %
578
%   I n i t i a l i z e M a g i c k                                           %
579
%                                                                             %
580
%                                                                             %
581
%                                                                             %
582
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
583
%
584
%  InitializeMagick() initializes the GraphicsMagick environment.
585
%
586
%  InitializeMagick() or InitializeMagickEx() MUST be invoked by the using
587
%  program before making use of GraphicsMagick functions or else the library
588
%  will be unusable and any usage is likely to cause a crash.
589
%
590
%  This function should be invoked in the primary (original) thread of the
591
%  application's process, and before starting any OpenMP threads, as part
592
%  of program initialization.
593
%
594
%  If alternate memory allocations are provided via MagickAllocFunctions()
595
%  then that function should be invoked before InitializeMagickEx() since
596
%  the memory allocation functions need to be consistent.
597
%
598
%  The format of the InitializeMagick function is:
599
%
600
%      InitializeMagick(const char *path)
601
%
602
%  A description of each parameter follows:
603
%
604
%    o path: The execution path of the current GraphicsMagick client (or NULL)
605
%
606
%
607
*/
608
609
/*
610
  Due to legacy compilers, POSIX.1 actually allows the signal function
611
  to return 'int' or 'void'. The compiler is not so lenient so we must
612
  ensure that the return type matches the prototype in the headers.
613
*/
614
#if !defined(RETSIGTYPE)
615
# define RETSIGTYPE void
616
#endif
617
typedef RETSIGTYPE Sigfunc(int);
618
619
#if !defined(SIG_ERR)
620
# define SIG_ERR (Sigfunc *)-1
621
#endif
622
#if !defined(SIG_DFL)
623
# define SIG_DFL (Sigfunc *)0
624
#endif
625
626
static RETSIGTYPE MagickPanicSignalHandler(int signo);
627
static RETSIGTYPE MagickSignalHandler(int signo);
628
629
/*
630
  Signal function which only sets the signal handler if it its handling
631
  is still set to SIG_DFL. This ensures that signal handlers are not
632
  registered for signals which are being ignored, or that the API
633
  user has already registered before invoking InitializeMagick.
634
635
  Due to a weakness in the POSIX APIs, the only way to see the handler
636
  which was registered before is by registering a new handler.
637
638
  If an API user registers its own signal handler, then it is responsible
639
  for invoking DestroyMagick when a signal is received.
640
*/
641
static void
642
MagickCondSignal(int signo, Sigfunc *func)
643
2.52k
{
644
2.52k
#if defined(HAVE_SIGACTION) && defined(HAVE_SIGEMPTYSET)
645
2.52k
  struct sigaction
646
2.52k
    act,
647
2.52k
    oact;
648
649
  /*
650
    Signal set-up code which prevents interrupted system calls from
651
    automatically being restarted. From W. Richard Stevens "Advanced
652
    Programming in the UNIX Environment", Chapter 10.14.
653
  */
654
2.52k
  act.sa_handler=func;
655
2.52k
  (void) sigemptyset(&act.sa_mask);
656
2.52k
  act.sa_flags=0;
657
2.52k
#  if defined(SA_INTERRUPT)  /* SunOS */
658
2.52k
  act.sa_flags |= SA_INTERRUPT;
659
2.52k
#  endif /* if defined(SA_INTERRUPT) */
660
2.52k
#  if defined(SA_ONSTACK)  /* Use alternate signal stack if available */
661
2.52k
  act.sa_flags |= SA_ONSTACK;
662
2.52k
#  endif /* if defined(SA_ONSTACK) */
663
664
2.52k
  (void) memset(&oact, 0, sizeof(oact));
665
2.52k
  if (sigaction(signo, &act, &oact) == 0)
666
2.52k
    {
667
2.52k
      if ((oact.sa_flags & SA_SIGINFO) ||
668
1.76k
          (oact.sa_handler != SIG_DFL))
669
756
        {
670
          /* Restore prior handler! */
671
756
          if (sigaction(signo, &oact, &act) != 0)
672
0
            (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
673
0
                                  "Failed to restore prior signal handler for signal ID %d!",signo);
674
756
          else
675
756
            (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
676
756
                                  "Restored prior signal handler for signal ID %d!",signo);
677
756
        }
678
1.76k
      else
679
1.76k
        {
680
1.76k
          (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
681
1.76k
                                "Registered signal handler for signal ID %d",signo);
682
1.76k
        }
683
2.52k
    }
684
0
  else
685
0
    {
686
0
      (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
687
0
                            "Failed to register signal handler for signal ID %d!",signo);
688
0
    }
689
690
#else
691
  Sigfunc *
692
    o_handler;
693
694
  if ((o_handler=signal(signo, func)) != SIG_ERR)
695
    {
696
      if (o_handler != SIG_DFL)
697
        {
698
          /* Restore prior handler! */
699
          if (signal(signo, o_handler) ==  SIG_ERR)
700
            (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
701
                                  "Failed to restore prior signal handler for signal ID %d!",signo);
702
          else
703
            (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
704
                                  "Restored prior signal handler for signal ID %d!",signo);
705
        }
706
      else
707
        {
708
          (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
709
                                "Registered signal handler for signal ID %d",signo);
710
        }
711
    }
712
  else
713
    {
714
      (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
715
                            "Failed to register signal handler for signal ID %d!",signo);
716
    }
717
#endif
718
2.52k
}
719
720
/*
721
  Signal handler which does nothing.
722
*/
723
#if 0
724
static RETSIGTYPE
725
MagickIgnoreSignalHandler(int signo)
726
{
727
  fprintf(stderr,"Caught ignored signal %d\n", signo);
728
}
729
#endif
730
731
/*
732
  Write a message about the signal to stderr.
733
*/
734
static void
735
MagickSignalHandlerMessage(const int signo, const char *subtext)
736
0
{
737
  /*
738
    Signals we might handle, to map to their common description.
739
740
    May use strsignal() on POSIX.1-2008-compliant systems, but it is
741
    not documented to be async-safe.
742
743
  */
744
0
  static const struct {
745
0
    const int signo;
746
0
    const char name[8];
747
0
    const char *descr;
748
0
  } signal_descr[] = {
749
0
#if defined(SIGHUP)
750
0
    { SIGHUP, "SIGHUP","Hangup" },
751
0
#endif
752
0
#if defined(SIGINT)
753
0
    { SIGINT, "SIGINT", "Interrupt" },
754
0
#endif
755
0
#if defined(SIGQUIT)
756
0
    { SIGQUIT, "SIGQUIT", "Quit" },
757
0
#endif
758
0
#if defined(SIGILL)
759
0
    { SIGILL, "SIGILL", "Illegal Instruction" },
760
0
#endif
761
0
#if defined(SIGABRT)
762
0
    { SIGABRT, "SIGABRT", "Abort" },
763
0
#endif
764
0
#if defined(SIGFPE)
765
0
    { SIGFPE, "SIGFPE", "Arithmetic Exception" },
766
0
#endif
767
0
#if defined(SIGBUS)
768
0
    { SIGBUS, "SIGBUS", "Bus Error" },
769
0
#endif
770
0
#if defined(SIGSEGV)
771
0
    { SIGSEGV, "SIGSEGV", "Segmentation Fault" },
772
0
#endif
773
0
#if defined(SIGPIPE)
774
0
    { SIGPIPE, "SIGPIPE", "Broken Pipe" },
775
0
#endif
776
0
#if defined(SIGALRM)
777
0
    { SIGALRM, "SIGALRM", "Alarm Clock" },
778
0
#endif
779
0
#if defined(SIGTERM)
780
0
    { SIGTERM, "SIGTERM", "Terminated" },
781
0
#endif
782
0
#if defined(SIGCHLD)
783
0
    { SIGCHLD, "SIGCHLD", "Child Status Changed" },
784
0
#endif
785
0
#if defined(SIGXCPU)
786
0
    { SIGXCPU, "SIGXCPU", "CPU time limit exceeded" },
787
0
#endif
788
0
#if defined(SIGXFSZ)
789
0
    { SIGXFSZ, "SIGXFSZ", "File size limit exceeded" }
790
0
#endif
791
0
  };
792
793
0
  static char
794
0
    message[128];
795
796
0
  size_t
797
0
    i;
798
799
0
  int
800
0
    num=signo;
801
802
  /*
803
    Output messages like:
804
805
    gm convert: quitting due to signal 2 (SIGINT) "Interrupt"...
806
    gm convert: abort due to signal 11 (SIGSEGV) "Segmentation Fault"...
807
  */
808
0
  (void) strlcpy(message, GetClientName(), sizeof(message));
809
0
  (void) strlcat(message,": ", sizeof(message));
810
0
  (void) strlcat(message,subtext,sizeof(message));
811
0
  (void) strlcat(message," due to signal ",sizeof(message));
812
0
  i=strlen(message);
813
0
  for ( ; (num != 0) && (i < sizeof(message)-1) ; i++)
814
0
    {
815
0
      int rem = num % 10;
816
0
      message[i] = rem + '0';
817
0
      num = num/10;
818
0
    }
819
0
  message[i] = '\0';
820
0
  for ( i=0; i < (sizeof(signal_descr)/sizeof(signal_descr[0])); i++)
821
0
    {
822
0
      if (signo == signal_descr[i].signo)
823
0
        {
824
0
          (void) strlcat(message," (",sizeof(message));
825
0
          (void) strlcat(message,signal_descr[i].name,sizeof(message));
826
0
          (void) strlcat(message,") \"",sizeof(message));
827
0
          (void) strlcat(message,signal_descr[i].descr,sizeof(message));
828
0
          (void) strlcat(message,"\"",sizeof(message));
829
0
        }
830
0
    }
831
0
  (void) strlcat(message,"...\n",sizeof(message));
832
833
0
  if (write(STDERR_FILENO,message,
834
0
            (MAGICK_POSIX_IO_SIZE_T) strlen(message)) == -1)
835
0
    {
836
      /* Exists to quench warning */
837
0
    }
838
0
}
839
840
841
/*
842
  Signal handler to ensure that DestroyMagick is invoked in case the
843
  user aborts the program.
844
845
  The WIN32 documentation says that SIGINT is not supported under any
846
  version of Windows. It also says that a new thread is created to
847
  handle the interrupt caused by CNTRL+C. The Windows signal
848
  documentation also says that it is unsafe to do anything useful from
849
  within a signal handler.  This means that malloc/free and any system
850
  call should not be executed. Theoretically DestroyMagick() should
851
  not be executed since its purpose is to invoke unsafe functions.
852
  SIGILL, SIGSEGV, and SIGTERM are documented to never be generated by
853
  Windows NT.
854
855
  While support for signal is definitely broken under Windows, the good
856
  news is that it seems to be unlikely to generate a signal we care about.
857
*/
858
859
static RETSIGTYPE
860
MagickPanicSignalHandler(int signo)
861
0
{
862
0
  ARG_NOT_USED(signo);
863
864
0
  panic_signal_handler_call_count++;
865
866
  /*
867
    Only handle signal one time.
868
  */
869
0
  if (1 == panic_signal_handler_call_count)
870
0
    {
871
      /*
872
        Release persistent resources
873
      */
874
0
      PanicDestroyMagick();
875
876
      /*
877
        Produce a useful message for the user
878
      */
879
0
      MagickSignalHandlerMessage(signo,"abort");
880
881
      /*
882
        Call abort so that we quit with core dump.
883
      */
884
0
      abort();
885
0
    }
886
0
}
887
888
static MagickBool QuitProgressMonitor(const char *task,
889
                                      const magick_int64_t quantum,
890
                                      const magick_uint64_t span,
891
                                      ExceptionInfo *exception)
892
0
{
893
0
  ARG_NOT_USED(task);
894
0
  ARG_NOT_USED(quantum);
895
0
  ARG_NOT_USED(span);
896
897
  /* Report an error message */
898
0
  if (exception->severity < FatalErrorException)
899
0
    ThrowException(exception,MonitorFatalError,UserRequestedTerminationBySignal,0);
900
901
0
  return MagickFail;
902
0
}
903
904
static RETSIGTYPE
905
MagickSignalHandler(int signo)
906
0
{
907
  /* fprintf(stderr,"Caught signal %d\n", signo); */
908
909
0
  quit_signal_handler_call_count++;
910
911
  /*
912
    Only handle signal one time.
913
  */
914
0
  if (1 == quit_signal_handler_call_count)
915
0
    {
916
0
      if (MagickInitialized == InitInitialized)
917
0
        {
918
919
          /*
920
            Set progress monitor handler to one which always returns
921
            MagickFail.
922
          */
923
0
          (void) SetMonitorHandler(QuitProgressMonitor);
924
925
          /*
926
            Release persistent resources
927
          */
928
0
          PanicDestroyMagick();
929
930
          /*
931
            Produce a useful message for the user
932
          */
933
0
          if (signo != SIGINT)
934
0
            MagickSignalHandlerMessage(signo,"quitting");
935
0
        }
936
937
      /*
938
        Invoke _exit(signo) (or equivalent) which avoids invoking
939
        registered atexit() functions.
940
      */
941
0
      SignalHandlerExit(signo);
942
0
    }
943
0
}
944
945
/*
946
   The goal of this routine is to determine whether the passed
947
   string is a valid and complete path to a file within the
948
   filesystem
949
 */
950
#if !defined(UseInstalledMagick)
951
static unsigned int
952
IsValidFilesystemPath(const char *path)
953
252
{
954
252
  if ((path != (const char *) NULL) && (*path != '\0'))
955
252
    {
956
252
#if defined(POSIX)
957
      /* For POSIX we check the first character to see of it is a file
958
          system path separator. If not then we ignore the passed data
959
      */
960
252
      if ((*path == *DirectorySeparator))
961
252
        return IsAccessibleNoLogging(path);
962
#elif defined(MSWINDOWS)
963
      /* For Windows we check to see if the path passed seems to be a
964
         pathof any kind (contains delimiters) or seem to be either UNC
965
         path or one with a drive letter spec in it: \\Server\share, C:\
966
      */
967
      if (((*path == *DirectorySeparator) && (*(path+1) == *DirectorySeparator)) ||
968
            (*(path+1) == ':') ||
969
              (strchr(path,*DirectorySeparator) != (char *) NULL))
970
        return IsAccessibleNoLogging(path);
971
#else
972
      /* In any other case, we just look to see if it has path delimiters */
973
      if ((strchr(path,*DirectorySeparator) != (char *) NULL))
974
        return IsAccessibleNoLogging(path);
975
#endif
976
252
    }
977
0
  return False;
978
252
}
979
#endif /* !defined(UseInstalledMagick) */
980
981
/*
982
  Try and figure out the path and name of the client
983
 */
984
static void
985
InitializeMagickClientPathAndName(const char *path)
986
252
{
987
252
#if !defined(UseInstalledMagick)
988
252
  const char
989
252
    *spath;
990
991
252
  char
992
252
    execution_path[MaxTextExtent];
993
994
  /* the following is to make the logging more readable later on */
995
252
  spath = path;
996
252
  if (spath == (char *) NULL)
997
0
    spath = "NULL";
998
252
  if (*spath == '\0')
999
0
    spath = "EMPTY";
1000
1001
252
  *execution_path='\0';
1002
252
  if (!IsValidFilesystemPath(path))
1003
0
    {
1004
      /*
1005
        If the path passed is NULL or invalid then we try to ask the
1006
        OS what the name of the executable is. Callers will often pass
1007
        NULL in order to invoke this functionality.
1008
      */
1009
0
      if (GetExecutionPath(execution_path))
1010
0
        {
1011
          /*
1012
            The call to the OS worked so we can do all the settings
1013
          */
1014
0
          (void) DefineClientPathAndName(execution_path);
1015
0
          (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1016
0
            "Invalid path \"%s\" passed - asking OS worked: \"%s\"",spath,
1017
0
              execution_path);
1018
0
        }
1019
0
      else
1020
0
        {
1021
          /*
1022
            The call to the OS failed so we try to compute a usable
1023
            path based on the current working directory or by
1024
            searching the executable search path.
1025
          */
1026
0
          if (path)
1027
0
            (void) strlcpy(execution_path,path,MaxTextExtent);
1028
0
          if (GetExecutionPathUsingName(execution_path))
1029
0
            {
1030
0
              (void) DefineClientPathAndName(execution_path);
1031
0
              (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1032
0
                "Invalid path \"%s\" passed - asking OS failed, getcwd worked: \"%s\"",spath,
1033
0
                  execution_path);
1034
0
            }
1035
0
          else
1036
0
            {
1037
              /*
1038
                At this point we are totally hosed and have nothing to
1039
                go on for the path, so all we can do is log the error
1040
              */
1041
0
              (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1042
0
                "Invalid path \"%s\" passed - asking OS failed, getcwd also failed",spath);
1043
0
            }
1044
0
        }
1045
0
    }
1046
252
  else
1047
252
    {
1048
      /*
1049
        This is the easy one. The caller gave us the correct and
1050
        working path to the application, so we just use it
1051
      */
1052
252
      (void) strlcpy(execution_path,path,MaxTextExtent);
1053
252
      (void) DefineClientPathAndName(execution_path);
1054
252
      (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),"Valid path \"%s\"",spath);
1055
252
    }
1056
#else
1057
  ARG_NOT_USED(path);
1058
#endif
1059
252
}
1060
1061
/*
1062
  Establish signal handlers for common signals
1063
1064
*/
1065
static void
1066
InitializeMagickSignalHandlers(void)
1067
252
{
1068
#if 0
1069
  /* termination of child process */
1070
#if defined(SIGCHLD)
1071
  MagickCondSignal(SIGCHLD,MagickIgnoreSignalHandler);
1072
#endif
1073
#endif
1074
1075
  /* hangup, default terminate */
1076
252
#if defined(SIGHUP)
1077
252
  MagickCondSignal(SIGHUP,MagickSignalHandler);
1078
252
#endif
1079
  /* interrupt (CONTROL-c), default terminate */
1080
252
#if defined(SIGINT)
1081
252
  MagickCondSignal(SIGINT,MagickSignalHandler);
1082
252
#endif
1083
  /* quit (CONTROL-\), default terminate with core */
1084
252
#if defined(SIGQUIT)
1085
252
  MagickCondSignal(SIGQUIT,MagickPanicSignalHandler);
1086
252
#endif
1087
  /* software-triggered abort, default terminate with core */
1088
252
#if defined(SIGABRT)
1089
252
  MagickCondSignal(SIGABRT,MagickPanicSignalHandler);
1090
252
#endif
1091
  /* floating point exception, default terminate with core */
1092
252
#if defined(SIGFPE)
1093
252
  MagickCondSignal(SIGFPE,MagickPanicSignalHandler);
1094
252
#endif
1095
  /* software termination signal from kill, default terminate */
1096
252
#if defined(SIGTERM)
1097
252
  MagickCondSignal(SIGTERM,MagickSignalHandler);
1098
252
#endif
1099
  /* Bus Error */
1100
252
#if defined(SIGBUS)
1101
252
  MagickCondSignal(SIGBUS,MagickPanicSignalHandler);
1102
252
#endif
1103
  /* segmentation fault */
1104
252
#if defined(SIGSEGV)
1105
252
  MagickCondSignal(SIGSEGV,MagickPanicSignalHandler);
1106
252
#endif
1107
  /* exceeded cpu limit, default terminate */
1108
252
#if defined(SIGXCPU)
1109
252
  MagickCondSignal(SIGXCPU,MagickSignalHandler);
1110
252
#endif
1111
  /* exceeded file size limit, default terminate */
1112
252
#if defined(SIGXFSZ)
1113
252
  MagickCondSignal(SIGXFSZ,MagickSignalHandler);
1114
252
#endif
1115
252
}
1116
1117
1118
MagickExport void
1119
InitializeMagick(const char *path)
1120
252
{
1121
252
  ExceptionInfo exception;
1122
252
  GetExceptionInfo(&exception);
1123
252
  (void) InitializeMagickEx(path,0,&exception);
1124
252
  if (exception.severity != UndefinedException)
1125
0
    CatchException(&exception);
1126
252
  DestroyExceptionInfo(&exception);
1127
252
}
1128
1129
/*
1130
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1131
%                                                                             %
1132
%                                                                             %
1133
%                                                                             %
1134
%   I n i t i a l i z e M a g i c k E x                                       %
1135
%                                                                             %
1136
%                                                                             %
1137
%                                                                             %
1138
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1139
%
1140
%  InitializeMagickEx() initializes the GraphicsMagick environment,
1141
%  providing a bit more more control and visibility over initialization
1142
%  than the original InitializeMagick().  Use DestroyMagick() to destroy
1143
%  the GraphicsMagick environment when it is not longer needed.
1144
%
1145
%  InitializeMagick() or InitializeMagickEx() MUST be invoked by the using
1146
%  program before making use of GraphicsMagick functions or else the library
1147
%  will be unusable and any usage is likely to cause a crash.
1148
%
1149
%  This function should be invoked in the primary (original) thread of the
1150
%  application's process, and before starting any OpenMP threads, as part
1151
%  of program initialization.
1152
%
1153
%  If alternate memory allocations are provided via MagickAllocFunctions()
1154
%  then that function should be invoked before InitializeMagickEx() since
1155
%  the memory allocation functions need to be consistent.
1156
%
1157
%  Available options are:
1158
%
1159
%    o MAGICK_OPT_NO_SIGNAL_HANDER - Don't register ANSI/POSIX signal handlers
1160
%
1161
%  The format of the InitializeMagickEx function is:
1162
%
1163
%      MagickPassFail InitializeMagickEx(const char *path,
1164
%                                        unsigned int options,
1165
%                                        ExceptionInfo *exception)
1166
%
1167
%  A description of each parameter follows:
1168
%
1169
%    o path: The execution path of the current GraphicsMagick client (or NULL)
1170
%
1171
%    o options: Options bit flags tailoring initializations performed
1172
%
1173
%    o exception: Information about initialization failure is reported here.
1174
%
1175
%
1176
*/
1177
1178
MagickExport MagickPassFail
1179
InitializeMagickEx(const char *path, unsigned int options,
1180
                   ExceptionInfo *exception)
1181
252
{
1182
  /*
1183
    NOTE: This routine sets up the path to the client which needs to
1184
    be determined before almost anything else works right. This also
1185
    includes logging!!! So we can't start logging until the path is
1186
    actually saved. As soon as we know what the path is we make the
1187
    same call to DefineClientSettings to set it up. Please make sure
1188
    that this rule is followed in any future updates the this code!!!
1189
  */
1190
1191
252
  const char
1192
252
    *p;
1193
1194
252
  MagickPassFail
1195
252
    status = MagickPass;
1196
1197
252
  (void) exception;
1198
1199
  /* Acquire initialization lock */
1200
252
  SPINLOCK_WAIT;
1201
1202
252
  if (MagickInitialized == InitInitialized)
1203
0
    {
1204
      /* Release initialization lock */
1205
0
      SPINLOCK_RELEASE;
1206
0
      return status;
1207
0
    }
1208
1209
#if defined(USE_GLIBC_MTRACE) && USE_GLIBC_MTRACE
1210
  mtrace();
1211
#endif /* if defined(USE_GLIBC_MTRACE) && USE_GLIBC_MTRACE */
1212
1213
  /* Save initialization options in case we need them later */
1214
252
  initialize_magick_options = options;
1215
1216
#if defined(MSWINDOWS)
1217
# if defined(_DEBUG) && !defined(__BORLANDC__)
1218
  {
1219
    int
1220
      debug;
1221
1222
    debug=_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
1223
    debug|=_CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_DELAY_FREE_MEM_DF |
1224
      _CRTDBG_LEAK_CHECK_DF;
1225
    /* debug=_CrtSetDbgFlag(debug); */
1226
    /* _ASSERTE(_CrtCheckMemory()); */
1227
  }
1228
# endif /* defined(_DEBUG) */
1229
#endif /* defined(MSWINDOWS) */
1230
1231
  /* Initialize semaphores */
1232
252
  InitializeSemaphore();
1233
1234
  /* Initialize exception handling */
1235
252
  InitializeMagickExceptionHandling();
1236
1237
  /* Initialize logging */
1238
252
  InitializeLogInfo();
1239
1240
  /* Initialize our random number generator */
1241
252
  InitializeMagickRandomGenerator();
1242
1243
252
  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1244
252
                        "Initialize Magick (path=\"%s\", options = 0x%04x)",
1245
252
                        path ? path : "(null)", options);
1246
1247
  /*
1248
    Set the filesystem block size.
1249
  */
1250
252
  {
1251
252
    size_t
1252
252
      block_size=16384;
1253
1254
252
    if ((p=getenv("MAGICK_IOBUF_SIZE")) != (const char *) NULL)
1255
0
      {
1256
0
        long
1257
0
          block_size_long;
1258
1259
0
        block_size_long = MagickAtoL(p);
1260
0
        if ((block_size_long > 0L) && (block_size_long <= 2097152L))
1261
0
          block_size=(size_t) block_size_long;
1262
0
        else
1263
0
          (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1264
0
                                "Ignoring unreasonable MAGICK_IOBUF_SIZE of "
1265
0
                                "%ld bbytes", block_size_long);
1266
0
      }
1267
1268
252
    MagickSetFileSystemBlockSize(block_size);
1269
252
  }
1270
1271
  /*
1272
    Establish the path, filename, and display name of the client app
1273
  */
1274
252
  InitializeMagickClientPathAndName(path);
1275
  /*
1276
    If the client name did not get setup for any reason, we take one
1277
    last shot at it using the data the caller passed us.
1278
  */
1279
252
  if (GetClientName() == (const char *) NULL)
1280
0
    DefineClientName(path);
1281
1282
  /*
1283
    Initialize any logging configuration which could not complete
1284
    since we did not know the installation directory yet
1285
  */
1286
252
  InitializeLogInfoPost();
1287
1288
  /*
1289
    Adjust minimum coder class if requested.
1290
  */
1291
252
  if ((p=getenv("MAGICK_CODER_STABILITY")) != (const char *) NULL)
1292
0
    {
1293
0
      if (LocaleCompare(p,"BROKEN") == 0)
1294
0
        MinimumCoderClass=BrokenCoderClass;
1295
0
      else if (LocaleCompare(p,"UNSTABLE") == 0)
1296
0
        MinimumCoderClass=UnstableCoderClass;
1297
0
      else if (LocaleCompare(p,"STABLE") == 0)
1298
0
        MinimumCoderClass=StableCoderClass;
1299
0
      else if (LocaleCompare(p,"PRIMARY") == 0)
1300
0
        MinimumCoderClass=PrimaryCoderClass;
1301
0
    }
1302
1303
#if defined(MSWINDOWS)
1304
  NTInitializeExceptionHandlers();  /* WIN32 Exceptions */
1305
#endif /* defined(MSWINDOWS) */
1306
252
  if (!(options & MAGICK_OPT_NO_SIGNAL_HANDER))
1307
252
    InitializeMagickSignalHandlers(); /* Signal handlers */
1308
252
  InitializeTemporaryFiles();       /* Temporary files (semaphore only) */
1309
252
  InitializeMagickResources();      /* Resources (semaphore+calculations) */
1310
252
  InitializeMagickRegistry();       /* Image/blob registry (semaphore+vars only) */
1311
252
  InitializeConstitute();           /* Constitute (semaphore only) */
1312
252
  InitializeMagickInfoList();       /* Coder registrations + modules */
1313
  /*InitializeMagicInfo();*/        /* File format detection */
1314
252
  InitializeTypeInfo();             /* Font information (semaphore only) */
1315
252
  InitializeDelegateInfo();         /* External delegate information (semaphore only) */
1316
252
  InitializeColorInfo();            /* Color database (semaphore only) */
1317
252
  InitializeMagickMonitor();        /* Progress monitor (semaphore only) */
1318
252
  MagickInitializeCommandInfo();    /* Command parser (semaphore only) */
1319
1320
  /* Let's log the three important setting as we exit this routine */
1321
252
  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1322
252
                        "Path: \"%s\" Name: \"%s\" Filename: \"%s\"",
1323
252
                        GetClientPath(),GetClientName(),GetClientFilename());
1324
1325
  /* Now initialized */
1326
252
  MagickInitialized=InitInitialized;
1327
1328
  /* Release initialization lock */
1329
252
  SPINLOCK_RELEASE;
1330
1331
252
  return status;
1332
252
}
1333

1334
/*
1335
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1336
%                                                                             %
1337
%                                                                             %
1338
%                                                                             %
1339
+   I n i t i a l i z e M a g i c k I n f o L i s t                           %
1340
%                                                                             %
1341
%                                                                             %
1342
%                                                                             %
1343
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1344
%
1345
%  Method InitializeMagickInfoList initializes the magick info facility
1346
%
1347
%  The format of the InitializeMagickInfoList method is:
1348
%
1349
%      MagickPassFail InitializeMagickInfoList(void)
1350
%
1351
%
1352
*/
1353
static MagickPassFail
1354
InitializeMagickInfoList(void)
1355
252
{
1356
252
  assert(magick_semaphore == (SemaphoreInfo *) NULL);
1357
252
  magick_semaphore=AllocateSemaphoreInfo();
1358
1359
252
  assert(module_semaphore == (SemaphoreInfo *) NULL);
1360
252
  module_semaphore=AllocateSemaphoreInfo();
1361
1362
252
  InitializeMagickModules();        /* Module loader */
1363
1364
252
  return MagickPass;
1365
252
}
1366

1367
/*
1368
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1369
%                                                                             %
1370
%                                                                             %
1371
%                                                                             %
1372
%   I s M a g i c k C o n f l i c t                                           %
1373
%                                                                             %
1374
%                                                                             %
1375
%                                                                             %
1376
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1377
%
1378
%  Method IsMagickConflict returns true if the image format conflicts with
1379
%  a logical drive (.e.g. X:).
1380
%
1381
%  The format of the IsMagickConflict method is:
1382
%
1383
%      MagickBool IsMagickConflict(const char *magick)
1384
%
1385
%  A description of each parameter follows:
1386
%
1387
%    o status: Method IsMagickConflict returns true if the image format
1388
%      conflicts with a logical drive.
1389
%
1390
%    o magick: Specifies the image format.
1391
%
1392
%
1393
*/
1394
MagickExport MagickBool
1395
IsMagickConflict(const char *magick)
1396
1.58M
{
1397
1.58M
  assert(magick != (char *) NULL);
1398
#if defined(MSWINDOWS) || defined(__CYGWIN__)
1399
  return(NTIsMagickConflict(magick));
1400
#endif
1401
1.58M
  ARG_NOT_USED(magick);
1402
1.58M
  return(MagickFalse);
1403
1.58M
}
1404

1405
/*
1406
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1407
%                                                                             %
1408
%                                                                             %
1409
%                                                                             %
1410
%  L i s t M a g i c k I n f o                                                %
1411
%                                                                             %
1412
%                                                                             %
1413
%                                                                             %
1414
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1415
%
1416
%  ListMagickInfo() lists the image formats to a file.
1417
%
1418
%  The format of the ListMagickInfo method is:
1419
%
1420
%      MagickPassFail ListMagickInfo(FILE *file,ExceptionInfo *exception)
1421
%
1422
%  A description of each parameter follows.
1423
%
1424
%    o file: A file handle.
1425
%
1426
%    o exception: Return any errors or warnings in this structure.
1427
%
1428
%
1429
*/
1430
MagickExport MagickPassFail
1431
ListMagickInfo(FILE *file,ExceptionInfo *exception)
1432
0
{
1433
1434
0
  MagickInfo
1435
0
    **magick_array;
1436
1437
0
  int
1438
0
    i;
1439
1440
0
  if (file == (FILE *) NULL)
1441
0
    file=stdout;
1442
1443
0
  magick_array=GetMagickInfoArray(exception);
1444
0
  if (!magick_array)
1445
0
    return False;
1446
1447
0
  (void) fprintf(file,"   Format L  Mode  Description\n");
1448
0
  (void) fprintf(file,"--------------------------------------------------------"
1449
0
    "------------------------\n");
1450
0
  for (i=0; magick_array[i] != 0; i++)
1451
0
  {
1452
0
    if (magick_array[i]->stealth)
1453
0
      continue;
1454
0
    (void) fprintf(file,"%9s %c  %c%c%c",
1455
0
                   magick_array[i]->name ? magick_array[i]->name : "",
1456
0
                   (magick_array[i]->coder_class == PrimaryCoderClass ? 'P' :
1457
0
                    (magick_array[i]->coder_class == StableCoderClass ? 'S' :
1458
0
                     'U')),
1459
0
                   (magick_array[i]->decoder ? 'r' : '-'),
1460
0
                   (magick_array[i]->encoder ? 'w' : '-'),
1461
0
                   ((magick_array[i]->encoder && magick_array[i]->adjoin) ? '+' : '-'));
1462
0
    if (magick_array[i]->description != (char *) NULL)
1463
0
      (void) fprintf(file,"  %.1024s",magick_array[i]->description);
1464
0
    if (magick_array[i]->version != (char *) NULL)
1465
0
      (void) fprintf(file," (%.1024s)",magick_array[i]->version);
1466
0
    (void) fprintf(file,"\n");
1467
0
    if (magick_array[i]->note != (char *) NULL)
1468
0
      {
1469
0
        char
1470
0
          **text;
1471
1472
0
        text=StringToList(magick_array[i]->note);
1473
0
        if (text != (char **) NULL)
1474
0
          {
1475
0
            register long
1476
0
              j;
1477
1478
0
            for (j=0; text[j] != (char *) NULL; j++)
1479
0
              {
1480
0
                (void) fprintf(file,"            %.1024s\n",text[j]);
1481
0
                MagickFreeMemory(text[j]);
1482
0
              }
1483
0
            MagickFreeMemory(text);
1484
0
          }
1485
0
      }
1486
0
  }
1487
0
  (void) fprintf(file,"\n Meaning of 'L': P=Primary, S=Stable, U=Unstable\n");
1488
0
  (void) fflush(file);
1489
0
  MagickFreeMemory(magick_array);
1490
0
  return(MagickPass);
1491
0
}
1492

1493
/*
1494
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1495
%                                                                             %
1496
%                                                                             %
1497
%                                                                             %
1498
%  L i s t M o d u l e M a p                                                  %
1499
%                                                                             %
1500
%                                                                             %
1501
%                                                                             %
1502
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1503
%
1504
%  Method ListModuleMap lists the module alias info to a file in the XML
1505
%  format used by modules.mgk. True is returned on success.
1506
%
1507
%  The format of the ListModuleMap method is:
1508
%
1509
%      MagickPassFail ListModuleMap(FILE *file,ExceptionInfo *exception)
1510
%
1511
%  A description of each parameter follows.
1512
%
1513
%    o file:  An pointer to a FILE.
1514
%
1515
%    o exception: Return any errors or warnings in this structure.
1516
%
1517
%
1518
*/
1519
MagickExport MagickPassFail
1520
ListModuleMap(FILE *file,ExceptionInfo *exception)
1521
0
{
1522
0
  MagickInfo
1523
0
    **magick_array;
1524
1525
0
  int
1526
0
    i;
1527
1528
0
  if (file == (const FILE *) NULL)
1529
0
    file=stdout;
1530
1531
0
   magick_array=GetMagickInfoArray(exception);
1532
0
   if (!magick_array)
1533
0
     return MagickFail;
1534
1535
0
   (void) fprintf(file, "<?xml version=\"1.0\"?>\n");
1536
0
   (void) fprintf(file, "<!-- %s -->\n",GetMagickCopyright());
1537
0
   (void) fprintf(file, "<!-- Magick Module Alias Map (modules.mgk) -->\n");
1538
0
   (void) fprintf(file, "<modulemap>\n");
1539
1540
0
   for (i=0; magick_array[i] != 0; i++)
1541
0
     {
1542
0
       if (LocaleCompare(magick_array[i]->name,magick_array[i]->module) != 0)
1543
0
         {
1544
0
           (void) fprintf(file, "  <module magick=\"%s\" name=\"%s\" />\n",
1545
0
                          magick_array[i]->name,
1546
0
                          (magick_array[i]->module == NULL ? "(null)" :
1547
0
                           magick_array[i]->module));
1548
0
         }
1549
0
     }
1550
0
   (void) fprintf(file, "</modulemap>\n");
1551
0
   (void) fflush(file);
1552
1553
0
   MagickFreeMemory(magick_array);
1554
1555
0
   return(MagickPass);
1556
0
}
1557

1558
/*
1559
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1560
%                                                                             %
1561
%                                                                             %
1562
%                                                                             %
1563
%  M a g i c k T o M i m e                                                    %
1564
%                                                                             %
1565
%                                                                             %
1566
%                                                                             %
1567
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1568
%
1569
%  Method MagickToMime returns the officially registered (or de facto) MIME
1570
%  media-type (see https://www.iana.org/assignments/media-types/media-types.xhtml)
1571
%  corresponding to a magick string.  If there is no registered media-type,
1572
%  then the string "image/x-magick" (all lower case) is returned.  The returned
1573
%  string must be deallocated by the user.
1574
%
1575
%  The format of the MagickToMime method is:
1576
%
1577
%      char *MagickToMime(const char *magick)
1578
%
1579
%  A description of each parameter follows.
1580
%
1581
%   o  magick:  GraphicsMagick format specification "magick" tag.
1582
%
1583
%
1584
*/
1585
MagickExport char *
1586
MagickToMime(const char *magick)
1587
3.12k
{
1588
3.12k
  char
1589
3.12k
    media[MaxTextExtent];
1590
1591
3.12k
  unsigned int
1592
3.12k
    i;
1593
1594
3.12k
  static const struct
1595
3.12k
  {
1596
3.12k
    const char
1597
3.12k
    magick[14],
1598
3.12k
      *media;
1599
3.12k
  }
1600
3.12k
    MediaTypes[] =
1601
3.12k
    {
1602
3.12k
      { "apng",  "image/apng" },
1603
3.12k
      { "avc",   "image/avci" },
1604
3.12k
      { "avi",   "video/avi" },
1605
3.12k
      { "avif",  "image/avif" },
1606
3.12k
      { "bmp",   "image/bmp" },
1607
3.12k
      { "cgm",   "image/cgm;Version=4;ProfileId=WebCGM" }, /* W3 WebCGM */
1608
3.12k
      { "dcm",   "application/dicom" }, /* Incomplete.  See RFC 3240 */
1609
3.12k
      { "dpx",   "image/dpx" },
1610
3.12k
      { "emf",   "image/emf" },
1611
3.12k
      { "epdf",  "application/pdf" },
1612
3.12k
      { "epi",   "application/postscript" },
1613
3.12k
      { "eps",   "application/postscript" },
1614
3.12k
      { "eps2",  "application/postscript" },
1615
3.12k
      { "eps3",  "application/postscript" },
1616
3.12k
      { "epsf",  "application/postscript" },
1617
3.12k
      { "ept",   "application/postscript" },
1618
3.12k
      { "fax",   "image/g3fax" },
1619
3.12k
      { "fits",  "image/fits" },
1620
3.12k
      { "fpx",   "image/vnd.fpx" },
1621
3.12k
      { "g3",    "image/g3fax" },
1622
3.12k
      { "gif",   "image/gif" },
1623
3.12k
      { "gif87", "image/gif" },
1624
3.12k
      { "heic",  "image/heic" },
1625
3.12k
      { "heic-sequence", "image/heic-sequence" },
1626
3.12k
      { "heif",  "image/heif" },
1627
3.12k
      { "heif-sequence", "image/heif-sequence" },
1628
3.12k
      { "ico",   "image/x-icon" },
1629
3.12k
      { "j2c",   "image/j2c" },
1630
3.12k
      { "jpeg",  "image/jpeg" },
1631
3.12k
      { "jpg",   "image/jpeg" },
1632
3.12k
      { "jxl",   "image/jxl" },
1633
3.12k
      { "mng",   "video/x-mng" },
1634
3.12k
      { "mpeg",  "video/mpeg" },
1635
3.12k
      { "pdf",   "application/pdf" },
1636
3.12k
      { "png",   "image/png" },
1637
3.12k
      { "ps",    "application/postscript" },
1638
3.12k
      { "ps2",   "application/postscript" },
1639
3.12k
      { "ps3",   "application/postscript" },
1640
3.12k
      { "svg",   "image/svg+xml" },
1641
3.12k
      { "tif",   "image/tiff" },
1642
3.12k
      { "tiff",  "image/tiff" },
1643
3.12k
      { "wbmp",  "image/vnd.wap.wbmp" },
1644
3.12k
      { "webp",  "image/webp" },
1645
3.12k
      { "wmf",   "image/wmf" }
1646
3.12k
    };
1647
1648
102k
  for (i=0; i < ArraySize(MediaTypes); i++)
1649
102k
    if (LocaleCompare(MediaTypes[i].magick,magick) == 0)
1650
2.73k
      return(AllocateString(MediaTypes[i].media));
1651
395
  MagickFormatString(media,sizeof(media),"image/x-%.1024s",magick);
1652
395
  LocaleLower(media+8);
1653
395
  return(AllocateString(media));
1654
3.12k
}
1655

1656
/*
1657
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1658
%                                                                             %
1659
%                                                                             %
1660
%                                                                             %
1661
%   R e g i s t e r M a g i c k I n f o                                       %
1662
%                                                                             %
1663
%                                                                             %
1664
%                                                                             %
1665
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1666
%
1667
%  RegisterMagickInfo() adds attributes for a particular image format to the
1668
%  list of supported formats.  The attributes include the image format name,
1669
%  a method to read and/or write the format, whether the format supports the
1670
%  saving of more than one frame to the same file or blob, whether the format
1671
%  supports native in-memory I/O, and a brief description of the format.
1672
%
1673
%  The format of the RegisterMagickInfo method is:
1674
%
1675
%      MagickInfo *RegisterMagickInfo(MagickInfo *magick_info)
1676
%
1677
%  A description of each parameter follows:
1678
%
1679
%    o magick_info: The magick info.
1680
%
1681
*/
1682
MagickExport MagickInfo *
1683
RegisterMagickInfo(MagickInfo *magick_info)
1684
984
{
1685
984
  assert(magick_info != (MagickInfo *) NULL);
1686
984
  assert(magick_info->signature == MagickSignature);
1687
1688
  /*
1689
    Remove any existing entry.
1690
  */
1691
984
  (void) UnregisterMagickInfo(magick_info->name);
1692
1693
  /*
1694
    Verify that coder stability level is sufficient.
1695
  */
1696
984
  if (magick_info->coder_class >= MinimumCoderClass)
1697
984
    {
1698
      /*
1699
        Add to front of list.
1700
      */
1701
984
      LockSemaphoreInfo(magick_semaphore);
1702
984
      magick_info->previous=(MagickInfo *) NULL;
1703
984
      magick_info->next=magick_list;
1704
984
      if (magick_info->next != (MagickInfo *) NULL)
1705
859
        magick_info->next->previous=magick_info;
1706
984
      magick_list=magick_info;
1707
984
      UnlockSemaphoreInfo(magick_semaphore);
1708
984
      return(magick_info);
1709
984
    }
1710
1711
  /*
1712
    Discard registration and return NULL.
1713
  */
1714
0
  DestroyMagickInfo(&magick_info);
1715
0
  return(magick_info);
1716
984
}
1717

1718
/*
1719
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1720
%                                                                             %
1721
%                                                                             %
1722
%                                                                             %
1723
%   P a n i c D e s t r o y M a g i c k                                       %
1724
%                                                                             %
1725
%                                                                             %
1726
%                                                                             %
1727
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1728
%
1729
%  PanicDestroyMagick() destroys only persistent allocations such as
1730
%  temporary files.  Other allocations (e.g. semaphores and heap memory)
1731
%  remain allocated.  This function is an alternative to DestroyMagick()
1732
%  which is async-safe so it may be invoked from signal handers, and
1733
%  may be invoked from thread context.  No semaphores are taken and no
1734
%  additional heap memory is allocated by this function.  The program
1735
%  must quit immediately after invoking this function.
1736
%
1737
%  The format of the PanicDestroyMagick function is:
1738
%
1739
%      void PanicDestroyMagick(void)
1740
%
1741
%
1742
*/
1743
/*
1744
  Set to 1 to break the memory allocation functions.  This is a
1745
  debugging aid.  In a multi-threaded program, other threads may
1746
  still be allocating and deallocating memory while a signal
1747
  handler is called.
1748
*/
1749
#define MAGICK_BREAK_HEAP 0
1750
#if MAGICK_BREAK_HEAP
1751
static void
1752
PanicFreeFunc(void *ptr)
1753
{
1754
  char err_str[] = "Attempt to free memory in PanicDestroyMagick()\n";
1755
  ARG_NOT_USED(ptr);
1756
  if (write(STDERR_FILENO,err_str,sizeof(err_str)-1) == -1)
1757
    {
1758
      /* Exists to quench warning */
1759
    }
1760
}
1761
static void *
1762
PanicMallocFunc(size_t size)
1763
{
1764
  char err_str[] = "Attempt to malloc memory in PanicDestroyMagick()\n";
1765
  ARG_NOT_USED(size);
1766
  if (write(STDERR_FILENO,err_str,sizeof(err_str)-1) == -1)
1767
    {
1768
      /* Exists to quench warning */
1769
    }
1770
  return (void *) NULL;
1771
}
1772
static void *
1773
PanicReallocFunc(void *ptr, size_t size)
1774
{
1775
  char err_str[] = "Attempt to realloc memory in PanicDestroyMagick()\n";
1776
  ARG_NOT_USED(ptr);
1777
  ARG_NOT_USED(size);
1778
  if (write(STDERR_FILENO,err_str,sizeof(err_str)-1) == -1)
1779
    {
1780
      /* Exists to quench warning */
1781
    }
1782
  return (void *) NULL;
1783
}
1784
#endif /* if MAGICK_BREAK_HEAP */
1785
MagickExport void
1786
PanicDestroyMagick(void)
1787
0
{
1788
0
  if (MagickInitialized == InitInitialized)
1789
0
    {
1790
#if MAGICK_BREAK_HEAP
1791
      /*
1792
        Enforce that we don't use the memory allocation functions by
1793
        setting them all to dummy functions.
1794
      */
1795
      MagickAllocFunctions(PanicFreeFunc,PanicMallocFunc,PanicReallocFunc);
1796
#endif /* if MAGICK_BREAK_HEAP */
1797
      /*
1798
        Release persistent resources
1799
      */
1800
0
      PurgeTemporaryFilesAsyncSafe();
1801
0
    }
1802
0
}
1803

1804
/*
1805
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1806
%                                                                             %
1807
%                                                                             %
1808
%                                                                             %
1809
%   S e t M a g i c k I n f o                                                 %
1810
%                                                                             %
1811
%                                                                             %
1812
%                                                                             %
1813
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1814
%
1815
%  Method SetMagickInfo allocates a MagickInfo structure and initializes the
1816
%  members to default values.
1817
%
1818
%  The format of the SetMagickInfo method is:
1819
%
1820
%      MagickInfo *SetMagickInfo(const char *name)
1821
%
1822
%  A description of each parameter follows:
1823
%
1824
%    o magick_info: Method SetMagickInfo returns the allocated and initialized
1825
%      MagickInfo structure.
1826
%
1827
%    o name: a character string that represents the image format associated
1828
%      with the MagickInfo structure.
1829
%
1830
%
1831
*/
1832
MagickExport MagickInfo *
1833
SetMagickInfo(const char *name)
1834
984
{
1835
984
  MagickInfo
1836
984
    *magick_info;
1837
1838
984
  assert(name != (const char *) NULL);
1839
984
  magick_info=MagickAllocateClearedMemory(MagickInfo *,sizeof(MagickInfo));
1840
984
  if (magick_info == (MagickInfo *) NULL)
1841
0
    MagickFatalError3(ResourceLimitFatalError,MemoryAllocationFailed,
1842
984
      UnableToAllocateMagickInfo);
1843
984
  magick_info->name=name;
1844
984
  magick_info->adjoin=MagickTrue;
1845
984
  magick_info->raw=MagickFalse;
1846
984
  magick_info->stealth=MagickFalse;
1847
984
  magick_info->seekable_stream=MagickFalse;
1848
984
  magick_info->blob_support=MagickTrue;
1849
984
  magick_info->thread_support=MagickTrue;
1850
984
  magick_info->coder_class=StableCoderClass;
1851
984
  magick_info->extension_treatment=HintExtensionTreatment;
1852
984
  magick_info->signature=MagickSignature;
1853
984
  return(magick_info);
1854
984
}
1855

1856
/*
1857
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1858
%                                                                             %
1859
%                                                                             %
1860
%                                                                             %
1861
%   U n r e g i s t e r M a g i c k I n f o                                   %
1862
%                                                                             %
1863
%                                                                             %
1864
%                                                                             %
1865
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1866
%
1867
%  Method UnregisterMagickInfo removes a name from the magick info list.  It
1868
%  returns MagickFail if the name does not exist in the list otherwise
1869
%  MagickPass.
1870
%
1871
%  The format of the UnregisterMagickInfo method is:
1872
%
1873
%      unsigned int UnregisterMagickInfo(const char *name)
1874
%
1875
%  A description of each parameter follows:
1876
%
1877
%    o status: Method UnregisterMagickInfo returns False if the name does not
1878
%      exist in the list otherwise True.
1879
%
1880
%    o name: a character string that represents the image format we are
1881
%      looking for.
1882
%
1883
*/
1884
MagickExport MagickPassFail
1885
UnregisterMagickInfo(const char *name)
1886
984
{
1887
984
  MagickInfo
1888
984
    *magick_info;
1889
1890
984
  register MagickInfo
1891
984
    *p;
1892
1893
984
  unsigned int
1894
984
    status;
1895
1896
984
  assert(name != (const char *) NULL);
1897
984
  status=MagickFail;
1898
984
  LockSemaphoreInfo(magick_semaphore);
1899
23.2k
  for (p=magick_list; p != (MagickInfo *) NULL; p=p->next)
1900
22.2k
  {
1901
22.2k
    if (LocaleCompare(p->name,name) != 0)
1902
22.2k
      continue;
1903
0
    if (p->next != (MagickInfo *) NULL)
1904
0
      p->next->previous=p->previous;
1905
0
    if (p->previous != (MagickInfo *) NULL)
1906
0
      p->previous->next=p->next;
1907
0
    else
1908
0
      magick_list=p->next;
1909
0
    magick_info=p;
1910
0
    DestroyMagickInfo(&magick_info);
1911
0
    status=MagickPass;
1912
0
    break;
1913
22.2k
  }
1914
984
  UnlockSemaphoreInfo(magick_semaphore);
1915
984
  return(status);
1916
984
}