Coverage Report

Created: 2026-06-16 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/graphicsmagick/magick/delegate.c
Line
Count
Source
1
/*
2
% Copyright (C) 2003-2026 GraphicsMagick Group
3
% Copyright (C) 2002 ImageMagick Studio
4
%
5
% This program is covered by multiple licenses, which are described in
6
% Copyright.txt. You should have received a copy of Copyright.txt with this
7
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
8
%
9
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10
%                                                                             %
11
%                                                                             %
12
%           DDDD   EEEEE  L      EEEEE   GGGG   AAA   TTTTT  EEEEE            %
13
%           D   D  E      L      E      G      A   A    T    E                %
14
%           D   D  EEE    L      EEE    G  GG  AAAAA    T    EEE              %
15
%           D   D  E      L      E      G   G  A   A    T    E                %
16
%           DDDD   EEEEE  LLLLL  EEEEE   GGG   A   A    T    EEEEE            %
17
%                                                                             %
18
%                                                                             %
19
%                   Methods to Read/Write/Invoke Delegates                    %
20
%                                                                             %
21
%                                                                             %
22
%                             Software Design                                 %
23
%                               John Cristy                                   %
24
%                               October 1998                                  %
25
%                                                                             %
26
%                                                                             %
27
%                                                                             %
28
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
29
%
30
%  The Delegates methods associate a set of commands with a particular
31
%  image format.  GraphicsMagick uses delegates for formats it does not handle
32
%  directly.
33
%
34
%  Thanks to Bob Friesenhahn for the initial inspiration and design of the
35
%  delegates methods.
36
%
37
%
38
*/
39

40
/*
41
  Include declarations.
42
*/
43
#include "magick/studio.h"
44
#include "magick/blob.h"
45
#include "magick/constitute.h"
46
#include "magick/delegate.h"
47
#include "magick/log.h"
48
#if defined(MSWINDOWS) || defined(__CYGWIN__)
49
# include "magick/nt_feature.h"
50
#endif
51
#if defined(POSIX)
52
# include "magick/unix_port.h"
53
#endif
54
#include "magick/semaphore.h"
55
#include "magick/tempfile.h"
56
#include "magick/utility.h"
57

58
/*
59
  Define declarations.
60
*/
61
20
#define DelegateFilename  "delegates.mgk"
62

63
/*
64
  Declare delegate map.
65
*/
66
static char
67
  *DelegateMap = (char *)
68
    "<?xml version=\"1.0\"?>"
69
    "<delegatemap>"
70
    "  <delegate stealth=\"True\" />"
71
    "</delegatemap>";
72

73
/*
74
  Global declaractions.
75
*/
76
static SemaphoreInfo
77
  *delegate_semaphore = (SemaphoreInfo *) NULL;
78
79
static DelegateInfo
80
  *delegate_list = (DelegateInfo *) NULL;
81

82
/*
83
  Forward declaractions.
84
*/
85
static unsigned int
86
  ReadConfigureFile(const char *,const unsigned long,ExceptionInfo *);
87

88
/*
89
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
90
%                                                                             %
91
%                                                                             %
92
%                                                                             %
93
%   D e s t r o y D e l e g a t e I n f o                                     %
94
%                                                                             %
95
%                                                                             %
96
%                                                                             %
97
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
98
%
99
%  Method DestroyDelegateInfo deallocates memory associated with the delegates
100
%  list.
101
%
102
%  The format of the DestroyDelegateInfo method is:
103
%
104
%      DestroyDelegateInfo(void)
105
%
106
*/
107
MagickExport void DestroyDelegateInfo(void)
108
0
{
109
0
  DelegateInfo
110
0
    *delegate_info;
111
112
0
  register DelegateInfo
113
0
    *p;
114
115
0
  for (p=delegate_list; p != (DelegateInfo *) NULL; )
116
0
  {
117
0
    delegate_info=p;
118
0
    p=p->next;
119
0
    if (delegate_info->path != (char *) NULL)
120
0
      MagickFreeMemory(delegate_info->path);
121
0
    if (delegate_info->decode != (char *) NULL)
122
0
      MagickFreeMemory(delegate_info->decode);
123
0
    if (delegate_info->encode != (char *) NULL)
124
0
      MagickFreeMemory(delegate_info->encode);
125
0
    if (delegate_info->commands != (char *) NULL)
126
0
      MagickFreeMemory(delegate_info->commands);
127
0
    MagickFreeMemory(delegate_info);
128
0
  }
129
0
  delegate_list=(DelegateInfo *) NULL;
130
0
  DestroySemaphoreInfo(&delegate_semaphore);
131
0
}
132

133
/*
134
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
135
%                                                                             %
136
%                                                                             %
137
%                                                                             %
138
%   G e t D e l e g a t e C o m m a n d                                       %
139
%                                                                             %
140
%                                                                             %
141
%                                                                             %
142
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
143
%
144
%  Method GetDelegateCommand replaces any embedded formatting characters with
145
%  the appropriate image attribute and returns the resulting command.
146
%
147
%  The format of the GetDelegateCommand method is:
148
%
149
%      char *GetDelegateCommand(const ImageInfo *image_info,Image *image,
150
%        const char *decode,const char *encode,ExceptionInfo *exception)
151
%
152
%  A description of each parameter follows:
153
%
154
%    o command: Method GetDelegateCommand returns the command associated
155
%      with specified delegate tag.
156
%
157
%    o image_info: The image info.
158
%
159
%    o image: The image.
160
%
161
%    o decode: Specifies the decode delegate we are searching for as a
162
%      character string.
163
%
164
%    o encode: Specifies the encode delegate we are searching for as a
165
%      character string.
166
%
167
%    o exception: Return any errors or warnings in this structure.
168
%
169
%
170
*/
171
MagickExport char *GetDelegateCommand(const ImageInfo *image_info,Image *image,
172
  const char *decode,const char *encode,ExceptionInfo *exception)
173
0
{
174
0
  char
175
0
    *command,
176
0
    **commands;
177
178
0
  const DelegateInfo
179
0
    *delegate_info;
180
181
0
  register long
182
0
    i;
183
184
0
  assert(image_info != (ImageInfo *) NULL);
185
0
  assert(image_info->signature == MagickSignature);
186
0
  assert(image != (Image *) NULL);
187
0
  assert(image->signature == MagickSignature);
188
0
  delegate_info=GetDelegateInfo(decode,encode,exception);
189
0
  if (delegate_info == (const DelegateInfo *) NULL)
190
0
    {
191
0
      ThrowException(exception,DelegateError,NoTagFound,
192
0
        decode ? decode : encode);
193
0
      return((char *) NULL);
194
0
    }
195
0
  commands=StringToList(delegate_info->commands);
196
0
  if (commands == (char **) NULL)
197
0
    {
198
0
      ThrowException(exception,ResourceLimitError,MemoryAllocationFailed,
199
0
        decode ? decode : encode);
200
0
      return((char *) NULL);
201
0
    }
202
0
  command=TranslateText(image_info,image,commands[0]);
203
0
  if (command == (char *) NULL)
204
0
    ThrowException(exception,ResourceLimitError,MemoryAllocationFailed,
205
0
      commands[0]);
206
  /*
207
    Free resources.
208
  */
209
0
  for (i=0; commands[i] != (char *) NULL; i++)
210
0
    MagickFreeMemory(commands[i]);
211
0
  MagickFreeMemory(commands);
212
0
  return(command);
213
0
}
214

215
/*
216
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
217
%                                                                             %
218
%                                                                             %
219
%                                                                             %
220
%   G e t D e l e g a t e I n f o                                             %
221
%                                                                             %
222
%                                                                             %
223
%                                                                             %
224
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
225
%
226
%  Method GetDelegateInfo returns any delegates associated with the specified
227
%  tag.
228
%
229
%  The format of the GetDelegateInfo method is:
230
%
231
%      const DelegateInfo *GetDelegateInfo(const char *decode,
232
%        const char *encode,ExceptionInfo *exception)
233
%
234
%  A description of each parameter follows:
235
%
236
%    o delgate_info: Method GetDelegateInfo returns any delegates associated
237
%      with the specified tag.
238
%
239
%    o decode: Specifies the decode delegate we are searching for as a
240
%      character string.
241
%
242
%    o encode: Specifies the encode delegate we are searching for as a
243
%      character string.
244
%
245
%    o exception: Return any errors or warnings in this structure.
246
%
247
%
248
*/
249
MagickExport const DelegateInfo *GetDelegateInfo(const char *decode,
250
  const char *encode,ExceptionInfo *exception)
251
30.0k
{
252
30.0k
  register DelegateInfo
253
30.0k
    *p;
254
255
30.0k
  if (delegate_list == (DelegateInfo *) NULL)
256
20
    {
257
20
      LockSemaphoreInfo(delegate_semaphore);
258
20
      if (delegate_list == (DelegateInfo *) NULL)
259
20
        (void) ReadConfigureFile(DelegateFilename,0,exception);
260
20
      UnlockSemaphoreInfo(delegate_semaphore);
261
20
    }
262
30.0k
  if ((LocaleCompare(decode,"*") == 0) && (LocaleCompare(encode,"*") == 0))
263
0
    return((const DelegateInfo *) delegate_list);
264
  /*
265
    Search for requested delegate.
266
  */
267
30.0k
  LockSemaphoreInfo(delegate_semaphore);
268
60.0k
  for (p=delegate_list; p != (const DelegateInfo *) NULL; p=p->next)
269
30.0k
  {
270
30.0k
    if (p->mode > 0)
271
0
      {
272
0
        if (LocaleCompare(p->decode,decode) == 0)
273
0
          break;
274
0
        continue;
275
0
      }
276
30.0k
    if (p->mode < 0)
277
0
      {
278
0
        if (LocaleCompare(p->encode,encode) == 0)
279
0
          break;
280
0
        continue;
281
0
      }
282
30.0k
    if (LocaleCompare(decode,p->decode) == 0)
283
0
      if (LocaleCompare(encode,p->encode) == 0)
284
0
        break;
285
30.0k
    if (LocaleCompare(decode,"*") == 0)
286
0
      if (LocaleCompare(encode,p->encode) == 0)
287
0
        break;
288
30.0k
    if (LocaleCompare(decode,p->decode) == 0)
289
0
      if (LocaleCompare(encode,"*") == 0)
290
0
        break;
291
30.0k
  }
292
30.0k
  if (p != (DelegateInfo *) NULL)
293
0
    if (p != delegate_list)
294
0
      {
295
        /*
296
          Self-adjusting list.
297
        */
298
0
        if (p->previous != (DelegateInfo *) NULL)
299
0
          p->previous->next=p->next;
300
0
        if (p->next != (DelegateInfo *) NULL)
301
0
          p->next->previous=p->previous;
302
0
        p->previous=(DelegateInfo *) NULL;
303
0
        p->next=delegate_list;
304
0
        delegate_list->previous=p;
305
0
        delegate_list=p;
306
0
      }
307
30.0k
  UnlockSemaphoreInfo(delegate_semaphore);
308
30.0k
  return((const DelegateInfo *) p);
309
30.0k
}
310

311
/*
312
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
313
%                                                                             %
314
%                                                                             %
315
%                                                                             %
316
%   G e t P o s t s c r i p t D e l e g a t e I n f o                         %
317
%                                                                             %
318
%                                                                             %
319
%                                                                             %
320
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
321
%
322
%  Method GetPostscriptDelegateInfo returns the Postscript delegate which
323
%  best supports the image type requested via ImageInfo
324
%
325
%  The format of the GetPostscriptDelegateInfo method is:
326
%
327
%      const DelegateInfo *(const ImageInfo *image_info,
328
%                           ExceptionInfo *exception)
329
%
330
%  A description of each parameter follows:
331
%
332
%    o image_info: The 'monochrome' and 'type' fields of image_info are used
333
%                  to select the best postscript delegate type.
334
%
335
%    o antialias: Set to best antialias setting for this delegate based on
336
%                 user requested antialias setting, and rendering depth.
337
%
338
%    o exception: Return any errors or warnings in this structure.
339
%
340
%
341
*/
342
MagickExport const DelegateInfo *GetPostscriptDelegateInfo(const ImageInfo *image_info,
343
                                                           unsigned int *antialias,
344
                                                           ExceptionInfo *exception)
345
29.7k
{
346
29.7k
  char
347
29.7k
    delegate[MaxTextExtent];
348
349
29.7k
  (void) strlcpy(delegate,"gs-color",sizeof(delegate));
350
29.7k
  *antialias=(image_info->antialias ? 4 : 1);
351
29.7k
  if ((image_info->monochrome) || (BilevelType == image_info->type))
352
0
    {
353
0
      (void) strlcpy(delegate,"gs-mono",sizeof(delegate));
354
0
      *antialias=1;
355
0
    }
356
29.7k
  else if (GrayscaleType == image_info->type)
357
0
    {
358
0
      (void) strlcpy(delegate,"gs-gray",sizeof(delegate));
359
0
    }
360
29.7k
  else if (PaletteType == image_info->type)
361
0
    {
362
0
      (void) strlcpy(delegate,"gs-palette",sizeof(delegate));
363
0
    }
364
29.7k
  else if ((GrayscaleMatteType == image_info->type) ||
365
29.7k
           (PaletteMatteType == image_info->type) ||
366
29.7k
           (TrueColorMatteType == image_info->type))
367
0
    {
368
0
      (void) strlcpy(delegate,"gs-color+alpha",sizeof(delegate));
369
0
    }
370
29.7k
  else if (ColorSeparationType == image_info->type)
371
0
    {
372
0
      (void) strlcpy(delegate,"gs-cmyk",sizeof(delegate));
373
0
    }
374
29.7k
  else if (ColorSeparationMatteType == image_info->type)
375
0
    {
376
0
      (void) strlcpy(delegate,"gs-cmyka",sizeof(delegate));
377
0
    }
378
29.7k
  return GetDelegateInfo(delegate,(char *) NULL,exception);
379
29.7k
}
380

381
/*
382
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
383
%                                                                             %
384
%                                                                             %
385
%                                                                             %
386
+   I n i t i a l i z e D e l e g a t e I n f o                               %
387
%                                                                             %
388
%                                                                             %
389
%                                                                             %
390
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
391
%
392
%  Method InitializeDelegateInfo initializes the delegate facility
393
%
394
%  The format of the InitializeDelegateInfo method is:
395
%
396
%      MagickPassFail InitializeDelegateInfo(void)
397
%
398
%
399
*/
400
MagickPassFail
401
InitializeDelegateInfo(void)
402
254
{
403
254
  assert(delegate_semaphore == (SemaphoreInfo *) NULL);
404
254
  delegate_semaphore=AllocateSemaphoreInfo();
405
254
  return MagickPass;
406
254
}
407

408
/*
409
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
410
%                                                                             %
411
%                                                                             %
412
%                                                                             %
413
%   I n v o k e D e l e g a t e                                               %
414
%                                                                             %
415
%                                                                             %
416
%                                                                             %
417
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
418
%
419
%  Method InvokeDelegate replaces any embedded formatting characters with
420
%  the appropriate image attribute and executes the resulting command.  False
421
%  is returned if the commands execute with success otherwise True.
422
%
423
%  The format of the InvokeDelegate method is:
424
%
425
%      unsigned int InvokeDelegate(ImageInfo *image_info,Image *image,
426
%        const char *decode,const char *encode,ExceptionInfo *exception)
427
%
428
%  A description of each parameter follows:
429
%
430
%    o image_info: The imageInfo.
431
%
432
%    o image: The image.
433
%
434
%    o exception: Return any errors or warnings in this structure.
435
%
436
%
437
*/
438
#if defined(POSIX)
439
/*
440
  Escape characters from the string 'src' to the string 'dst',
441
  limiting the number of output characters according to 'size'.
442
*/
443
static size_t
444
UnixShellTextEscape(char *dst, const char *src, const size_t size)
445
0
{
446
0
  size_t
447
0
    length=0;
448
449
0
  char
450
0
    *p;
451
452
0
  const char
453
0
    *q;
454
455
0
  assert(dst != NULL);
456
0
  assert(src != (const char *) NULL);
457
0
  assert(size >= 1);
458
459
  /*
460
    Copy src to dst within bounds of size-1, while escaping special
461
    characters.
462
  */
463
0
  for ( p=dst, q=src, length=0 ;
464
0
        (*q != 0) && (length < size-1) ;
465
0
        length++, p++, q++ )
466
0
    {
467
0
      register const char c = *q;
468
0
      if ((c == '\\') ||
469
0
          (c == '`') ||
470
0
          (c == '"') ||
471
0
          (c == '$'))
472
0
        {
473
0
          if (length+1 >= size-1)
474
0
            break;
475
0
          *p = '\\';
476
0
          p++;
477
0
          length++;
478
0
        }
479
0
      *p = c;
480
0
    }
481
482
0
  dst[length]='\0';
483
484
0
  return length;
485
0
}
486
#endif /* POSIX */
487
488
#if defined(HAVE_SPAWNVP) /* Windows spawnvp() */
489
/*
490
  Escape a dynamically-allocated string argument (if needed),
491
  replacing with a new allocation if escaping was necessary.
492
*/
493
static void
494
WindowsArgumentTextEscape(char **arg)
495
{
496
  const char
497
    *sa;
498
499
  char
500
    *escaped;
501
502
  size_t
503
    e,
504
    i,
505
    length;
506
507
  MagickBool
508
    do_escape=MagickFalse;
509
510
  /*
511
    Compute length, allowing for escape characters.
512
513
    It is possible that other characters should be escaped, but we are
514
    unaware of the specific characters or the correct syntax.  The
515
    characters and syntax might depend on the version of Windows or
516
    the Windows CRT used.
517
  */
518
  e=0;
519
  length=0;
520
  sa=*arg;
521
  for ( i=0; sa[i] != '\0'; i++)
522
    {
523
      if (isspace((int) sa[i]))
524
        {
525
          length += 2;
526
          do_escape=MagickTrue;
527
        }
528
      length++;
529
    }
530
  length++; /* null */
531
  if (do_escape)
532
    {
533
      /*
534
        Allocate buffer
535
      */
536
      escaped=MagickAllocateMemory(char *,length);
537
      /*
538
        Escape into buffer
539
      */
540
      if (escaped != (char *) NULL)
541
        {
542
          sa=*arg;
543
          e=0;
544
          for ( i=0; sa[i] != '\0'; i++)
545
            {
546
              char c=sa[i];
547
              if (isspace((int) c))
548
                {
549
                  escaped[e++]='"';
550
                  escaped[e++]=c;
551
                  escaped[e++]='"';
552
                }
553
              else
554
                {
555
                  escaped[e++]=c;
556
                }
557
            }
558
          escaped[e]='\0';
559
          MagickFreeMemory(*arg);
560
          *arg = escaped;
561
        }
562
    }
563
}
564
#endif /* defined(HAVE_SPAWNVP) */
565
#if defined(MSWINDOWS)
566
/*
567
  Escape characters from the string 'src' to the string 'dst',
568
  limiting the number of output characters according to 'size'.
569
*/
570
static size_t
571
WindowsShellTextEscape(char *dst, const char *src, const size_t size)
572
{
573
  size_t
574
    length=0;
575
576
  char
577
    *p;
578
579
  const char
580
    *q;
581
582
  assert(dst != NULL);
583
  assert(src != (const char *) NULL);
584
  assert(size >= 1);
585
586
587
  /*
588
    Copy src to dst within bounds of size-1, while escaping special
589
    characters.
590
  */
591
  for ( p=dst, q=src, length=0 ;
592
        (*q != 0) && (length < size-1) ;
593
        length++, p++, q++ )
594
    {
595
      register const char c = *q;
596
#if 0
597
      /*
598
        FIXME: Currently the correct implementation is not known so we
599
        don't alter arguments at the moment.
600
      */
601
      if ((c == '\\') ||
602
          (c == '"') ||
603
          (c == '%%'))
604
        {
605
          if (length+1 >= size-1)
606
            break;
607
          *p = '\\';
608
          p++;
609
          length++;
610
        }
611
#endif
612
      *p = c;
613
    }
614
615
  dst[length]='\0';
616
617
  return length;
618
}
619
#endif /* MSWINDOWS */
620
621
MagickExport unsigned int InvokeDelegate(ImageInfo *image_info,Image *image,
622
                                         const char *decode,const char *encode,ExceptionInfo *exception)
623
0
{
624
0
  char
625
0
    *command,
626
0
    **commands,
627
0
    filename[MaxTextExtent];
628
629
0
  const DelegateInfo
630
0
    *delegate_info;
631
632
0
  register long
633
0
    i;
634
635
0
  unsigned int
636
0
    status,
637
0
    temporary_image_filename;
638
639
  /*
640
    Get delegate.
641
  */
642
0
  assert(image_info != (ImageInfo *) NULL);
643
0
  assert(image_info->signature == MagickSignature);
644
0
  assert(image != (Image *) NULL);
645
0
  assert(image->signature == MagickSignature);
646
0
  temporary_image_filename=(*image->filename == '\0');
647
0
  if (temporary_image_filename)
648
0
    {
649
      /* Allocate a temporary filename if image is unnamed.  */
650
0
      if(!AcquireTemporaryFileName(image->filename))
651
0
        {
652
0
          (void) ThrowException(exception,FileOpenError,UnableToCreateTemporaryFile,image->filename);
653
0
          return(False);
654
0
        }
655
0
    }
656
0
  (void) strlcpy(filename,image->filename,MaxTextExtent);
657
0
  delegate_info=GetDelegateInfo(decode,encode,exception);
658
0
  if (delegate_info == (DelegateInfo *) NULL)
659
0
    {
660
0
      if (temporary_image_filename)
661
0
        (void) LiberateTemporaryFile(image->filename);
662
0
      (void) ThrowException(exception,DelegateError,NoTagFound,
663
0
                            decode ? decode : encode);
664
0
      return(False);
665
0
    }
666
667
0
  if (*image_info->filename == '\0')
668
0
    {
669
      /* ReadImage will normally have already set image_info->filename
670
         to the name of a temporary file.  If not, then assign
671
         one. Setting image_info->temporary to True indicates that
672
         there is a temporary file to be removed later.  */
673
0
      if(!AcquireTemporaryFileName(image_info->filename))
674
0
        {
675
0
          if (temporary_image_filename)
676
0
            (void) LiberateTemporaryFile(image->filename);
677
0
          (void) ThrowException(exception,FileOpenError,UnableToCreateTemporaryFile,image_info->filename);
678
0
          return(False);
679
0
        }
680
0
      image_info->temporary=True;
681
0
    }
682
683
0
  if (delegate_info->mode != 0)
684
0
    if ((decode && (delegate_info->encode != (char *) NULL)) ||
685
0
        (encode && (delegate_info->decode != (char *) NULL)))
686
0
      {
687
0
        char
688
0
          decode_filename[MaxTextExtent],
689
0
          *magick;
690
691
0
        ImageInfo
692
0
          *clone_info;
693
694
0
        register Image
695
0
          *p;
696
697
        /*
698
          Delegate requires a particular image format.
699
        */
700
701
0
        if (!AcquireTemporaryFileName(image_info->unique))
702
0
          {
703
0
            if (temporary_image_filename)
704
0
              (void) LiberateTemporaryFile(image->filename);
705
0
            (void) ThrowException(exception,FileOpenError,UnableToCreateTemporaryFile,image_info->unique);
706
0
            return(False);
707
0
          }
708
709
0
        if (!AcquireTemporaryFileName(image_info->zero))
710
0
          {
711
0
            if (temporary_image_filename)
712
0
              (void) LiberateTemporaryFile(image->filename);
713
0
            (void) LiberateTemporaryFile(image_info->unique);
714
0
            (void) ThrowException(exception,FileOpenError,UnableToCreateTemporaryFile,image_info->zero);
715
0
            return(False);
716
0
          }
717
        /* Expand sprintf-style codes in delegate command to command string */
718
0
        magick=TranslateText(image_info,image,decode != (char *) NULL ?
719
0
                             delegate_info->encode : delegate_info->decode);
720
0
        if (magick == (char *) NULL)
721
0
          {
722
0
            (void) LiberateTemporaryFile(image_info->unique);
723
0
            (void) LiberateTemporaryFile(image_info->zero);
724
0
            if (temporary_image_filename)
725
0
              (void) LiberateTemporaryFile(image->filename);
726
0
            (void) ThrowException(exception,DelegateError,DelegateFailed,
727
0
                                  decode ? decode : encode);
728
0
            return(False);
729
0
          }
730
0
        LocaleUpper(magick);
731
0
        clone_info=CloneImageInfo(image_info);
732
0
        (void) strlcpy((char *) clone_info->magick,magick,MaxTextExtent);
733
0
        (void) strlcpy(image->magick,magick,MaxTextExtent);
734
0
        MagickFreeMemory(magick);
735
0
        (void) strlcpy(decode_filename,image->filename,MaxTextExtent);
736
0
        MagickFormatString(clone_info->filename,sizeof(clone_info->filename),"%.1024s:",delegate_info->decode);
737
0
        (void) SetImageInfo(clone_info,SETMAGICK_WRITE,exception);
738
0
        (void) strlcpy(clone_info->filename,image_info->filename,
739
0
                       MaxTextExtent);
740
0
        for (p=image; p != (Image *) NULL; p=p->next)
741
0
          {
742
0
            MagickFormatString(p->filename,sizeof(p->filename),"%.1024s:%.1024s",delegate_info->decode,
743
0
                               decode_filename);
744
0
            status=WriteImage(clone_info,p);
745
0
            if (status == False)
746
0
              {
747
0
                (void) LiberateTemporaryFile(image_info->unique);
748
0
                (void) LiberateTemporaryFile(image_info->zero);
749
0
                if (temporary_image_filename)
750
0
                  (void) LiberateTemporaryFile(image->filename);
751
0
                DestroyImageInfo(clone_info);
752
0
                (void) ThrowException(exception,DelegateError,DelegateFailed,
753
0
                                      decode ? decode : encode);
754
0
                return(False);
755
0
              }
756
0
            if (clone_info->adjoin)
757
0
              break;
758
0
          }
759
0
        (void) LiberateTemporaryFile(image_info->unique);
760
0
        (void) LiberateTemporaryFile(image_info->zero);
761
0
        DestroyImageInfo(clone_info);
762
0
      }
763
  /*
764
    Invoke delegate.
765
  */
766
0
  (void) strlcpy(image->filename,filename,MaxTextExtent);
767
0
  commands=StringToList(delegate_info->commands);
768
0
  if (commands == (char **) NULL)
769
0
    {
770
0
      if (temporary_image_filename)
771
0
        (void) LiberateTemporaryFile(image->filename);
772
0
      (void) ThrowException(exception,ResourceLimitError,MemoryAllocationFailed,decode ? decode : encode);
773
0
      return(False);
774
0
    }
775
0
  command=(char *) NULL;
776
0
  status=True;
777
  /* For each delegate command ... */
778
0
  for (i=0; commands[i] != (char *) NULL; i++)
779
0
    {
780
0
      status=True;
781
      /* Allocate convenience temporary files */
782
0
      if (!AcquireTemporaryFileName(image_info->unique))
783
0
        {
784
0
          (void) ThrowException(exception,FileOpenError,UnableToCreateTemporaryFile,image_info->unique);
785
0
          status=False;
786
0
          goto error_exit;
787
0
        }
788
0
      if (!AcquireTemporaryFileName(image_info->zero))
789
0
        {
790
0
          (void) ThrowException(exception,FileOpenError,UnableToCreateTemporaryFile,image_info->zero);
791
0
          (void) LiberateTemporaryFile(image_info->unique);
792
0
          status=False;
793
0
          goto error_exit;
794
0
        }
795
0
      {
796
0
        MagickBool
797
0
          needs_shell;
798
799
        /*
800
          Check to see if command template must be executed via shell
801
          due to using constructs requiring multiple processes or I/O
802
          redirection.
803
        */
804
0
        needs_shell = MagickFalse;
805
0
        {
806
0
          char *
807
0
            p;
808
809
0
          p = commands[i];
810
0
          for (p = commands[i]; *p; p++)
811
0
            {
812
0
              if (('&' == *p) ||
813
0
                  (';' == *p) ||
814
0
                  ('<' == *p) ||
815
0
                  ('>' == *p) ||
816
0
                  ('|' == *p))
817
0
                {
818
0
                  needs_shell = MagickTrue;
819
0
                  break;
820
0
                }
821
0
            }
822
0
        }
823
824
0
        if (MagickFalse == needs_shell)
825
0
          {
826
0
            int
827
0
              arg_count,
828
0
              j;
829
830
0
            char
831
0
              **arg_array;
832
833
            /*
834
              Convert command template into an argument array.  Translate
835
              each argument array element individually in order to
836
              absolutely avoid any possibility that the number of arguments
837
              may be altered due to substituted data.
838
            */
839
0
            arg_array = StringToArgv(commands[i],&arg_count);
840
0
            for (j = 0; arg_array[j] != (const char*) NULL; j++)
841
0
              {
842
0
                if (strchr(arg_array[j], '%') != (const char*) NULL)
843
0
                  {
844
0
                    char *expanded = TranslateText(image_info,image,arg_array[j]);
845
0
                    if (expanded != (char *) NULL)
846
0
                      {
847
0
                        MagickFreeMemory(arg_array[j]);
848
0
                        arg_array[j] = expanded;
849
0
                      }
850
0
                  }
851
#if defined(HAVE_SPAWNVP)
852
                /*
853
                  Windows _spawnvp() pretends to offer an argv style
854
                  interface but actually splits arguments into
855
                  additional arguments based on white-space.  It might
856
                  have more wonderful properties we are not aware of
857
                  yet.  Escape white-space in arguments with double
858
                  quotes to avoid the splitting.
859
860
                  This code should likely be in MagickSpawnVP() but then
861
                  we would need to clone the input array so it can be
862
                  modified.
863
864
                  This undocumented feature is an example of why
865
                  Microsoft Windows can not be a secure operating
866
                  system.
867
                */
868
                WindowsArgumentTextEscape(&arg_array[j]);
869
#endif
870
0
              }
871
            /*
872
              Execute delegate using our secure "spawn" facility.
873
            */
874
0
            status = MagickSpawnVP(image_info->verbose,arg_array[1],arg_array+1);
875
0
            for (j = 0; arg_array[j] != (const char*) NULL; j++)
876
0
              MagickFreeMemory(arg_array[j]);
877
0
            MagickFreeMemory(arg_array);
878
0
          }
879
0
        else
880
0
          {
881
            /*
882
              Expand sprintf-style codes in delegate command to command
883
              string, escaping replacement text appropriately
884
            */
885
0
            command=TranslateTextEx(image_info,image,commands[i],
886
0
#if defined(POSIX)
887
0
                                    UnixShellTextEscape
888
0
#endif /* POSIX */
889
#if defined(MSWINDOWS)
890
                                    WindowsShellTextEscape
891
#endif /* MSWINDOWS */
892
0
                                    );
893
0
            if (command == (char *) NULL)
894
0
              break;
895
            /*
896
              Execute delegate using command shell.
897
            */
898
0
            status=SystemCommand(image_info->verbose,command);
899
0
          }
900
0
      }
901
0
      MagickFreeMemory(command);
902
      /* Liberate convenience temporary files */
903
0
      (void) LiberateTemporaryFile(image_info->unique);
904
0
      (void) LiberateTemporaryFile(image_info->zero);
905
0
      if (status != False)
906
0
        {
907
0
          (void) ThrowException(exception,DelegateError,DelegateFailed,
908
0
                                commands[i]);
909
0
          goto error_exit;
910
0
        }
911
0
      MagickFreeMemory(commands[i]);
912
0
    }
913
  /*
914
    Free resources.
915
  */
916
0
 error_exit:
917
0
  if (temporary_image_filename)
918
0
    (void) LiberateTemporaryFile(image->filename);
919
0
  for ( ; commands[i] != (char *) NULL; i++)
920
0
    MagickFreeMemory(commands[i]);
921
0
  MagickFreeMemory(commands);
922
0
  return(status != False);
923
0
}
924

925
/*
926
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
927
%                                                                             %
928
%                                                                             %
929
%                                                                             %
930
+   I n v o k e P o s t s c r i p t D e l e g a t e                           %
931
%                                                                             %
932
%                                                                             %
933
%                                                                             %
934
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
935
%
936
%  InvokePostscriptDelegate() executes the postscript interpreter with the
937
%  specified command.
938
%
939
%  The format of the InvokePostscriptDelegate method is:
940
%
941
%      MagickPassFail InvokePostscriptDelegate(const unsigned int verbose,
942
%        const char *command, ExceptionInfo *exception)
943
%
944
%  A description of each parameter follows:
945
%
946
%    o status:  Method InvokePostscriptDelegate returns MagickPass if the command
947
%      is successfully executed, otherwise MagickFail.
948
%
949
%    o verbose: A value other than zero displays the command prior to
950
%      executing it.
951
%
952
%    o command: The address of a character string containing the command to
953
%      execute.  The command is formulated through direct MagickFormatString()
954
%      substitutions rather than using TranslateText.
955
%
956
%
957
*/
958
MagickExport MagickPassFail
959
InvokePostscriptDelegate(const unsigned int verbose,
960
                         const char *command,ExceptionInfo *exception)
961
0
{
962
0
  int
963
0
    status;
964
965
0
#if defined(HasGS)
966
967
0
  register long
968
0
    i;
969
970
0
  char
971
0
    **argv;
972
973
0
  int
974
0
    argc;
975
976
#if (defined(HasGSLIB) || defined(MSWINDOWS))
977
978
  gs_main_instance
979
    *interpreter;
980
981
  int
982
    pexit_code;
983
984
#if defined(MSWINDOWS)
985
  const GhostscriptVectors
986
    *gs_func;
987
988
  gs_func=NTGhostscriptDLLVectors();
989
#elif defined(HasGSLIB)
990
  GhostscriptVectors
991
    gs_func_struct;
992
993
  const GhostscriptVectors
994
    *gs_func;
995
996
  gs_func=(&gs_func_struct);
997
  gs_func_struct.exit=gsapi_exit;
998
  gs_func_struct.init_with_args=gsapi_init_with_args;
999
  gs_func_struct.new_instance=gsapi_new_instance;
1000
  gs_func_struct.run_string=gsapi_run_string;
1001
  gs_func_struct.delete_instance=gsapi_delete_instance;
1002
#endif
1003
  if (gs_func != (GhostscriptVectors *) NULL)
1004
    {
1005
1006
      /*
1007
        Allocate an interpreter.
1008
      */
1009
      interpreter = (gs_main_instance *) NULL;
1010
      status=(gs_func->new_instance)(&interpreter,(void *) NULL);
1011
      if (status < 0)
1012
        {
1013
          ThrowException(exception,DelegateError,
1014
                         FailedToAllocateGhostscriptInterpreter,command);
1015
          return(MagickFail);
1016
        }
1017
      /*
1018
        Initialize interpreter with argument list.
1019
      */
1020
      argv=StringToArgv(command,&argc);
1021
      if (argv == (char **) NULL)
1022
        {
1023
          ThrowException(exception,DelegateError,FailedToAllocateArgumentList,
1024
                         command);
1025
          return(MagickFail);
1026
        }
1027
1028
      if (verbose)
1029
        {
1030
          char
1031
            buffer[MaxTextExtent];
1032
1033
#if defined(MSWINDOWS)
1034
          (void) NTGhostscriptDLL(buffer,sizeof(buffer));
1035
#else
1036
          (void) strlcpy(buffer,"[ghostscript library]",sizeof(buffer));
1037
#endif
1038
          (void) fputs(buffer,stderr);
1039
          for (i=2 ; i < argc ; i++)
1040
            (void) fprintf(stderr," \"%s\"",argv[i]);
1041
          (void) fflush(stderr);
1042
        }
1043
      status=(gs_func->init_with_args)(interpreter,argc-1,argv+1);
1044
      if (status == 0)
1045
        {
1046
          status=(gs_func->run_string)
1047
            (interpreter,"systemdict /start get exec\n",0,&pexit_code);
1048
          if ((status == 0) || (status <= -100))
1049
            {
1050
              char
1051
                reason[MaxTextExtent];
1052
1053
              MagickFormatString(reason,sizeof(reason),"Ghostscript returns status %d, exit code %d",
1054
                                 status,pexit_code);
1055
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),"%s",reason);
1056
              ThrowException(exception,DelegateError,PostscriptDelegateFailed,command);
1057
            }
1058
        }
1059
      /*
1060
        Exit interpreter.
1061
      */
1062
      (gs_func->exit)(interpreter);
1063
      /*
1064
        Deallocate interpreter.
1065
      */
1066
      (gs_func->delete_instance)(interpreter);
1067
      for (i=0; i < argc; i++)
1068
        MagickFreeMemory(argv[i]);
1069
      MagickFreeMemory(argv);
1070
      if ((status == 0) || (status <= -100))
1071
        {
1072
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1073
                                "Returning with failure");
1074
          return(MagickFail);
1075
        }
1076
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1077
                            "Returning with success");
1078
      return(MagickPass);
1079
    }
1080
#endif /* defined(HasGSLIB) || defined(MSWINDOWS) */
1081
1082
0
  status=MagickFail;
1083
0
  {
1084
    /*
1085
      Build Ghostscript command argument list
1086
    */
1087
0
    argv = StringToArgv(command,&argc);
1088
0
    if (argv == (char **) NULL)
1089
0
      {
1090
0
        ThrowException(exception,DelegateError,
1091
0
                       FailedToAllocateArgumentList,
1092
0
                       command);
1093
0
      }
1094
0
    else
1095
0
      {
1096
0
        if (strlen(argv[1]) == 0)
1097
0
          {
1098
            /*
1099
              argv[1] can be empty under Windows due to empty
1100
              command substitution text.
1101
            */
1102
0
            ThrowException(exception,DelegateError,
1103
0
                           FailedToFindGhostscript,
1104
0
                           command);
1105
0
            status=MagickFail;
1106
0
          }
1107
0
        else
1108
0
          {
1109
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1110
0
                                  "Invoking Ghostscript utility command");
1111
0
            if (MagickSpawnVP(verbose,argv[1],argv+1) == 0)
1112
0
              status=MagickPass;
1113
0
          }
1114
0
        for (i=0; i < argc; i++)
1115
0
          MagickFreeMemory(argv[i]);
1116
0
        MagickFreeMemory(argv);
1117
0
      }
1118
0
  }
1119
#else
1120
1121
  /*
1122
    Ghostscript is not supported at all!
1123
  */
1124
  (void) verbose;
1125
  (void) command;
1126
  (void) exception;
1127
1128
  status = MagickFail;
1129
1130
#endif /* if defined(HasGS) */
1131
1132
0
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1133
0
                        "Returning with %s", status == MagickFail ?
1134
0
                        "failure" : "success");
1135
1136
0
  return status;
1137
0
}
1138

1139
/*
1140
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1141
%                                                                             %
1142
%                                                                             %
1143
%                                                                             %
1144
%  L i s t D e l e g a t e I n f o                                            %
1145
%                                                                             %
1146
%                                                                             %
1147
%                                                                             %
1148
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1149
%
1150
%  Method ListDelegateInfo lists the image formats to a file.
1151
%
1152
%  The format of the ListDelegateInfo method is:
1153
%
1154
%      unsigned int ListDelegateInfo(FILE *file,ExceptionInfo *exception)
1155
%
1156
%  A description of each parameter follows.
1157
%
1158
%    o file:  An pointer to a FILE.
1159
%
1160
%    o exception: Return any errors or warnings in this structure.
1161
%
1162
%
1163
*/
1164
MagickExport unsigned int ListDelegateInfo(FILE *file,ExceptionInfo *exception)
1165
0
{
1166
0
  char
1167
0
    **commands,
1168
0
    delegate[MaxTextExtent];
1169
1170
0
  register long
1171
0
    i;
1172
1173
0
  register const DelegateInfo
1174
0
    *p;
1175
1176
0
  if (file == (const FILE *) NULL)
1177
0
    file=stdout;
1178
0
  (void) GetDelegateInfo("*","*",exception);
1179
0
  LockSemaphoreInfo(delegate_semaphore);
1180
0
  for (p=delegate_list; p != (const DelegateInfo *) NULL; p=p->next)
1181
0
  {
1182
0
    if ((p->previous == (DelegateInfo *) NULL) ||
1183
0
        (LocaleCompare(p->path,p->previous->path) != 0))
1184
0
      {
1185
0
        if (p->previous != (DelegateInfo *) NULL)
1186
0
          (void) fprintf(file,"\n");
1187
0
        if (p->path != (char *) NULL)
1188
0
          (void) fprintf(file,"Path: %.1024s\n\n",p->path);
1189
0
        (void) fprintf(file,"Delegate             Command\n");
1190
0
        (void) fprintf(file,"-------------------------------------------------"
1191
0
          "------------------------------\n");
1192
0
      }
1193
0
    if (p->stealth)
1194
0
      continue;
1195
0
    *delegate='\0';
1196
0
    if (p->encode != (char *) NULL)
1197
0
      (void) strlcpy(delegate,p->encode,sizeof(delegate));
1198
0
    (void) strlcat(delegate,"        ",sizeof(delegate));
1199
0
    delegate[8]='\0';
1200
0
    commands=StringToList(p->commands);
1201
0
    if (commands == (char **) NULL)
1202
0
      continue;
1203
0
    {
1204
0
          size_t
1205
0
        command_length,
1206
0
         length=0;
1207
1208
0
      int
1209
0
        command_start_column,
1210
0
        formatted_chars=0,
1211
0
        screen_width=79,
1212
0
        strip_length;
1213
1214
0
      char
1215
0
        *s;
1216
1217
      /* Format output so that command spans multiple lines if
1218
         necessary */
1219
0
      {
1220
0
        const char * const columns_env = getenv("COLUMNS");
1221
0
        if (columns_env)
1222
0
          screen_width=MagickAtoI(columns_env)-1;
1223
0
      }
1224
0
      command_length=strlen(commands[0]);
1225
0
      command_start_column=fprintf(file,"%8s%c=%c%s  ",p->decode ? p->decode : "",
1226
0
        p->mode <= 0 ? '<' : ' ',p->mode >= 0 ? '>' : ' ',delegate);
1227
0
      for (s=commands[0]; length < command_length; s+=formatted_chars)
1228
0
        {
1229
0
          if (s != commands[0])
1230
0
            (void) fprintf(file,"%*s",command_start_column,"");
1231
0
          strip_length=screen_width-command_start_column;
1232
0
          if (length+strip_length < command_length)
1233
0
            {
1234
0
              char
1235
0
                *e;
1236
1237
0
              for(e=s+strip_length; (*e != ' ') && (e > s) ; e--);
1238
0
              strip_length=e-s;
1239
0
            }
1240
0
          formatted_chars=fprintf(file,"%.*s",strip_length,s);
1241
0
          length+=formatted_chars;
1242
0
          (void) fprintf(file,"\n");
1243
0
          if (formatted_chars <= 0)
1244
0
            break;
1245
0
        }
1246
0
    }
1247
0
    for (i=0; commands[i] != (char *) NULL; i++)
1248
0
      MagickFreeMemory(commands[i]);
1249
0
    MagickFreeMemory(commands);
1250
0
  }
1251
0
  (void) fflush(file);
1252
0
  UnlockSemaphoreInfo(delegate_semaphore);
1253
0
  return(True);
1254
0
}
1255

1256
/*
1257
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1258
%                                                                             %
1259
%                                                                             %
1260
%                                                                             %
1261
+   R e a d C o n f i g u r e F i l e                                         %
1262
%                                                                             %
1263
%                                                                             %
1264
%                                                                             %
1265
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1266
%
1267
%  Method ReadConfigureFile reads the delegate configuration file which maps
1268
%  delegate invocation strings to a particular image format.
1269
%
1270
%  The format of the ReadConfigureFile method is:
1271
%
1272
%      unsigned int ReadConfigureFile(const char *basename,
1273
%        const unsigned long depth,ExceptionInfo *exception)
1274
%
1275
%  A description of each parameter follows:
1276
%
1277
%    o status: Method ReadConfigureFile returns True if a matching
1278
%        entry is found, otherwise False.
1279
%
1280
%    o basename:  The color configuration filename.
1281
%
1282
%    o depth: depth of <include /> statements.
1283
%
1284
%    o exception: Return any errors or warnings in this structure.
1285
%
1286
%
1287
*/
1288
#if defined(MSWINDOWS)
1289
static void CatDelegatePath(char *path,
1290
                            const char *binpath,
1291
                            const char *command)
1292
{
1293
  strlcpy(path,binpath,MaxTextExtent);
1294
  strlcat(path,command,MaxTextExtent);
1295
  if (IsAccessibleNoLogging(path))
1296
    return;
1297
1298
  strlcpy(path,command,MaxTextExtent);
1299
  return;
1300
}
1301
#endif /* defined(MSWINDOWS) */
1302
static unsigned int ReadConfigureFile(const char *basename,
1303
  const unsigned long depth,ExceptionInfo *exception)
1304
20
{
1305
20
  char
1306
20
    keyword[MaxTextExtent],
1307
20
    path[MaxTextExtent],
1308
20
    *q,
1309
20
    *token,
1310
20
    *xml;
1311
1312
20
  size_t
1313
20
    length,
1314
20
    token_max_length;
1315
1316
  /*
1317
    Read the delegates configure file.
1318
  */
1319
20
  (void) strlcpy(path,basename,sizeof(path));
1320
20
  if (depth == 0)
1321
20
    xml=(char *) GetConfigureBlob(basename,path,&length,exception);
1322
0
  else
1323
0
    xml=(char *) FileToBlob(basename,&length,exception);
1324
20
  if (xml == (char *) NULL)
1325
20
    xml=AllocateString(DelegateMap);
1326
20
  token=AllocateString(xml);
1327
20
  token_max_length=strlen(token);
1328
220
  for (q=xml; *q != '\0'; )
1329
200
    {
1330
      /*
1331
        Interpret XML.
1332
      */
1333
200
      MagickGetToken(q,&q,token,token_max_length);
1334
200
      if (*token == '\0')
1335
0
        break;
1336
200
      (void) strlcpy(keyword,token,MaxTextExtent);
1337
200
      if (LocaleNCompare(keyword,"<!--",4) == 0)
1338
0
        {
1339
          /*
1340
            Comment element.
1341
          */
1342
0
          while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
1343
0
            MagickGetToken(q,&q,token,token_max_length);
1344
0
          continue;
1345
0
        }
1346
200
      if (LocaleCompare(keyword,"<include") == 0)
1347
0
        {
1348
          /*
1349
            Include element.
1350
          */
1351
0
          while ((*token != '>') && (*q != '\0'))
1352
0
            {
1353
0
              (void) strlcpy(keyword,token,MaxTextExtent);
1354
0
              MagickGetToken(q,&q,token,token_max_length);
1355
0
              if (*token != '=')
1356
0
                continue;
1357
0
              MagickGetToken(q,&q,token,token_max_length);
1358
0
              if (LocaleCompare(keyword,"file") == 0)
1359
0
                {
1360
0
                  if (depth > 200)
1361
0
                    ThrowException(exception,ConfigureError,IncludeElementNestedTooDeeply,path);
1362
0
                  else
1363
0
                    {
1364
0
                      char
1365
0
                        filename[MaxTextExtent];
1366
1367
0
                      GetPathComponent(path,HeadPath,filename);
1368
0
                      if (*filename != '\0')
1369
0
                        (void) strlcat(filename,DirectorySeparator,MaxTextExtent);
1370
0
                      (void) strlcat(filename,token,MaxTextExtent);
1371
0
                      (void) ReadConfigureFile(filename,depth+1,exception);
1372
0
                    }
1373
0
                  if (delegate_list != (DelegateInfo *) NULL)
1374
0
                    while (delegate_list->next != (DelegateInfo *) NULL)
1375
0
                      delegate_list=delegate_list->next;
1376
0
                }
1377
0
            }
1378
0
          continue;
1379
0
        }
1380
200
      if (LocaleCompare(keyword,"<delegate") == 0)
1381
20
        {
1382
20
          DelegateInfo
1383
20
            *delegate_info;
1384
1385
          /*
1386
            Allocate memory for the delegate list.
1387
          */
1388
20
          delegate_info=MagickAllocateMemory(DelegateInfo *,sizeof(DelegateInfo));
1389
20
          if (delegate_info == (DelegateInfo *) NULL)
1390
0
            MagickFatalError3(ResourceLimitFatalError,MemoryAllocationFailed,
1391
20
                             UnableToAllocateDelegateInfo);
1392
20
          (void) memset(delegate_info,0,sizeof(DelegateInfo));
1393
20
          delegate_info->path=AcquireString(path);
1394
20
          delegate_info->signature=MagickSignature;
1395
20
          if (delegate_list == (DelegateInfo *) NULL)
1396
20
            {
1397
20
              delegate_list=delegate_info;
1398
20
              continue;
1399
20
            }
1400
0
          delegate_list->next=delegate_info;
1401
0
          delegate_info->previous=delegate_list;
1402
0
          delegate_list=delegate_list->next;
1403
0
          continue;
1404
20
        }
1405
180
      if (delegate_list == (DelegateInfo *) NULL)
1406
140
        continue;
1407
40
      MagickGetToken(q,(char **) NULL,token,token_max_length);
1408
40
      if (*token != '=')
1409
20
        continue;
1410
20
      MagickGetToken(q,&q,token,token_max_length);
1411
20
      MagickGetToken(q,&q,token,token_max_length);
1412
20
      switch (*keyword)
1413
20
        {
1414
0
        case 'C':
1415
0
        case 'c':
1416
0
          {
1417
0
            if (LocaleCompare((char *) keyword,"command") == 0)
1418
0
              {
1419
0
                delegate_list->commands=AllocateString(token);
1420
                /*
1421
                  Support XML predefined entities substitutions.
1422
1423
                  FIXME: Support XML character reference syntax and
1424
                  provide more optimized support for XML predefined
1425
                  entities substitutions.
1426
                 */
1427
0
                if (strchr(delegate_list->commands,'&') != (char *) NULL)
1428
0
                  {
1429
0
                    SubstituteString((char **) &delegate_list->commands,"&lt;","<");
1430
0
                    SubstituteString((char **) &delegate_list->commands,"&gt;",">");
1431
0
                    SubstituteString((char **) &delegate_list->commands,"&apos;","'");
1432
0
                    SubstituteString((char **) &delegate_list->commands,"&quot;","\"");
1433
0
                    SubstituteString((char **) &delegate_list->commands,"&amp;","&");
1434
0
                  }
1435
#if defined(MSWINDOWS)
1436
                if (strchr(delegate_list->commands,'@') != (char *) NULL)
1437
                  {
1438
                    char
1439
                      BinPath[MaxTextExtent],
1440
                      path[MaxTextExtent];
1441
1442
                    BinPath[0]=0;
1443
#if defined(HasGS)
1444
                    /* Substitute @PSDelegate@ with path to Ghostscript */
1445
                    NTGhostscriptEXE(path,MaxTextExtent-1);
1446
                    SubstituteString((char **) &delegate_list->commands,
1447
                                     "@PSDelegate@",path);
1448
#endif /* if defined(HasGS) */
1449
1450
# if defined(UseInstalledMagick)
1451
#  if defined(MagickBinPath)
1452
                    strlcpy(BinPath,MagickBinPath,sizeof(BinPath));
1453
#  else
1454
                    {
1455
                      char
1456
                        *key,
1457
                        *key_value;
1458
1459
                      /* Obtain installation path from registry */
1460
                      key="BinPath";
1461
                      key_value=NTRegistryKeyLookup(key);
1462
                      if (!key_value)
1463
                        {
1464
                          ThrowException(exception,ConfigureError,
1465
                              RegistryKeyLookupFailed,key);
1466
                        }
1467
                      else
1468
                        {
1469
                          strlcpy(BinPath,key_value,sizeof(BinPath));
1470
                          MagickFreeMemory(key_value);
1471
                        }
1472
                    }
1473
#  endif /* defined(MagickBinPath) */
1474
# else
1475
                    /* Base path off of client path */
1476
                    strlcpy(BinPath,SetClientPath(NULL),sizeof(BinPath));
1477
# endif /* defined(UseInstalledMagick) */
1478
                    if ((BinPath[0] != 0) &&
1479
                        (BinPath[strlen(BinPath)-1] != *DirectorySeparator))
1480
                      strlcat(BinPath,DirectorySeparator,sizeof(BinPath));
1481
1482
                    /* Substitute @GMDelegate@ with path to gm.exe */
1483
                    CatDelegatePath(path,BinPath,"gm.exe");
1484
                    SubstituteString((char **) &delegate_list->commands,
1485
                                     "@GMDelegate@",path);
1486
1487
                    /* Substitute @GMDisplayDelegate@ with path to
1488
                       gmdisplay.exe */
1489
                    CatDelegatePath(path,BinPath,"gmdisplay.exe");
1490
                    SubstituteString((char **) &delegate_list->commands,
1491
                                     "@GMDisplayDelegate@",path);
1492
1493
                    /* Substitute @MPEGDecodeDelegate@ with path to
1494
                       mpeg2dec.exe */
1495
                    CatDelegatePath(path,BinPath,"mpeg2dec.exe");
1496
                    SubstituteString((char **) &delegate_list->commands,
1497
                                     "@MPEGDecodeDelegate@",path);
1498
1499
                    /* Substitute @MPEGEncodeDelegate@ with path to
1500
                       mpeg2enc.exe */
1501
                    CatDelegatePath(path,BinPath,"mpeg2enc.exe");
1502
                    SubstituteString((char **) &delegate_list->commands,
1503
                                     "@MPEGEncodeDelegate@",path);
1504
1505
                    /* Substitute @HPGLDecodeDelegate@ with path to
1506
                       hp2xx.exe */
1507
                    CatDelegatePath(path,BinPath,"hp2xx.exe");
1508
                    SubstituteString((char **) &delegate_list->commands,
1509
                                     "@HPGLDecodeDelegate@",path);
1510
                  }
1511
#endif /* defined(MSWINDOWS) */
1512
0
              } /* LocaleCompare */
1513
0
            break;
1514
0
          }
1515
0
        case 'D':
1516
0
        case 'd':
1517
0
          {
1518
0
            if (LocaleCompare((char *) keyword,"decode") == 0)
1519
0
              {
1520
0
                delegate_list->decode=AcquireString(token);
1521
0
                delegate_list->mode=1;
1522
0
                break;
1523
0
              }
1524
0
            break;
1525
0
          }
1526
0
        case 'E':
1527
0
        case 'e':
1528
0
          {
1529
0
            if (LocaleCompare((char *) keyword,"encode") == 0)
1530
0
              {
1531
0
                delegate_list->encode=AcquireString(token);
1532
0
                delegate_list->mode=(-1);
1533
0
                break;
1534
0
              }
1535
0
            break;
1536
0
          }
1537
0
        case 'M':
1538
0
        case 'm':
1539
0
          {
1540
0
            if (LocaleCompare((char *) keyword,"mode") == 0)
1541
0
              {
1542
0
                delegate_list->mode=1;
1543
0
                if (LocaleCompare(token,"bi") == 0)
1544
0
                  delegate_list->mode=0;
1545
0
                else
1546
0
                  if (LocaleCompare(token,"encode") == 0)
1547
0
                    delegate_list->mode=(-1);
1548
0
                break;
1549
0
              }
1550
0
            break;
1551
0
          }
1552
0
        case 'S':
1553
20
        case 's':
1554
20
          {
1555
20
            if (LocaleCompare((char *) keyword,"stealth") == 0)
1556
20
              {
1557
20
                delegate_list->stealth=LocaleCompare(token,"True") == 0;
1558
20
                break;
1559
20
              }
1560
0
            break;
1561
20
          }
1562
0
        default:
1563
0
          break;
1564
20
        }
1565
20
    }
1566
20
  MagickFreeMemory(token);
1567
20
  MagickFreeMemory(xml);
1568
20
  if (delegate_list == (DelegateInfo *) NULL)
1569
0
    return(False);
1570
20
  while (delegate_list->previous != (DelegateInfo *) NULL)
1571
0
    delegate_list=delegate_list->previous;
1572
20
  return(True);
1573
20
}
1574

1575
/*
1576
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1577
%                                                                             %
1578
%                                                                             %
1579
%                                                                             %
1580
%   S e t D e l e g a t e I n f o                                             %
1581
%                                                                             %
1582
%                                                                             %
1583
%                                                                             %
1584
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1585
%
1586
%  Method SetDelegateInfo adds or replaces a delegate in the delegate list and
1587
%  returns the address of the first delegate.  If the delegate is NULL, just
1588
%  the address of the first delegate is returned.
1589
%
1590
%  The format of the SetDelegateInfo method is:
1591
%
1592
%      DelegateInfo *SetDelegateInfo(DelegateInfo *delegate_info)
1593
%
1594
%  A description of each parameter follows:
1595
%
1596
%    o delegate_info: Method SetDelegateInfo returns the address of the
1597
%      first delegate in the delegates list.
1598
%
1599
%    o delegate_info:  A structure of type DelegateInfo.  This information
1600
%      is added to the end of the delegates linked-list.
1601
%
1602
%
1603
*/
1604
MagickExport DelegateInfo *SetDelegateInfo(DelegateInfo *delegate_info)
1605
0
{
1606
0
  register DelegateInfo
1607
0
    *p;
1608
1609
0
  DelegateInfo
1610
0
    *delegate;
1611
1612
  /*
1613
    Initialize new delegate.
1614
  */
1615
0
  assert(delegate_info != (DelegateInfo *) NULL);
1616
0
  assert(delegate_info->signature == MagickSignature);
1617
0
  delegate=MagickAllocateMemory(DelegateInfo *,sizeof(DelegateInfo));
1618
0
  if (delegate == (DelegateInfo *) NULL)
1619
0
    return((DelegateInfo *) delegate_list);
1620
0
  delegate->decode=AcquireString(delegate_info->decode);
1621
0
  delegate->encode=AcquireString(delegate_info->encode);
1622
0
  delegate->mode=delegate_info->mode;
1623
0
  delegate->commands=(char *) NULL;
1624
0
  if (delegate_info->commands != (char *) NULL)
1625
0
    delegate->commands=AllocateString(delegate_info->commands);
1626
0
  delegate->previous=(DelegateInfo *) NULL;
1627
0
  delegate->next=(DelegateInfo *) NULL;
1628
0
  if (delegate_list == (DelegateInfo *) NULL)
1629
0
    {
1630
0
      delegate_list=delegate;
1631
0
      return((DelegateInfo *) delegate_list);
1632
0
    }
1633
0
  for (p=delegate_list; p != (DelegateInfo *) NULL; p=p->next)
1634
0
  {
1635
0
    if ((LocaleCompare(p->decode,delegate_info->decode) == 0) &&
1636
0
        (LocaleCompare(p->encode,delegate_info->encode) == 0) &&
1637
0
        (p->mode == delegate_info->mode))
1638
0
      {
1639
        /*
1640
          Delegate overrides an existing one with the same tags.
1641
        */
1642
0
        MagickFreeMemory(p->commands);
1643
0
        p->commands=delegate->commands;
1644
0
        MagickFreeMemory(delegate);
1645
0
        return((DelegateInfo *) delegate_list);
1646
0
      }
1647
0
    if (p->next == (DelegateInfo *) NULL)
1648
0
      break;
1649
0
  }
1650
  /*
1651
    Place new delegate at the end of the delegate list.
1652
  */
1653
0
  delegate->previous=p;
1654
0
  p->next=delegate;
1655
0
  return((DelegateInfo *) delegate_list);
1656
0
}