Coverage Report

Created: 2026-06-16 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/graphicsmagick/magick/utility.c
Line
Count
Source
1
/*
2
% Copyright (C) 2003-2026 GraphicsMagick Group
3
% Copyright (c) 2000 Markus Friedl.  All rights reserved.
4
% Copyright (C) 2002 ImageMagick Studio
5
% Copyright 1991-1999 E. I. du Pont de Nemours and Company
6
%
7
% This program is covered by multiple licenses, which are described in
8
% Copyright.txt. You should have received a copy of Copyright.txt with this
9
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
10
%
11
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
12
%                                                                             %
13
%                                                                             %
14
%                                                                             %
15
%             U   U  TTTTT  IIIII  L      IIIII  TTTTT  Y   Y                 %
16
%             U   U    T      I    L        I      T     Y Y                  %
17
%             U   U    T      I    L        I      T      Y                   %
18
%             U   U    T      I    L        I      T      Y                   %
19
%              UUU     T    IIIII  LLLLL  IIIII    T      Y                   %
20
%                                                                             %
21
%                                                                             %
22
%                     GraphicsMagick Utility Methods                          %
23
%                                                                             %
24
%                                                                             %
25
%                             Software Design                                 %
26
%                               John Cristy                                   %
27
%                              January 1993                                   %
28
%                                                                             %
29
%                                                                             %
30
%                                                                             %
31
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
32
%
33
%
34
*/
35

36
/*
37
  Include declarations.
38
*/
39
#include "magick/studio.h"
40
#include "magick/analyze.h"
41
#include "magick/attribute.h"
42
#include "magick/blob.h"
43
#include "magick/color.h"
44
#include "magick/confirm_access.h"
45
#include "magick/enum_strings.h"
46
#include "magick/log.h"
47
#include "magick/magick.h"
48
#include "magick/pixel_cache.h"
49
#include "magick/random.h"
50
#include "magick/signature.h"
51
#include "magick/tempfile.h"
52
#include "magick/utility.h"
53
54
#if defined(HAVE_MACH_O_DYLD_H)
55
/* Needed for _NSGetExecutablePath */
56
# include <mach-o/dyld.h>
57
#endif
58
59
#if defined(HAVE_SPAWNVP) && defined(HAVE_PROCESS_H)
60
#  include <process.h>
61
#endif
62
63
/*
64
  Static declarations.
65
*/
66
static const char
67
  Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
68
69
static const unsigned char
70
  AsciiMap[] =
71
  {
72
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
73
    0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
74
    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
75
    0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
76
    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
77
    0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
78
    0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73,
79
    0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
80
    0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
81
    0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
82
    0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
83
    0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
84
    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
85
    0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
86
    0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,
87
    0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
88
    0xc0, 0xe1, 0xe2, 0xe3, 0xe4, 0xc5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb,
89
    0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
90
    0xf8, 0xf9, 0xfa, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3,
91
    0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
92
    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb,
93
    0xfc, 0xfd, 0xfe, 0xff,
94
  };
95

96
/*
97
  Forward declaration.
98
*/
99
static int
100
  IsDirectory(const char *);
101
102
static int
103
  MagickStrToD(const char *start,char **end,double *value);
104
105
static MagickPassFail
106
  MagickStrToInt64(const char *start,char **end,magick_int64_t *value);
107

108
/*
109
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
110
%                                                                             %
111
%                                                                             %
112
%                                                                             %
113
%   A c q u i r e S t r i n g                                                 %
114
%                                                                             %
115
%                                                                             %
116
%                                                                             %
117
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
118
%
119
%  AcquireString() allocates memory for a string and copies the source string
120
%  to that memory location (and returns it). This method is best used to
121
%  allocate constant strings since only enough memory to support the data
122
%  is allocated.
123
%
124
%  The format of the AcquireString method is:
125
%
126
%      char *AcquireString(const char *source)
127
%
128
%  A description of each parameter follows:
129
%
130
%    o allocated_string:  Method AcquireString returns a copy of the source
131
%      string.
132
%
133
%    o source: A character string.
134
%
135
%
136
*/
137
MagickExport char *AcquireString(const char *source)
138
38.1M
{
139
38.1M
  char
140
38.1M
    *destination;
141
142
38.1M
  size_t
143
38.1M
    length;
144
145
38.1M
  assert(source != (const char *) NULL);
146
38.1M
  length=strlen(source);
147
38.1M
  destination=MagickAllocateMemory(char *,length+1);
148
38.1M
  if (destination == (char *) NULL)
149
0
    MagickFatalError3(ResourceLimitFatalError,MemoryAllocationFailed,
150
38.1M
      UnableToAllocateString);
151
38.1M
  if (length != 0)
152
34.1M
    (void) memcpy(destination,source,length);
153
38.1M
  destination[length]='\0';
154
38.1M
  return(destination);
155
38.1M
}
156

157
/*
158
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
159
%                                                                             %
160
%                                                                             %
161
%                                                                             %
162
%   A l l o c a t e S t r i n g                                               %
163
%                                                                             %
164
%                                                                             %
165
%                                                                             %
166
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
167
%
168
%  AllocateString() allocates memory for a string and copies the source string
169
%  to that memory location (and returns it). Additional memory is allocated
170
%  so that subsequent concatenations to the string are most efficient.
171
%
172
%  The format of the AllocateString method is:
173
%
174
%      char *AllocateString(const char *source)
175
%
176
%  A description of each parameter follows:
177
%
178
%    o allocated_string:  Method AllocateString returns a copy of the source
179
%      string.
180
%
181
%    o source: A character string.
182
%
183
%
184
*/
185
MagickExport char *AllocateString(const char *source)
186
4.89M
{
187
4.89M
  char
188
4.89M
    *destination;
189
190
4.89M
  size_t
191
4.89M
    allocation_length,
192
4.89M
    source_length;
193
194
4.89M
  allocation_length=MaxTextExtent;
195
4.89M
  source_length=0;
196
4.89M
  if (source != (char *) NULL)
197
4.89M
    {
198
4.89M
      source_length=strlen(source);
199
4.89M
      allocation_length=source_length+1;
200
4.89M
      MagickRoundUpStringLength(allocation_length);
201
4.89M
    }
202
4.89M
  destination=MagickAllocateMemory(char *,allocation_length);
203
4.89M
  if (destination == (char *) NULL)
204
0
    MagickFatalError3(ResourceLimitFatalError,MemoryAllocationFailed,
205
4.89M
      UnableToAllocateString);
206
4.89M
  if (source_length != 0)
207
4.37M
    (void) memcpy(destination,source,source_length);
208
4.89M
  destination[source_length]='\0';
209
4.89M
  return(destination);
210
4.89M
}
211

212
/*
213
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
214
%                                                                             %
215
%                                                                             %
216
%                                                                             %
217
%  A p p e n d I m a g e F o r m a t                                          %
218
%                                                                             %
219
%                                                                             %
220
%                                                                             %
221
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
222
%
223
%  AppendImageFormat() appends the image format type to the filename.  If an
224
%  extension to the file already exists, it is first removed.
225
%
226
%  The format of the AppendImageFormat method is:
227
%
228
%      void AppendImageFormat(const char *format,char *filename)
229
%
230
%  A description of each parameter follows.
231
%
232
%   o  format:  Specifies a pointer to an array of characters.  This is the
233
%      format of the image.
234
%
235
%   o  filename:  Specifies a pointer to an array of characters.  The unique
236
%      file name is returned in this array.
237
%
238
%
239
*/
240
MagickExport void AppendImageFormat(const char *format,char *filename)
241
60.1k
{
242
60.1k
  char
243
60.1k
    root[MaxTextExtent];
244
245
60.1k
  assert(format != (char *) NULL);
246
60.1k
  assert(filename != (char *) NULL);
247
60.1k
  if ((*format == '\0') || (*filename == '\0'))
248
0
    return;
249
60.1k
  if (LocaleCompare(filename,"-") == 0)
250
0
    {
251
0
      char
252
0
        message[MaxTextExtent];
253
254
0
      MagickFormatString(message,sizeof(message),"%.1024s:%.1024s",format,filename);
255
0
      (void) strlcpy(filename,message,MaxTextExtent);
256
0
      return;
257
0
    }
258
60.1k
  GetPathComponent(filename,RootPath,root);
259
60.1k
  MagickFormatString(filename,MaxTextExtent,"%.1024s.%.1024s",root,format);
260
60.1k
}
261

262
/*
263
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
264
%                                                                             %
265
%                                                                             %
266
%                                                                             %
267
%   B a s e 6 4 D e c o d e                                                   %
268
%                                                                             %
269
%                                                                             %
270
%                                                                             %
271
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
272
%
273
%  Base64Decode() decodes Base64-encoded text and returns its binary
274
%  equivalent.  NULL is returned if the text is not valid base64 data, or a
275
%  memory allocation failure occurs.
276
%
277
%  Contributed by Bob Friesenhahn.
278
%
279
%  The format of the Base64Decode method is:
280
%
281
%      unsigned char *Base64Decode(const char *source,length_t *length)
282
%
283
%  A description of each parameter follows:
284
%
285
%    o source:  A pointer to a Base64-encoded string.
286
%
287
%    o length: The number of bytes decoded.
288
%
289
*/
290
MagickExport unsigned char *Base64Decode(const char *source,size_t *length)
291
32.0k
{
292
32.0k
  int
293
32.0k
    state;
294
295
32.0k
  register const char
296
32.0k
    *p,
297
32.0k
    *q;
298
299
32.0k
  register size_t
300
32.0k
    i;
301
302
32.0k
  size_t
303
32.0k
    max_length;
304
305
32.0k
  unsigned char
306
32.0k
    *decode;
307
308
32.0k
  assert(source != (char *) NULL);
309
32.0k
  assert(length != (size_t *) NULL);
310
32.0k
  *length=0;
311
32.0k
  max_length=3*strlen(source)/4+1;
312
32.0k
  decode=MagickAllocateMemory(unsigned char *,max_length);
313
32.0k
  if (decode == (unsigned char *) NULL)
314
0
    return((unsigned char *) NULL);
315
32.0k
  i=0;
316
32.0k
  state=0;
317
46.9M
  for (p=source; *p != '\0'; p++)
318
46.9M
  {
319
46.9M
    if (isspace((int)(unsigned char) *p))
320
800k
      continue;
321
46.1M
    if (*p == '=')
322
1.34k
      break;
323
46.1M
    q=strchr(Base64,*p);
324
46.1M
    if (q == (char *) NULL)
325
100
      {
326
100
        MagickFreeMemory(decode);
327
100
        return((unsigned char *) NULL);  /* non-base64 character */
328
100
      }
329
46.1M
    switch (state)
330
46.1M
    {
331
11.5M
      case 0:
332
11.5M
      {
333
11.5M
        decode[i]=(q-Base64) << 2;
334
11.5M
        state++;
335
11.5M
        break;
336
0
      }
337
11.5M
      case 1:
338
11.5M
      {
339
11.5M
        decode[i++]|=(q-Base64) >> 4;
340
11.5M
        decode[i]=((q-Base64) & 0x0f) << 4;
341
11.5M
        state++;
342
11.5M
        break;
343
0
      }
344
11.5M
      case 2:
345
11.5M
      {
346
11.5M
        decode[i++]|=(q-Base64) >> 2;
347
11.5M
        decode[i]=((q-Base64) & 0x03) << 6;
348
11.5M
        state++;
349
11.5M
        break;
350
0
      }
351
11.5M
      case 3:
352
11.5M
      {
353
11.5M
        decode[i++]|=(q-Base64);
354
11.5M
        state=0;
355
11.5M
        break;
356
0
      }
357
46.1M
    }
358
46.1M
  }
359
  /*
360
    Verify Base-64 string has proper terminal characters.
361
  */
362
31.9k
  if (*p != '=')
363
30.5k
    {
364
30.5k
      if (state != 0)
365
55
        {
366
55
          MagickFreeMemory(decode);
367
55
          return((unsigned char *) NULL);
368
55
        }
369
30.5k
    }
370
1.34k
  else
371
1.34k
    {
372
1.34k
      p++;
373
1.34k
      switch (state)
374
1.34k
      {
375
4
        case 0:
376
9
        case 1:
377
9
        {
378
          /*
379
            Unrecognized '=' character.
380
          */
381
9
          MagickFreeMemory(decode);
382
9
          return((unsigned char *) NULL);
383
4
        }
384
704
        case 2:
385
704
        {
386
1.01k
          for ( ; *p != '\0'; p++)
387
1.01k
            if (!isspace((int)(unsigned char)*p))
388
699
              break;
389
704
          if (*p != '=')
390
23
            {
391
23
              MagickFreeMemory(decode);
392
23
              return((unsigned char *) NULL);
393
23
            }
394
681
          p++;
395
681
          break;
396
704
        }
397
635
        case 3:
398
635
        {
399
893
          for ( ; *p != '\0'; p++)
400
273
            if (!isspace((int)(unsigned char) *p))
401
15
              {
402
15
                MagickFreeMemory(decode);
403
15
                return((unsigned char *) NULL);
404
15
              }
405
620
          if (decode[i] != 0)
406
5
            {
407
5
              MagickFreeMemory(decode);
408
5
              return((unsigned char *) NULL);
409
5
            }
410
615
          break;
411
620
        }
412
1.34k
      }
413
1.34k
    }
414
31.7k
  *length=i;
415
31.7k
  assert(*length < max_length);
416
31.7k
  return(decode);
417
31.7k
}
418

419
/*
420
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
421
%                                                                             %
422
%                                                                             %
423
%                                                                             %
424
%   B a s e 6 4 E n c o d e                                                   %
425
%                                                                             %
426
%                                                                             %
427
%                                                                             %
428
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
429
%
430
%  Base64Encode() encodes arbitrary binary data to base64 encoded format as
431
%  described by the "Base64 Content-Transfer-Encoding" section of RFC 2045 and
432
%  returns the result as a null-terminated ASCII string.  NULL is returned if
433
%  a memory allocation failure occurs.
434
%
435
%  Contributed by Bob Friesenhahn.
436
%
437
%  The format of the Base64Encode method is:
438
%
439
%      char *Base64Encode(const unsigned char *blob,const size_t blob_length,
440
%        size_t *encode_length)
441
%
442
%  A description of each parameter follows:
443
%
444
%    o blob:           A pointer to binary data to encode.
445
%
446
%    o blob_length:    The number of bytes to encode.
447
%
448
%    o encode_length:  The number of bytes encoded.
449
%
450
*/
451
49.5M
#define Index64(index) ((index) & 0x3f)
452
MagickExport char *Base64Encode(const unsigned char *blob,
453
  const size_t blob_length,size_t *encode_length)
454
2.56k
{
455
2.56k
  char
456
2.56k
    *encode;
457
458
2.56k
  register const unsigned char
459
2.56k
    *p;
460
461
2.56k
  register size_t
462
2.56k
    i;
463
464
2.56k
  size_t
465
2.56k
    max_length,
466
2.56k
    remaining;
467
468
2.56k
  assert(blob != (const unsigned char *) NULL);
469
2.56k
  assert(blob_length != 0);
470
2.56k
  assert(encode_length != (size_t *) NULL);
471
2.56k
  *encode_length=0;
472
2.56k
  max_length=MagickArraySize(4U,blob_length)/3U;
473
2.56k
  if (max_length)
474
2.56k
    max_length += 4U;
475
2.56k
  encode=MagickAllocateMemory(char *,max_length);
476
2.56k
  if (encode == (char *) NULL)
477
0
    return((char *) NULL);
478
2.56k
  i=0;
479
12.3M
  for (p=blob; p < (blob+blob_length-2); p+=3)
480
12.3M
  {
481
12.3M
    encode[i++]=Base64[Index64(*p >> 2)];
482
12.3M
    encode[i++]=Base64[Index64(((*p & 0x03) << 4)+(*(p+1) >> 4))];
483
12.3M
    encode[i++]=Base64[Index64(((*(p+1) & 0x0f) << 2)+(*(p+2) >> 6))];
484
12.3M
    encode[i++]=Base64[Index64(*(p+2))];
485
12.3M
  }
486
2.56k
  remaining=blob_length % 3;
487
2.56k
  if (remaining != 0)
488
1.83k
    {
489
1.83k
      long
490
1.83k
        j;
491
492
1.83k
      unsigned char
493
1.83k
        code[3];
494
495
1.83k
      code[0]='\0';
496
1.83k
      code[1]='\0';
497
1.83k
      code[2]='\0';
498
4.69k
      for (j=0; j < (long) remaining; j++)
499
2.85k
        code[j]=(*p++);
500
1.83k
      encode[i++]=Base64[Index64(code[0] >> 2)];
501
1.83k
      encode[i++]=Base64[Index64(((code[0] & 0x03) << 4)+(code[1] >> 4))];
502
1.83k
      if (remaining == 1)
503
821
        encode[i++]='=';
504
1.01k
      else
505
1.01k
        encode[i++]=Base64[Index64(((code[1] & 0x0f) << 2)+(code[2] >> 6))];
506
1.83k
      encode[i++]='=';
507
1.83k
    }
508
2.56k
  *encode_length=i;
509
2.56k
  encode[i++]='\0';
510
2.56k
  assert(i <= max_length);
511
2.56k
  return(encode);
512
2.56k
}
513

514
/*
515
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
516
%                                                                             %
517
%                                                                             %
518
%                                                                             %
519
%   C l o n e S t r i n g                                                     %
520
%                                                                             %
521
%                                                                             %
522
%                                                                             %
523
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
524
%
525
%  Method CloneString allocates memory for the destination string and copies
526
%  the source string to that memory location.
527
%
528
%  The format of the CloneString method is:
529
%
530
%      MagickPassFail CloneString(char **destination,const char *source)
531
%
532
%  A description of each parameter follows:
533
%
534
%    o status:  Method CloneString returns MagickPass if the string is cloned,
535
%      otherwise MagickFail is returned.
536
%
537
%    o destination:  A pointer to a character string.
538
%
539
%    o source: A character string.
540
%
541
%
542
*/
543
MagickExport MagickPassFail CloneString(char **destination,const char *source)
544
553k
{
545
553k
  size_t
546
553k
    allocation_length,
547
553k
    string_length;
548
549
553k
  assert(destination != (char **) NULL);
550
553k
  if (source == (const char *) NULL)
551
0
    {
552
0
      MagickFreeMemory(*destination);
553
0
      return(MagickPass);
554
0
    }
555
553k
  string_length=strlen(source);
556
553k
  allocation_length=string_length+1;
557
553k
  MagickRoundUpStringLength(allocation_length);
558
553k
  MagickReallocMemory(char *,*destination,allocation_length);
559
553k
  if (*destination == (char *) NULL)
560
0
    MagickFatalError3(ResourceLimitFatalError,MemoryAllocationFailed,
561
553k
      UnableToAllocateString);
562
553k
  if (0 != string_length)
563
515k
    (void) memcpy(*destination,source,string_length);
564
553k
  (*destination)[string_length]='\0';
565
553k
  return(MagickPass);
566
553k
}
567

568
/*
569
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
570
%                                                                             %
571
%                                                                             %
572
%                                                                             %
573
%   C o n c a t e n a t e S t r i n g                                         %
574
%                                                                             %
575
%                                                                             %
576
%                                                                             %
577
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
578
%
579
%  Method ConcatenateString appends a copy of string source, including
580
%  the terminating null character, to the end of string destination.
581
%
582
%  The format of the ConcatenateString method is:
583
%
584
%      MagickPassFail ConcatenateString(char **destination,const char *source)
585
%
586
%  A description of each parameter follows:
587
%
588
%    o status:  Method ConcatenateString returns MagickPass if the string is cloned,
589
%      otherwise MagickFail is returned.
590
%
591
%    o destination:  A pointer to a character string.
592
%
593
%    o source: A character string.
594
%
595
%
596
*/
597
MagickExport MagickPassFail ConcatenateString(char **destination,
598
  const char *source)
599
494k
{
600
494k
  size_t
601
494k
    allocation_length,
602
494k
    destination_length=0,
603
494k
    source_length;
604
605
494k
  assert(destination != (char **) NULL);
606
494k
  if (source == (const char *) NULL)
607
0
    return(MagickPass);
608
494k
  source_length=strlen(source);
609
494k
  if (*destination != (char *) NULL)
610
69.0k
    destination_length=strlen(*destination);
611
494k
  allocation_length=destination_length+source_length+1;
612
494k
  MagickRoundUpStringLength(allocation_length);
613
494k
  MagickReallocMemory(char *,(*destination),allocation_length);
614
494k
  if (*destination == (char *) NULL)
615
0
    MagickFatalError3(ResourceLimitFatalError,MemoryAllocationFailed,
616
494k
      UnableToConcatenateString);
617
494k
  if (0 != source_length)
618
494k
    (void) memcpy(&(*destination)[destination_length],source,source_length);
619
494k
  (*destination)[destination_length+source_length]='\0';
620
494k
  return(MagickPass);
621
494k
}
622

623
/*
624
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
625
%                                                                             %
626
%                                                                             %
627
%                                                                             %
628
%   D e f i n e C l i e n t N a m e                                           %
629
%                                                                             %
630
%                                                                             %
631
%                                                                             %
632
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
633
%
634
%  DefineClientName() this is a helper function that parses the passed string
635
%    in order to define the name of the client application.
636
%
637
%  The format of the DefineClientName method is:
638
%
639
%      void DefineClientName(const char *path)
640
%
641
%  A description of each parameter follows:
642
%
643
%    o path: A string that can also be a full path that contains the name of
644
%            application
645
%
646
*/
647
MagickExport void DefineClientName(const char *path)
648
254
{
649
254
  if ((path != (char *) NULL) && (*path != '\0'))
650
254
    {
651
254
      char
652
254
        component[MaxTextExtent];
653
654
254
      GetPathComponent(path,BasePath,component);
655
254
      (void) SetClientName(component);
656
254
    }
657
254
}
658

659
/*
660
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
661
%                                                                             %
662
%                                                                             %
663
%                                                                             %
664
%   D e f i n e C l i e n t P a t h A n d N a m e                             %
665
%                                                                             %
666
%                                                                             %
667
%                                                                             %
668
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
669
%
670
%  DefineClientPathAndName() this is a helper function that parses the passed
671
%  string in order to define several global settings related to the location of
672
%  the application. It sets the path, the filename, and the display name of the
673
%  client application based on the input string which is assumed to be the full
674
%  and valid path to the client.
675
%
676
%  The format of the DefineClientPathAndName method is:
677
%
678
%      void DefineClientPathAndName(const char *path)
679
%
680
%  A description of each parameter follows:
681
%
682
%    o path: A string that must be a full path that contains the name of
683
%            application
684
%
685
*/
686
MagickExport void DefineClientPathAndName(const char *path)
687
254
{
688
254
  if ((path != (char *) NULL) && (*path != '\0'))
689
254
    {
690
254
      char
691
254
        component[MaxTextExtent];
692
693
      /* This is the path only - including the parent folder */
694
254
      GetPathComponent(path,HeadPath,component);
695
254
      (void) SetClientPath(component);
696
      /* This is the file name AND the extension - of present */
697
254
      GetPathComponent(path,TailPath,component);
698
254
      (void) SetClientFilename(component);
699
      /* The last step is to define a human readable name for
700
         the help and error logging systems. */
701
254
      DefineClientName(component);
702
254
    }
703
254
}
704

705
/*
706
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
707
%                                                                             %
708
%                                                                             %
709
%                                                                             %
710
%   E s c a p e S t r i n g                                                   %
711
%                                                                             %
712
%                                                                             %
713
%                                                                             %
714
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
715
%
716
%  EscapeString() allocates memory for a backslash-escaped version of a
717
%  source text string, copies the escaped version of the text to that
718
%  memory location while adding backslash characters, and returns the
719
%  escaped string.
720
%
721
%  The format of the EscapeString method is:
722
%
723
%      char *EscapeString(const char *source,const char escape)
724
%
725
%  A description of each parameter follows:
726
%
727
%    o allocated_string:  Method EscapeString returns the escaped string.
728
%
729
%    o source: A character string.
730
%
731
%    o escape: The quoted string termination character to escape (e.g. '"').
732
%
733
*/
734
MagickExport char *EscapeString(const char *source,const char escape)
735
37.8k
{
736
37.8k
  char
737
37.8k
    *destination;
738
739
37.8k
  register char
740
37.8k
    *q;
741
742
37.8k
  register const char
743
37.8k
    *p;
744
745
37.8k
  size_t
746
37.8k
    length;
747
748
37.8k
  assert(source != (const char *) NULL);
749
750
  /*
751
    Use dry-run method to compute required string length.
752
  */
753
37.8k
  length=0;
754
62.0M
  for (p=source; *p; p++)
755
61.9M
    {
756
61.9M
      if ((*p == '\\') || (*p == escape))
757
149k
        length++;
758
61.9M
      length++;
759
61.9M
    }
760
37.8k
  destination=MagickAllocateMemory(char *,length+1);
761
37.8k
  if (destination == (char *) NULL)
762
0
    MagickFatalError3(ResourceLimitFatalError,MemoryAllocationFailed,
763
37.8k
      UnableToEscapeString);
764
37.8k
  *destination='\0';
765
37.8k
  q=destination;
766
62.0M
  for (p=source; *p; p++)
767
61.9M
    {
768
61.9M
      if ((*p == '\\') || (*p == escape))
769
149k
        *q++= '\\';
770
61.9M
      *q++=(*p);
771
61.9M
    }
772
37.8k
  *q=0;
773
37.8k
  return(destination);
774
37.8k
}
775

776
/*
777
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
778
%                                                                             %
779
%                                                                             %
780
%                                                                             %
781
%   E x p a n d F i l e n a m e                                               %
782
%                                                                             %
783
%                                                                             %
784
%                                                                             %
785
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
786
%
787
%  Method ExpandFilename expands '~' in a filename.
788
%
789
%  The format of the ExpandFilename function is:
790
%
791
%      ExpandFilename(char *filename)
792
%
793
%  A description of each parameter follows:
794
%
795
%    o filename: Specifies a pointer to a character array that contains the
796
%      filename.
797
%
798
%
799
*/
800
MagickExport void ExpandFilename(char *filename)
801
0
{
802
0
  char
803
0
    expanded_filename[MaxTextExtent];
804
805
0
  register char
806
0
    *p;
807
808
0
  if (filename == (char *) NULL)
809
0
    return;
810
0
  if (*filename != '~')
811
0
    return;
812
0
  (void) strlcpy(expanded_filename,filename,MaxTextExtent);
813
0
  if (*(filename+1) == '/')
814
0
    {
815
      /*
816
        Substitute ~ with $HOME.
817
      */
818
0
      p=(char *) getenv("HOME");
819
0
      if (p == (char *) NULL)
820
0
        p=(char *) ".";
821
0
      (void) strlcpy(expanded_filename,p,MaxTextExtent);
822
0
      (void) strlcat(expanded_filename,filename+1,MaxTextExtent);
823
0
    }
824
0
  else
825
0
    {
826
0
#if defined(POSIX)
827
0
      char
828
0
        username[MaxTextExtent];
829
830
0
#  if defined(HAVE_GETPWNAM_R)
831
0
      struct  passwd
832
0
        pwd;
833
834
0
      long
835
0
        pwnam_buf_len_s;
836
837
0
      size_t
838
0
        pwnam_buf_len;
839
840
0
      char
841
0
        *pwnam_buf = (char *) NULL;
842
0
#  endif /* if defined(HAVE_GETPWNAM_R) */
843
844
0
      struct passwd
845
0
        *entry;
846
847
      /*
848
        Substitute ~ with home directory from password file.
849
      */
850
0
      (void) strlcpy(username,filename+1,MaxTextExtent);
851
0
      p=strchr(username,'/');
852
0
      if (p != (char *) NULL)
853
0
        *p='\0';
854
855
0
#  if defined(HAVE_GETPWNAM_R)
856
0
      entry=(struct passwd *) NULL;
857
0
      errno = 0;
858
0
      pwnam_buf_len_s = sysconf(_SC_GETPW_R_SIZE_MAX);
859
0
      if (pwnam_buf_len_s <= 0)
860
0
        return;
861
0
      pwnam_buf_len = (size_t) pwnam_buf_len_s;
862
0
      pwnam_buf=MagickAllocateMemory(char *,pwnam_buf_len);
863
0
      if (pwnam_buf != (char *) NULL)
864
0
        (void) getpwnam_r(username,&pwd,pwnam_buf,pwnam_buf_len,&entry);
865
#else
866
      entry=getpwnam(username); /* Thread-unsafe version */
867
#  endif /* if defined(HAVE_GETPWNAM_R) */
868
0
      if (entry != (struct passwd *) NULL)
869
0
        {
870
0
          (void) strncpy(expanded_filename,entry->pw_dir,MaxTextExtent-1);
871
0
          if (p != (char *) NULL)
872
0
            {
873
0
              (void) strlcat(expanded_filename,"/",sizeof(expanded_filename));
874
0
              (void) strlcat(expanded_filename,p+1,sizeof(expanded_filename));
875
0
            }
876
0
        }
877
0
#  if defined(HAVE_GETPWNAM_R)
878
0
      MagickFreeMemory(pwnam_buf);
879
0
#  endif /* if defined(HAVE_GETPWNAM_R) */
880
0
#endif
881
0
    }
882
0
  (void) strlcpy(filename,expanded_filename,MaxTextExtent);
883
0
}
884

885
/*
886
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
887
%                                                                             %
888
%                                                                             %
889
%                                                                             %
890
%   E x p a n d F i l e n a m e s                                             %
891
%                                                                             %
892
%                                                                             %
893
%                                                                             %
894
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
895
%
896
%  Method ExpandFilenames checks each argument of the command line vector and
897
%  expands it if they have a wildcard character.  For example, *.jpg might
898
%  expand to:  bird.jpg rose.jpg tiki.jpg.
899
%
900
%  The format of the ExpandFilenames function is:
901
%
902
%      status=ExpandFilenames(int *argc,char ***argv)
903
%
904
%  A description of each parameter follows:
905
%
906
%    o argc: Specifies a pointer to an integer describing the number of
907
%      elements in the argument vector.
908
%
909
%    o argv: Specifies a pointer to a text array containing the command line
910
%      arguments.  The existing argument list is replaced.
911
%
912
%
913
*/
914
MagickExport MagickPassFail ExpandFilenames(int *argc,char ***argv)
915
24
{
916
24
  const
917
24
    size_t prealloc_entries = 1024;
918
919
24
  char
920
24
    current_directory[MaxTextExtent],
921
24
    *option,
922
24
    **vector;
923
924
24
  long
925
24
    count,
926
24
    number_files;
927
928
24
  register long
929
24
    i,
930
24
    j;
931
932
24
  MagickBool
933
24
    first;
934
935
  /*
936
    Allocate argument vector.
937
  */
938
24
  assert(argc != (int *) NULL);
939
24
  assert(argv != (char ***) NULL);
940
24
  vector=MagickAllocateMemory(char **,(*argc+prealloc_entries)*sizeof(char *));
941
24
  if (vector == (char **) NULL)
942
0
    return(MagickFail);
943
  /*
944
    Expand any wildcard filenames.
945
  */
946
24
  current_directory[0]='\0';
947
24
  count=0;
948
48
  for (i=0; i < *argc; i++)
949
24
    {
950
24
      char
951
24
        **filelist,
952
24
        filename[MaxTextExtent],
953
24
        magick[MaxTextExtent],
954
24
        path[MaxTextExtent],
955
24
        subimage[MaxTextExtent];
956
957
24
      option=(*argv)[i];
958
      /* Never throw options away, so copy here, then perhaps modify later */
959
24
      vector[count++]=AcquireString(option);
960
961
      /*
962
        Don't expand or process any VID: argument since the VID coder
963
        does its own expansion
964
      */
965
24
      if (LocaleNCompare("VID:",option,4) == 0)
966
0
        continue;
967
968
      /*
969
        Don't attempt to expand the argument to these options.
970
      */
971
24
      if ((LocaleNCompare("+define",option,7) == 0) ||
972
24
          (LocaleNCompare("+profile",option,8) == 0) ||
973
24
          (LocaleNCompare("-comment",option,8) == 0) ||
974
24
          (LocaleNCompare("-convolve",option,9) == 0) ||
975
24
          (LocaleNCompare("-draw",option,5) == 0) ||
976
24
          (LocaleNCompare("-font",option,5) == 0) ||
977
24
          (LocaleNCompare("-format",option,7) == 0) ||
978
24
          (LocaleNCompare("-label",option,6) == 0))
979
0
        {
980
0
          i++;
981
0
          if (i == *argc)
982
0
            continue;
983
0
          option=(*argv)[i];
984
0
          vector[count++]=AcquireString(option);
985
0
          continue;
986
0
        }
987
988
      /* Pass quotes through to the command-line parser */
989
24
      if ((*option == '"') || (*option == '\''))
990
0
        continue;
991
992
      /*
993
        Expand @filename to a list of arguments.
994
      */
995
24
      j=0;
996
24
      if ((option[0] == '@') && (!IsAccessibleNoLogging(option)))
997
0
        {
998
0
          FILE
999
0
            *file;
1000
1001
0
          file=fopen(option+1,"r");
1002
0
          if (file != (FILE *) NULL)
1003
0
            {
1004
1005
0
              first=MagickTrue;
1006
0
              number_files=0;
1007
0
              while (fgets(filename,sizeof(filename),file) != (char *) NULL)
1008
0
                {
1009
0
                  for (j=0; filename[j] != '\0'; j++)
1010
0
                    if (filename[j] == '\n')
1011
0
                      filename[j] = '\0';
1012
1013
0
                  if (filename[0] != '\0')
1014
0
                    {
1015
0
                      if ((number_files % prealloc_entries) == 0)
1016
0
                        {
1017
0
                          char **new_vector;
1018
0
                          new_vector=
1019
0
                            (char **) MagickRealloc(vector,
1020
0
                                                    MagickArraySize((size_t) *argc+count+prealloc_entries,
1021
0
                                                                    sizeof(char *)));
1022
0
                          if (new_vector == (char **) NULL)
1023
0
                            {
1024
0
                              for (j=0 ; j < count; j++)
1025
0
                                MagickFreeMemory(vector[j]);
1026
0
                              MagickFreeMemory(vector);
1027
0
                              fclose(file);
1028
0
                              return(MagickFail);
1029
0
                            }
1030
0
                          vector = new_vector;
1031
0
                        }
1032
1033
0
                      if (first)
1034
0
                        {
1035
                          /* Deallocate original option assigned above */
1036
0
                          --count;
1037
0
                          MagickFreeMemory(vector[count]);
1038
0
                          first=MagickFalse;
1039
0
                        }
1040
0
                      number_files++;
1041
0
                      vector[count++]=AcquireString(filename);
1042
0
                    }
1043
0
                }
1044
1045
0
              fclose(file);
1046
0
            }
1047
0
        }
1048
1049
      /*
1050
         Fast cycle options that are not expandable filename patterns.
1051
         ListFiles only expands patterns in the filename.  We also check
1052
         if the full option resolves to a file since ListFiles() obtains
1053
         a list of all the files in the directory and is thus very slow
1054
         if there are thousands of files.
1055
      */
1056
24
      GetPathComponent(option,TailPath,filename);
1057
24
      if ((!IsGlob(filename)) || IsAccessibleNoLogging(option))
1058
24
        continue;
1059
1060
      /* Chop the option to get its other filename components. */
1061
0
      GetPathComponent(option,MagickPath,magick);
1062
0
      GetPathComponent(option,HeadPath,path);
1063
0
      GetPathComponent(option,SubImagePath,subimage);
1064
1065
      /* GetPathComponent throws away the colon */
1066
0
      if (*magick != '\0')
1067
0
        (void) strlcat(magick,":",sizeof(magick));
1068
0
      ExpandFilename(path);
1069
1070
0
      if ('\0' == current_directory[0])
1071
0
        if (getcwd(current_directory,MaxTextExtent-1) == NULL)
1072
0
          MagickFatalError(ConfigureFatalError,UnableToGetCurrentDirectory,
1073
0
                           NULL);
1074
1075
      /* Get the list of matching file names. */
1076
0
      filelist=ListFiles(*path=='\0' ? current_directory : path,
1077
0
                         filename,&number_files);
1078
1079
0
      if (filelist != (char **) NULL)
1080
0
        for (j=0; j < number_files; j++)
1081
0
          if (IsDirectory(filelist[j]) <= 0)
1082
0
            break;
1083
1084
      /* ListFiles() may change current directory without restoring. */
1085
0
      if ((strlen(current_directory) > 0) && (chdir(current_directory) != 0))
1086
0
        {
1087
0
          if (filelist != (char **) NULL)
1088
0
            {
1089
0
              for (j=0; j < number_files; j++)
1090
0
                MagickFreeMemory(filelist[j]);
1091
0
              MagickFreeMemory(filelist);
1092
0
            }
1093
0
          MagickFatalError(ConfigureFatalError,UnableToRestoreCurrentDirectory,
1094
0
                           NULL);
1095
0
        }
1096
1097
0
      if (filelist == 0)
1098
0
        continue;
1099
1100
0
      if (j == number_files)
1101
0
        {
1102
          /*
1103
            Bourne/Bash shells passes through unchanged any glob patterns
1104
            not matching anything (abc* and there's no file starting with
1105
            abc). Do the same for behaviour consistent with that.
1106
          */
1107
0
          if (filelist != (char **) NULL)
1108
0
            {
1109
0
              for (j=0; j < number_files; j++)
1110
0
                MagickFreeMemory(filelist[j]);
1111
0
              MagickFreeMemory(filelist);
1112
0
            }
1113
0
          continue;
1114
0
        }
1115
1116
      /*
1117
        There's at least one matching filename.
1118
        Transfer file list to argument vector.
1119
      */
1120
0
      {
1121
0
         char **new_vector;
1122
0
         new_vector =
1123
0
           (char **) MagickRealloc(vector,
1124
0
                                   MagickArraySize((size_t) *argc+count+number_files+prealloc_entries,
1125
0
                                                   sizeof(char *)));
1126
0
         if (new_vector == (char **) NULL)
1127
0
           {
1128
0
             for (j=0 ; j < count; j++)
1129
0
               MagickFreeMemory(vector[j]);
1130
0
             MagickFreeMemory(vector);
1131
0
             if (filelist != (char **) NULL)
1132
0
               {
1133
0
                 for (j=0; j < number_files; j++)
1134
0
                   MagickFreeMemory(filelist[j]);
1135
0
                 MagickFreeMemory(filelist);
1136
0
               }
1137
0
             return(MagickFail);
1138
0
           }
1139
0
         vector=new_vector;
1140
0
      }
1141
1142
0
      first=MagickTrue;
1143
0
      for (j=0; j < number_files; j++)
1144
0
        {
1145
0
          char
1146
0
            filename_buffer[MaxTextExtent];
1147
1148
0
          if (filelist[j] == (const char *) NULL)
1149
0
            continue;
1150
0
          filename_buffer[0]='\0';
1151
0
          if (strlcat(filename_buffer,path,sizeof(filename_buffer))
1152
0
              >= sizeof(filename_buffer))
1153
0
            MagickFatalError2(ResourceLimitFatalError,"Path buffer overflow",
1154
0
                              filename_buffer);
1155
0
          if (*path != '\0')
1156
0
            {
1157
0
              if (strlcat(filename_buffer,DirectorySeparator,sizeof(filename_buffer))
1158
0
                  >= sizeof(filename_buffer))
1159
0
                MagickFatalError2(ResourceLimitFatalError,"Path buffer overflow",
1160
0
                                  filename_buffer);
1161
0
            }
1162
0
          if (strlcat(filename_buffer,filelist[j],sizeof(filename_buffer))
1163
0
              >= sizeof(filename_buffer))
1164
0
            MagickFatalError2(ResourceLimitFatalError,"Path buffer overflow",
1165
0
                              filename_buffer);
1166
          /* If it's a filename (not a directory) ... */
1167
0
          if (IsDirectory(filename_buffer) == 0)
1168
0
            {
1169
0
              char
1170
0
                formatted_buffer[MaxTextExtent];
1171
1172
0
              *formatted_buffer='\0';
1173
0
              if (strlcat(formatted_buffer,magick,sizeof(formatted_buffer))
1174
0
                  >= sizeof(formatted_buffer))
1175
0
                MagickFatalError2(ResourceLimitFatalError,"Path buffer overflow",
1176
0
                                  formatted_buffer);
1177
0
              if (strlcat(formatted_buffer,filename_buffer,sizeof(formatted_buffer))
1178
0
                  >= sizeof(formatted_buffer))
1179
0
                MagickFatalError2(ResourceLimitFatalError,"Path buffer overflow",
1180
0
                                  formatted_buffer);
1181
0
              if (strlcat(formatted_buffer,subimage,sizeof(formatted_buffer))
1182
0
                  >= sizeof(formatted_buffer))
1183
0
                MagickFatalError2(ResourceLimitFatalError,"Path buffer overflow",
1184
0
                                  formatted_buffer);
1185
0
              if (first)
1186
0
                {
1187
                  /* Deallocate original option assigned above */
1188
0
                  --count;
1189
0
                  MagickFreeMemory(vector[count]);
1190
0
                  first=MagickFalse;
1191
0
                }
1192
0
              vector[count++]=AcquireString(formatted_buffer);
1193
0
            }
1194
0
          MagickFreeMemory(filelist[j]);
1195
0
        }
1196
0
      MagickFreeMemory(filelist);
1197
0
    }
1198
24
  *argc=count;
1199
24
  *argv=vector;
1200
24
  return(MagickPass);
1201
24
}
1202

1203
/*
1204
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1205
%                                                                             %
1206
%                                                                             %
1207
%                                                                             %
1208
%  F o r m a t S i z e                                                        %
1209
%                                                                             %
1210
%                                                                             %
1211
%                                                                             %
1212
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1213
%
1214
%  FormatSize() converts a size to a human readable format, for example,
1215
%  14kb, 234mb, 2.7gb, or 3.0tb.  Scaling is done by repetitively dividing by
1216
%  1024.
1217
%
1218
%  The format of the FormatSize method is:
1219
%
1220
%      char *FormatSize(const magick_int64_t size,char *format)
1221
%
1222
%  A description of each parameter follows:
1223
%
1224
%    o size:  convert this size to a human readable format.
1225
%
1226
%    o format:  human readable format.
1227
%
1228
%
1229
*/
1230
MagickExport void FormatSize(const magick_int64_t size,char *format)
1231
1.20M
{
1232
1.20M
  double
1233
1.20M
    length;
1234
1235
1.20M
  register unsigned int
1236
1.20M
    i;
1237
1238
1.20M
  length=size;
1239
1.66M
  for (i=0; length > 1024; i++)
1240
459k
    length/=1024.0;
1241
1.20M
  if (i > 0)
1242
385k
    MagickFormatString(format,MaxTextExtent,"%.1f",length);
1243
824k
  else
1244
824k
    MagickFormatString(format,MaxTextExtent,"%.0f",length);
1245
1.20M
  switch (i)
1246
1.20M
    {
1247
0
    default: break;
1248
824k
    case 0: break;
1249
319k
    case 1: (void) strlcat(format,"Ki",MaxTextExtent); break; /* kilo, 10^3 */
1250
57.9k
    case 2: (void) strlcat(format,"Mi",MaxTextExtent); break; /* mega, 10^6 */
1251
7.83k
    case 3: (void) strlcat(format,"Gi",MaxTextExtent); break; /* giga, 10^9 */
1252
0
    case 4: (void) strlcat(format,"Ti",MaxTextExtent); break; /* tera, 10^12 */
1253
0
    case 5: (void) strlcat(format,"Pi",MaxTextExtent); break; /* peta, 10^15 */
1254
0
    case 6: (void) strlcat(format,"Ei",MaxTextExtent); break; /* exa,  10^18 */
1255
1.20M
    }
1256
1.20M
}
1257

1258
/*
1259
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1260
%                                                                             %
1261
%                                                                             %
1262
%                                                                             %
1263
%  F o r m a t S t r i n g                                                    %
1264
%                                                                             %
1265
%                                                                             %
1266
%                                                                             %
1267
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1268
%
1269
%  Method FormatString prints formatted output of a variable argument list
1270
%  buffer, limiting its output to MaxTextExtent.
1271
%  The formatted size (as would be returned by strlen()) is returned.
1272
%
1273
%  The format of the FormatString method is:
1274
%
1275
%      size_t FormatString(char *string,const char *format,...)
1276
%
1277
%  A description of each parameter follows.
1278
%
1279
%   o  string:  Method FormatString returns the formatted string in this
1280
%      character buffer. Buffer must be at least MaxTextExtent characters
1281
%      in size.
1282
%
1283
%   o  format:  A string describing the format to use to write the remaining
1284
%      arguments.
1285
%
1286
%
1287
*/
1288
MagickExport size_t FormatStringList(char *string,const char *format,
1289
                                     va_list operands)
1290
0
{
1291
0
  size_t
1292
0
    fls = 0;
1293
1294
0
  int
1295
0
    fli;
1296
1297
0
#if defined(HAVE_VSNPRINTF)
1298
0
  fli=vsnprintf(string,MaxTextExtent,format,operands);
1299
#else
1300
  fli=vsprintf(string,format,operands);
1301
#endif
1302
0
  if (fli >= MaxTextExtent)
1303
0
    fls=MaxTextExtent-1;
1304
0
  else if (fli > 0)
1305
0
    fls=(size_t) fli;
1306
0
  return fls;
1307
0
}
1308
MagickExport size_t FormatString(char *string,const char *format,...)
1309
0
{
1310
0
  va_list
1311
0
    operands;
1312
1313
0
  size_t
1314
0
    formatted_len;
1315
1316
0
  va_start(operands,format);
1317
0
  formatted_len=MagickFormatStringList(string, MaxTextExtent, format, operands);
1318
0
  va_end(operands);
1319
0
  return formatted_len;
1320
0
}
1321

1322
/*
1323
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1324
%                                                                             %
1325
%                                                                             %
1326
%                                                                             %
1327
%   G e t E x e c u t i o n P a t h                                           %
1328
%                                                                             %
1329
%                                                                             %
1330
%                                                                             %
1331
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1332
%
1333
%  GetExecutionPath() returns the pathname of the executable that started
1334
%  the process. The user-supplied buffer must be at least MaxTextExtent
1335
%  bytes long.  On success True is returned, otherwise False.
1336
%
1337
%  The format of the GetExecutionPath method is:
1338
%
1339
%      unsigned int GetExecutionPath(char *path)
1340
%
1341
%  A description of each parameter follows:
1342
%
1343
%    o path: The pathname of the executable that started the process.
1344
%
1345
*/
1346
MagickExport MagickPassFail GetExecutionPath(char *path)
1347
0
{
1348
0
  *path='\0';
1349
#if defined(MSWINDOWS)
1350
  /*
1351
    Microsoft Windows provides an means to obtain the path to the
1352
    currently executing executable or DLL.
1353
  */
1354
  return(NTGetExecutionPath(path));
1355
#endif
1356
#if defined(HAVE_GETEXECNAME)
1357
  {
1358
    /*
1359
      Sun's Solaris provides a getexecname() for obtaining the path to
1360
      this executable.
1361
    */
1362
    const char
1363
      *execution_path;
1364
1365
    execution_path=(const char *) getexecname();
1366
    if (execution_path != (const char *) NULL)
1367
      {
1368
        if (*execution_path != *DirectorySeparator)
1369
          {
1370
            if (getcwd(path,MaxTextExtent-1) == NULL)
1371
              MagickFatalError(ConfigureFatalError,UnableToGetCurrentDirectory,
1372
                               NULL);
1373
            (void) strlcat(path,"/",MaxTextExtent);
1374
          }
1375
        (void) strlcat(path,execution_path,MaxTextExtent);
1376
        if (IsAccessible(path))
1377
          return(MagickPass);
1378
      }
1379
  }
1380
#endif
1381
#if defined(HAVE__NSGETEXECUTABLEPATH) && defined(HAVE_REALPATH)
1382
  {
1383
    /*
1384
      Apple OS-X provides a _NSGetExecutablePath function for
1385
      obtaining the path to the executable.  The returned path may be
1386
      a symbolic link to the actual executable so use realpath() to
1387
      resolve the real path.  It is claimed that _NSGetExecutablePath
1388
      could possibly return a path longer than MAXPATHLEN.  Inspection
1389
      of <sys/param.h> on an OS-X system reveals that MAXPATHLEN is
1390
      defined to be PATH_MAX. So we will provide for PATH_MAX*2.
1391
    */
1392
    uint32_t
1393
      bufsize;
1394
1395
    char
1396
      executable_path[PATH_MAX*2],
1397
      real_path[PATH_MAX+1];
1398
1399
    bufsize=sizeof(executable_path);
1400
    if (_NSGetExecutablePath(executable_path,&bufsize) == 0)
1401
      if (realpath(executable_path,real_path) != NULL)
1402
        if (strlcpy(path,real_path,MaxTextExtent) < MaxTextExtent)
1403
          if (IsAccessible(path))
1404
            return(MagickPass);
1405
  }
1406
#endif
1407
0
#if defined(HAVE_GETPID) && defined(HAVE_READLINK)
1408
0
  {
1409
    /*
1410
      On Linux, the symbolic link "/proc/PID/exe" (where 'PID' is the
1411
      integer process ID) points to the physical executable.  FreeBSD
1412
      is similar except that the link path is "/proc/PID/file".  Maybe
1413
      some other systems use compatible schemes.
1414
    */
1415
0
    int
1416
0
      length;
1417
1418
0
    long
1419
0
      pid;
1420
1421
0
    char
1422
0
      link_path[MaxTextExtent],
1423
0
      real_path[PATH_MAX+1];
1424
1425
0
    pid=(long) getpid();
1426
    /* Linux format */
1427
0
    MagickFormatString(link_path,sizeof(link_path),"/proc/%ld/exe",pid);
1428
0
    length=readlink(link_path, real_path, PATH_MAX);
1429
0
    if (length == -1)
1430
0
      {
1431
        /* Try FreeBSD format */
1432
0
        MagickFormatString(link_path,sizeof(link_path),"/proc/%ld/file",pid);
1433
0
        length=readlink(link_path, real_path, PATH_MAX);
1434
0
      }
1435
0
    if ((length > 0) && (length <= PATH_MAX))
1436
0
      {
1437
0
        real_path[length]=0;
1438
0
        if (strlcpy(path,real_path,MaxTextExtent) < MaxTextExtent)
1439
0
          if (IsAccessible(path))
1440
0
            return(MagickPass);
1441
0
      }
1442
0
  }
1443
0
#endif
1444
0
  return(MagickFail);
1445
0
}
1446

1447
/*
1448
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1449
%                                                                             %
1450
%                                                                             %
1451
%                                                                             %
1452
%   G e t E x e c u t i o n P a t h U s i n g N a m e                         %
1453
%                                                                             %
1454
%                                                                             %
1455
%                                                                             %
1456
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1457
%
1458
%  GetExecutionPathUsingName() replaces the provided path with the full
1459
%  path to the directory containing the executable.  The replaced path
1460
%  is terminated by a directory separator.  The provided path may be
1461
%  a bare executable name, a relative path to the executable, or the
1462
%  full path to the executable.  The provided path is usually obtained
1463
%  from the argv[0] argument to main. If the path is a bare executable
1464
%  name, then the executable is located via the executable search path.
1465
%  If the path is replaced, then MagickPass is returned, otherwise
1466
%  MagickFail is returned.
1467
%
1468
%  The format of the GetExecutionPathUsingName method is:
1469
%
1470
%      unsigned int GetExecutionPathUsingName(char *path)
1471
%
1472
%  A description of each parameter follows:
1473
%
1474
%    o path: The path (partial or complete) to the executable.
1475
%
1476
*/
1477
MagickExport MagickPassFail GetExecutionPathUsingName(char *path)
1478
0
{
1479
0
  char
1480
0
    execution_path[MaxTextExtent],
1481
0
    original_cwd[MaxTextExtent],
1482
0
    temporary_path[MaxTextExtent],
1483
0
    *p;
1484
1485
0
  execution_path[0]='\0';
1486
1487
  /*
1488
    Save original working directory so it can be restored later.
1489
  */
1490
0
  if (getcwd(original_cwd,sizeof(original_cwd)-1) == NULL)
1491
0
              MagickFatalError(ConfigureFatalError,UnableToGetCurrentDirectory,
1492
0
                               NULL);
1493
1494
  /*
1495
    Check to see if path is a valid relative path from current
1496
    directory.
1497
  */
1498
0
  if (IsAccessibleNoLogging(path))
1499
0
    {
1500
      /*
1501
        If we can change directory to the path, then capture the full
1502
        path to it.  Otherwise, remove any trailing path component
1503
        (typically the program name) and try again.
1504
      */
1505
0
      if ((strlen(path) >0 ) && (chdir(path) == 0))
1506
0
        {
1507
0
          if (getcwd(execution_path,sizeof(execution_path)-2) == NULL)
1508
0
            MagickFatalError(ConfigureFatalError,UnableToGetCurrentDirectory,
1509
0
                             NULL);
1510
0
        }
1511
0
      else
1512
0
        {
1513
0
          (void) strlcpy(temporary_path,path,sizeof(execution_path));
1514
0
          p=strrchr(temporary_path,DirectorySeparator[0]);
1515
0
          if (p)
1516
0
            *p='\0';
1517
0
          if ((strlen(temporary_path) > 0) && (chdir(temporary_path) == 0))
1518
0
            {
1519
0
              if (getcwd(execution_path,sizeof(execution_path)-2) == NULL)
1520
0
                MagickFatalError(ConfigureFatalError,UnableToGetCurrentDirectory,
1521
0
                                 NULL);
1522
0
            }
1523
0
        }
1524
0
    }
1525
  /*
1526
    Otherwise, check to see if bare program name is available via the
1527
    executable search path.
1528
  */
1529
0
  if ((execution_path[0] == 0) && (strchr(path,DirectorySeparator[0]) == NULL ))
1530
0
  {
1531
0
    const char
1532
0
      *search_path;
1533
1534
0
    search_path=getenv("PATH");
1535
0
    if ( search_path )
1536
0
      {
1537
0
        const char
1538
0
          *end = NULL,
1539
0
          *start = search_path;
1540
1541
0
        end=start+strlen(start);
1542
0
        while ( start < end )
1543
0
          {
1544
0
            const char
1545
0
              *separator;
1546
1547
0
            size_t
1548
0
              length;
1549
1550
0
            separator = strchr(start,DirectoryListSeparator);
1551
0
            if (separator)
1552
0
              length=separator-start;
1553
0
            else
1554
0
              length=end-start;
1555
0
            if (length > MaxTextExtent-1)
1556
0
              length = MaxTextExtent-1;
1557
0
            (void) strlcpy(temporary_path,start,length+1);
1558
0
            if ((strlen(temporary_path) > 0) && (chdir(temporary_path) == 0))
1559
0
              {
1560
0
                if (temporary_path[length-1] != DirectorySeparator[0])
1561
0
                  (void) strlcat(temporary_path,DirectorySeparator,sizeof(temporary_path));
1562
0
                (void) strlcat(temporary_path,path,sizeof(temporary_path));
1563
0
                if (IsAccessibleNoLogging(temporary_path))
1564
0
                  {
1565
0
                    if (getcwd(execution_path,sizeof(execution_path)-2) == NULL)
1566
0
                      MagickFatalError(ConfigureFatalError,UnableToGetCurrentDirectory,
1567
0
                                       NULL);
1568
0
                    break;
1569
0
                  }
1570
0
              }
1571
0
            start += length+1;
1572
0
          }
1573
0
      }
1574
0
  }
1575
1576
  /*
1577
    Restore original working directory.
1578
  */
1579
0
  if ((strlen(original_cwd) > 0) && (chdir(original_cwd) != 0))
1580
0
    return(MagickFail);
1581
1582
0
  if (execution_path[0] != '\0')
1583
0
    {
1584
0
      (void) strlcat(execution_path,DirectorySeparator,sizeof(execution_path));
1585
0
      (void) strlcpy(path,execution_path,MaxTextExtent);
1586
0
      (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1587
0
                            "Path \"%.1024s\" is usable.",path);
1588
0
      errno=0;
1589
0
      return (MagickPass);
1590
0
    }
1591
1592
0
  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1593
0
                        "Path \"%.1024s\" is not valid.",path);
1594
0
  return(MagickFail);
1595
0
}
1596

1597
/*
1598
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1599
%                                                                             %
1600
%                                                                             %
1601
%                                                                             %
1602
%   G e t G e o m e t r y                                                     %
1603
%                                                                             %
1604
%                                                                             %
1605
%                                                                             %
1606
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1607
%
1608
%  GetGeometry() parses a geometry specification and returns the width
1609
%  height, x, and y values.  It also returns flags that indicates which
1610
%  of the four values (width, height, x, y) were located in the string, and
1611
%  whether the x and y values are negative.  In addition, there are flags to
1612
%  report any meta characters (%, !, <,  >, @, and ^).
1613
%
1614
%  The format of the GetGeometry method is:
1615
%
1616
%      int GetGeometry(const char *image_geometry,long *x,long *y,
1617
%        unsigned long *width,unsigned long *height)
1618
%
1619
%  A description of each parameter follows:
1620
%
1621
%    o flags:  Method GetGeometry returns a bitmask that indicates
1622
%      which of the values from GeometryFlags (XValue, YValue, WidthValue,
1623
%      HeightValue, XNegative, YNegative, PercentValue, AspectValue, LessValue,
1624
%      GreaterValue, AreaValue, MinimumValue) were located in the geometry
1625
%      string.
1626
%
1627
%    o image_geometry:  Specifies a character string representing the geometry
1628
%      specification in the form
1629
%      <width>x<height>{+-}<x>{+-}<y>{%}{@}{!}{^}{<}{>}.
1630
%
1631
%    o x,y:  The x and y offset as determined by the geometry specification is
1632
%      returned here.
1633
%
1634
%    o width,height:  The width and height as determined by the geometry
1635
%      specification is returned here.
1636
%
1637
%
1638
*/
1639
324k
#define MagickULongRangeOk(double_val) ((double_val <= (double) ULONG_MAX) && (double_val >= 0.0))
1640
94.4k
#define MagickLongRangeOk(double_val) ((double_val <= (double) LONG_MAX) && (double_val >= (double) LONG_MIN))
1641
MagickExport int GetGeometry(const char *image_geometry,long *x,long *y,
1642
  unsigned long *width,unsigned long *height)
1643
200k
{
1644
200k
  const char
1645
200k
    *c;
1646
1647
200k
  char
1648
200k
    geometry[MaxTextExtent],
1649
200k
    *p,
1650
200k
    *q;
1651
1652
200k
  int
1653
200k
    count,
1654
200k
    flags,
1655
200k
    i;
1656
1657
200k
  double
1658
200k
    double_val;
1659
1660
200k
  RectangleInfo
1661
200k
    bounds;
1662
1663
  /*
1664
    Ensure the image geometry is valid.
1665
  */
1666
200k
  assert(x != (long *) NULL);
1667
200k
  assert(y != (long *) NULL);
1668
200k
  assert(width != (unsigned long *) NULL);
1669
200k
  assert(height != (unsigned long *) NULL);
1670
200k
  if ((image_geometry == (char *) NULL) || (*image_geometry == '\0') ||
1671
196k
      (strlen(image_geometry) > MaxTextExtent-1))
1672
3.68k
    return(NoValue);
1673
1674
  /*
1675
    Transfer base geometry while recording and stripping flags
1676
  */
1677
196k
  i=0;
1678
196k
  q=geometry;
1679
196k
  flags=NoValue;
1680
1681
5.20M
  for (c=image_geometry; *c != 0 ; c++)
1682
5.01M
    {
1683
5.01M
      if (isspace((int) (*c)))
1684
1.70k
        {
1685
1.70k
          continue;
1686
1.70k
        }
1687
5.01M
      else
1688
5.01M
        switch (*c)
1689
5.01M
          {
1690
2.95k
          case '%':
1691
2.95k
            {
1692
2.95k
              flags|=PercentValue;
1693
2.95k
              break;
1694
0
            }
1695
25.9k
          case '!':
1696
25.9k
            {
1697
25.9k
              flags|=AspectValue;
1698
25.9k
              break;
1699
0
            }
1700
2.13k
          case '<':
1701
2.13k
            {
1702
2.13k
              flags|=LessValue;
1703
2.13k
              break;
1704
0
            }
1705
18.1k
          case '>':
1706
18.1k
            {
1707
18.1k
              flags|=GreaterValue;
1708
18.1k
              break;
1709
0
            }
1710
12.1k
          case '@':
1711
12.1k
            {
1712
12.1k
              flags|=AreaValue;
1713
12.1k
              break;
1714
0
            }
1715
16.0k
          case '^':
1716
16.0k
            {
1717
16.0k
              flags|=MinimumValue;
1718
16.0k
              break;
1719
0
            }
1720
109k
          case '+':
1721
176k
          case '-':
1722
187k
          case '.':
1723
3.21M
          case '0':
1724
3.56M
          case '1':
1725
3.70M
          case '2':
1726
3.84M
          case '3':
1727
3.98M
          case '4':
1728
4.08M
          case '5':
1729
4.21M
          case '6':
1730
4.44M
          case '7':
1731
4.57M
          case '8':
1732
4.73M
          case '9':
1733
4.76M
          case 'X':
1734
4.92M
          case 'x':
1735
4.92M
            {
1736
              /* Check for too many characters. */
1737
4.92M
              i++;
1738
4.92M
              if (i == sizeof(geometry)-1)
1739
365
                return NoValue;
1740
1741
4.92M
              *q=*c;
1742
4.92M
              q++;
1743
4.92M
              break;
1744
4.92M
            }
1745
12.8k
          default:
1746
12.8k
            {
1747
              /* Illegal character fails entire geometry translation */
1748
12.8k
              return NoValue;
1749
4.92M
            }
1750
5.01M
          }
1751
5.01M
    }
1752
183k
  *q='\0';
1753
1754
  /*
1755
    Parse width/height/x/y.  At this point resize qualifiers have been
1756
    truncated from the original geometry string.
1757
  */
1758
183k
  bounds.width=0;
1759
183k
  bounds.height=0;
1760
183k
  bounds.x=0;
1761
183k
  bounds.y=0;
1762
183k
  p=geometry;
1763
183k
  while ((*p != '\0') && (isspace((int)(*p))))
1764
0
    p++;
1765
183k
  if (*p == '\0')
1766
1.39k
    return(flags);
1767
182k
  if (*p == '=')
1768
0
    p++;
1769
182k
  if ((*p != '+') && (*p != '-') && (*p != 'x') && (*p != 'X'))
1770
164k
    {
1771
      /*
1772
        Parse width.
1773
      */
1774
164k
      q=p;
1775
1776
164k
      count=MagickStrToD(p,&q,&double_val);
1777
164k
      if (count)
1778
160k
        {
1779
160k
          double_val=floor(double_val+0.5);
1780
160k
          if (MagickULongRangeOk(double_val))
1781
159k
            {
1782
159k
              bounds.width=(unsigned long) double_val;
1783
159k
              flags|=WidthValue;
1784
159k
            }
1785
160k
        }
1786
164k
      if ((*q == 'x') || (*q == 'X') || ((flags & AreaValue) && (*q == '\0')))
1787
153k
        p=q;
1788
10.1k
      else
1789
10.1k
        {
1790
10.1k
          count=MagickStrToD(p,&p,&double_val);
1791
10.1k
          if (count)
1792
6.62k
            {
1793
6.62k
              double_val=floor(double_val+0.5);
1794
6.62k
              if (MagickULongRangeOk(double_val))
1795
5.66k
                {
1796
5.66k
                  bounds.width=(unsigned long) double_val;
1797
5.66k
                  bounds.height=bounds.width;
1798
5.66k
                  flags|=HeightValue;
1799
5.66k
                }
1800
6.62k
            }
1801
10.1k
        }
1802
164k
    }
1803
182k
  if ((*p == 'x') || (*p == 'X'))
1804
161k
    {
1805
      /*
1806
        Parse height.
1807
      */
1808
161k
      p++;
1809
161k
      q=p;
1810
161k
      count=MagickStrToD(p,&p,&double_val);
1811
161k
      if (count)
1812
157k
        {
1813
157k
          double_val=floor(double_val+0.5);
1814
157k
          if (MagickULongRangeOk(double_val))
1815
148k
            {
1816
148k
              bounds.height=(unsigned long) double_val;
1817
148k
              flags|=HeightValue;
1818
148k
            }
1819
157k
        }
1820
161k
    }
1821
182k
  if ((*p == '+') || (*p == '-'))
1822
69.8k
    {
1823
      /*
1824
        Parse x value.
1825
      */
1826
69.8k
      if (*p == '+')
1827
49.9k
        {
1828
49.9k
          p++;
1829
49.9k
          q=p;
1830
49.9k
          count=MagickStrToD(p,&p,&double_val);
1831
49.9k
          if (count)
1832
41.6k
            {
1833
41.6k
              double_val=ceil(double_val-0.5);
1834
41.6k
              if (MagickLongRangeOk(double_val))
1835
40.1k
                {
1836
40.1k
                  bounds.x=(long) double_val;
1837
40.1k
                  flags|=XValue;
1838
40.1k
                }
1839
41.6k
            }
1840
49.9k
        }
1841
19.9k
      else
1842
19.9k
        {
1843
19.9k
          p++;
1844
19.9k
          q=p;
1845
19.9k
          count=MagickStrToD(p,&p,&double_val);
1846
19.9k
          if (count)
1847
7.76k
            {
1848
7.76k
              double_val=ceil(-double_val-0.5);
1849
7.76k
              if (MagickLongRangeOk(double_val))
1850
6.12k
                {
1851
6.12k
                  bounds.x=(long) double_val;
1852
6.12k
                  flags|=XValue;
1853
6.12k
                  flags|=XNegative;
1854
6.12k
                }
1855
7.76k
            }
1856
19.9k
        }
1857
69.8k
      if ((*p == '+') || (*p == '-'))
1858
56.3k
        {
1859
          /*
1860
            Parse y value.
1861
          */
1862
56.3k
          if (*p == '+')
1863
44.7k
            {
1864
44.7k
              p++;
1865
44.7k
              q=p;
1866
44.7k
              count=MagickStrToD(p,&p,&double_val);
1867
44.7k
              if (count)
1868
41.0k
                {
1869
41.0k
                  double_val = ceil(double_val-0.5);
1870
41.0k
                  if (MagickLongRangeOk(double_val))
1871
38.7k
                    {
1872
38.7k
                      bounds.y=(long) double_val;
1873
38.7k
                      flags|=YValue;
1874
38.7k
                    }
1875
41.0k
                }
1876
44.7k
            }
1877
11.6k
          else
1878
11.6k
            {
1879
11.6k
              p++;
1880
11.6k
              q=p;
1881
11.6k
              count=MagickStrToD(p,&p,&double_val);
1882
11.6k
              if (count)
1883
3.97k
                {
1884
3.97k
                  double_val=ceil(-double_val-0.5);
1885
3.97k
                  if (MagickLongRangeOk(double_val))
1886
2.69k
                    {
1887
2.69k
                      bounds.y=(long) ceil(double_val);
1888
2.69k
                      flags|=YValue;
1889
2.69k
                      flags|=YNegative;
1890
2.69k
                    }
1891
3.97k
                }
1892
11.6k
            }
1893
56.3k
        }
1894
69.8k
    }
1895
182k
  if (*p != '\0')
1896
17.8k
    return(flags);
1897
164k
  if (flags & XValue)
1898
43.6k
    *x=bounds.x;
1899
164k
  if (flags & YValue)
1900
41.0k
    *y=bounds.y;
1901
164k
  if (flags & WidthValue)
1902
146k
    *width=bounds.width;
1903
164k
  if (flags & HeightValue)
1904
141k
    *height=bounds.height;
1905
164k
  return(flags);
1906
182k
}
1907

1908
/*
1909
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1910
%                                                                             %
1911
%                                                                             %
1912
%                                                                             %
1913
+   G e t M a g i c k D i m e n s i o n                                       %
1914
%                                                                             %
1915
%                                                                             %
1916
%                                                                             %
1917
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1918
%
1919
%  GetMagickDimension() parses a string in the scanf form %lfx%lf+%lf+%lf
1920
%  to obtain WIDTHxHEIGHT+XOFF+YOFF values and returns the number of values
1921
%  successfully parsed. This function exists to overcome a new behavior of
1922
%  ANSI C'99 which supports hex parsing.
1923
%
1924
%  The format of the GetMagickDimension method is:
1925
%
1926
%      int GetMagickDimension(const char *str,double *width,double *height,
1927
%                             double *xoff,double *yoff)
1928
%
1929
%  A description of each parameter follows:
1930
%
1931
%    o str:    String to parse
1932
%
1933
%    o width:  First double value
1934
%
1935
%    o height: Second double value
1936
%
1937
%    o xoff:   Third double value (usually "x offset").  May be NULL.
1938
%
1939
%    o yoff:   Fourth double value (usually "y offset"). May be NULL.
1940
%
1941
*/
1942
static int MagickStrToD(const char *start,char **end,double *value)
1943
480k
{
1944
480k
  const char
1945
480k
    *p;
1946
1947
480k
  char
1948
480k
    buff[MaxTextExtent],
1949
480k
    *estr;
1950
1951
480k
  int
1952
480k
    i,
1953
480k
    n=0;
1954
1955
480k
  p=start;
1956
1957
8.63M
  for (i=0; (*p != 0) && (*p != 'x') && (*p != ',') && (i < MaxTextExtent-2); i++)
1958
8.15M
    buff[i]=*p++;
1959
480k
  buff[i]=0;
1960
480k
  errno=0;
1961
480k
  *value=strtod(buff,&estr);
1962
480k
  if (buff == estr)
1963
40.3k
    {
1964
40.3k
      *value=0.0;
1965
40.3k
    }
1966
440k
#if defined(INFINITY)
1967
440k
  else if ((*value == +INFINITY) || (*value == -INFINITY))
1968
6.98k
    {
1969
6.98k
      *value=0.0;
1970
6.98k
      errno=ERANGE;
1971
6.98k
    }
1972
433k
#endif
1973
433k
  else if (isnan(*value))
1974
807
    {
1975
807
      *value=0.0;
1976
807
      errno=ERANGE;
1977
807
    }
1978
  /*
1979
    Warning: Visual Studio 2008 64-bit returns errno 34 "Result too
1980
    large", even though a correct value is returned!
1981
  */
1982
432k
  else if (errno == 0)
1983
429k
    {
1984
429k
      n++;
1985
429k
    }
1986
480k
  *end=(char *) start+(estr-buff);
1987
1988
480k
  return (n);
1989
480k
}
1990
MagickExport int
1991
GetMagickDimension(const char *str,double *width,double *height,
1992
                   double *xoff,double *yoff)
1993
12.1k
{
1994
12.1k
  int
1995
12.1k
    n,
1996
12.1k
    parsed;
1997
1998
12.1k
  const char
1999
12.1k
    *start=str;
2000
2001
12.1k
  char
2002
12.1k
    *end;
2003
2004
12.1k
  n=MagickStrToD(start,&end,width);
2005
12.1k
  if (n == 0)
2006
4.39k
    return n;
2007
7.72k
  start=end;
2008
7.72k
  if (*start == '%')
2009
708
    start++;
2010
7.72k
  if ((*start != 'x') && (*start != 'X'))
2011
1.52k
    return n;
2012
6.19k
  start++;
2013
6.19k
  parsed = MagickStrToD(start,&end,height);
2014
6.19k
  if (parsed == 0)
2015
4.10k
    return n;
2016
2.09k
  n += parsed;
2017
2.09k
  start=end;
2018
2.09k
  if (xoff != (double *) NULL)
2019
0
    {
2020
0
      if ((*start != '+') && (*start != '-'))
2021
0
        return n;
2022
0
      parsed = MagickStrToD(start,&end,xoff);
2023
0
      if (parsed == 0)
2024
0
        return n;
2025
0
      n += parsed;
2026
0
      if (*(start -1) == '-')
2027
0
        *xoff=-*xoff;
2028
0
      start=end;
2029
0
    }
2030
2.09k
  if (yoff != (double *) NULL)
2031
0
    {
2032
0
      if ((*start != '+') && (*start != '-'))
2033
0
        return n;
2034
0
      parsed = MagickStrToD(start,&end,yoff);
2035
0
      if (parsed == 0)
2036
0
        return n;
2037
0
      n += parsed;
2038
0
      if (*(start -1) == '-')
2039
0
        *yoff=-*yoff;
2040
0
      start=end;
2041
0
    }
2042
2043
2.09k
  return (n);
2044
2.09k
}
2045

2046
/*
2047
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2048
%                                                                             %
2049
%                                                                             %
2050
%                                                                             %
2051
+   G e t M a g i c k G e o m e t r y                                         %
2052
%                                                                             %
2053
%                                                                             %
2054
%                                                                             %
2055
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2056
%
2057
%  GetMagickGeometry() is similar to GetGeometry() except that existing
2058
%  'width', and 'height' input values are modified by the geometry
2059
%  influenced by the meta characters:  %, @, !, <, and >, as well as
2060
%  +x, and +y offsets.  The geometry string has the form:
2061
%
2062
%      <width>x<height>{+-}<x>{+-}<y>{%}{@} {!}{<}{>}
2063
%
2064
%  For example, the string "640x480>" is a valid geometry string.
2065
%
2066
%  The interpretation of the extra geometry string parameters are as
2067
%  follows:
2068
%    %: (PercentValue) The geometry width and height parameters are
2069
%       interpreted as a percentage of the supplied width and height
2070
%       parameters.
2071
%    @: (AreaValue) The geometry parameter represents the desired total
2072
%       area (e.g. "307520@") or an area equivalent to a specified
2073
%       width x height (e.g. "640x480@"), of the final image.
2074
%    !: (AspectValue) Force the width and height values to be absolute
2075
%       values.  The original image aspect ratio is not maintained.
2076
%    <: (LessValue) Update the provided width and height parameters if
2077
%       its dimensions are less than the geometry specification.
2078
%    >: (GreaterValue) Update the provided width and height parameters
2079
%       if its dimensions are greater than the geometry specification.
2080
%    ^: (MinimumValue) Width and height are increased as required to
2081
%       preserve aspect ratio while ensuring that width and height are
2082
%       no less than specified.
2083
%
2084
%  Any supplied offset parameters are used to adjust the image width,
2085
%  height, and x/y offset values as required to center the scaled image
2086
%  into the region specified by the supplied width and height.
2087
%
2088
%  If only the width is specified, the width assumes the value and the
2089
%  height is chosen to maintain the aspect ratio of the image. Similarly,
2090
%  if only the height is specified (e.g., -geometry x256), the width is
2091
%  chosen to maintain the aspect ratio.
2092
%
2093
%  The format of the GetMagickGeometry method is:
2094
%
2095
%      int GetMagickGeometry(const char *geometry,long *x,long *y,
2096
%        unsigned long *width,unsigned long *height)
2097
%
2098
%  A description of each parameter follows:
2099
%
2100
%    o flags:  Method GetMagickGeometry returns a bitmask that indicates
2101
%      which of the twelve values (XValue, YValue, WidthValue, HeightValue,
2102
%      XNegative, YNegative, PercentValue, AspectValue, LessValue,
2103
%      GreaterValue, AreaValue, MinimumValue) were located in the geometry
2104
%      string.
2105
%
2106
%    o image_geometry:  Specifies a character string representing the geometry
2107
%      specification.
2108
%
2109
%    o x,y:  A pointer to an integer.  The x and y offset as determined by
2110
%      the geometry specification is returned here.
2111
%
2112
%    o width,height:  A pointer to an unsigned integer.  The width and height
2113
%      as determined by the geometry specification is returned here.
2114
%
2115
%
2116
*/
2117
MagickExport int GetMagickGeometry(const char *geometry,long *x,long *y,
2118
                                   unsigned long *width,unsigned long *height)
2119
33.9k
{
2120
33.9k
  int
2121
33.9k
    flags;
2122
2123
33.9k
  long
2124
33.9k
    count;
2125
2126
33.9k
  unsigned long
2127
33.9k
    former_height,
2128
33.9k
    former_width;
2129
2130
  /*
2131
    Ensure the image geometry is valid.
2132
  */
2133
33.9k
  assert(x != (long *) NULL);
2134
33.9k
  assert(y != (long *) NULL);
2135
33.9k
  assert(width != (unsigned long *) NULL);
2136
33.9k
  assert(height != (unsigned long *) NULL);
2137
33.9k
  if ((geometry == (char *) NULL) || (*geometry == '\0'))
2138
0
    return(NoValue);
2139
  /*
2140
    Parse geometry using GetGeometry.
2141
  */
2142
33.9k
  former_width=(*width);
2143
33.9k
  former_height=(*height);
2144
33.9k
  flags=GetGeometry(geometry,x,y,width,height);
2145
2146
33.9k
  if ((former_width == 0UL) || (former_height == 0UL))
2147
0
    return(flags);
2148
2149
#if 0
2150
  fprintf(stderr,"WidthValue=%u, HeightValue=%u width=%lu, height=%lu\n",
2151
          flags & WidthValue ? 1 : 0,
2152
          flags & HeightValue ? 1 : 0,
2153
          *width,*height);
2154
#endif
2155
2156
33.9k
  if (flags & AreaValue) /* @  */
2157
0
    {
2158
0
      double
2159
0
        scale_factor,
2160
0
        original_area,
2161
0
        target_area;
2162
2163
0
      MagickBool
2164
0
        resize;
2165
2166
      /*
2167
        Geometry is an area in pixels.
2168
      */
2169
0
      target_area=0.0;
2170
0
      if (flags & WidthValue)
2171
0
        target_area=(double) (*width);
2172
0
      if (flags & HeightValue)
2173
0
        target_area *= (double) (*height);
2174
2175
0
      if (target_area > 0.25)
2176
0
        {
2177
0
          original_area=(double) former_width*former_height;
2178
0
          resize=MagickFalse;
2179
0
          if (flags & GreaterValue)
2180
0
            {
2181
              /* Resize if image area greater than target */
2182
0
              if (original_area > target_area)
2183
0
                resize=MagickTrue;
2184
0
            }
2185
0
          else if (flags & LessValue)
2186
0
            {
2187
              /* Resize if image area less than target */
2188
0
              if (original_area < target_area)
2189
0
                resize=MagickTrue;
2190
0
            }
2191
0
          else
2192
0
            {
2193
              /* Always resize */
2194
0
              resize=MagickTrue;
2195
0
            }
2196
2197
0
          if (resize)
2198
0
            {
2199
0
              scale_factor=1.0/sqrt(original_area/target_area);
2200
0
              *width=(unsigned long) floor(former_width*scale_factor+0.25);
2201
0
              *height=(unsigned long) floor(former_height*scale_factor+0.25);
2202
0
            }
2203
0
          else
2204
0
            {
2205
0
              *width=former_width;
2206
0
              *height=former_height;
2207
0
            }
2208
0
        }
2209
0
    }
2210
33.9k
  else
2211
33.9k
    {
2212
      /*
2213
        Deal with width or height being missing from geometry.  Supply
2214
        missing value required to preserve current image aspect ratio.
2215
      */
2216
33.9k
      if (((flags & WidthValue) && !(flags & HeightValue)))
2217
6.92k
        *height=(unsigned long) floor(((double) former_height/former_width)*
2218
6.92k
                                      (*width)+0.5);
2219
27.0k
      else if ((!(flags & WidthValue) &&  (flags & HeightValue)))
2220
0
        *width=(unsigned long) floor(((double) former_width/former_height)*
2221
0
                                     (*height)+0.5);
2222
#if 0
2223
      fprintf(stderr,"Geometry Bounds: %lux%lu\n",*width,*height);
2224
#endif
2225
33.9k
      if (flags & PercentValue)
2226
0
        {
2227
0
          double
2228
0
            x_scale,
2229
0
            y_scale;
2230
2231
          /*
2232
            Geometry is a percentage of the image size.
2233
          */
2234
0
          x_scale=(*width);
2235
0
          y_scale=(*height);
2236
0
          count=GetMagickDimension(geometry,&x_scale,&y_scale,NULL,NULL);
2237
0
          if (count == 1)
2238
0
            y_scale=x_scale;
2239
0
          *width=(unsigned long) floor((x_scale*former_width/100.0)+0.5);
2240
0
          *height=(unsigned long) floor((y_scale*former_height/100.0)+0.5);
2241
0
          former_width=(*width);
2242
0
          former_height=(*height);
2243
0
        }
2244
33.9k
      if (!(flags & AspectValue) && /* ! */
2245
12.5k
          ((*width != former_width) || (*height != former_height)))
2246
11.2k
        {
2247
11.2k
          double
2248
11.2k
            scale_factor;
2249
2250
          /*
2251
            Respect aspect ratio of the image but assure that it is no
2252
            larger than specified.
2253
          */
2254
11.2k
          if ((former_width == 0) || (former_height == 0))
2255
0
            {
2256
0
              scale_factor=1.0;
2257
0
            }
2258
11.2k
          else
2259
11.2k
            {
2260
11.2k
              double
2261
11.2k
                scale_height,
2262
11.2k
                scale_width;
2263
2264
11.2k
              scale_height=(double) *height/former_height;
2265
11.2k
              scale_width=(double) *width/former_width;
2266
2267
11.2k
              scale_factor=scale_width;
2268
11.2k
              if ((flags & MinimumValue) != 0)
2269
0
                {
2270
                  /* Width and height are minimum values */
2271
0
                  if (scale_width < scale_height)
2272
0
                    scale_factor=scale_height;
2273
0
                }
2274
11.2k
              else
2275
11.2k
                {
2276
                  /* Width and height are maximum values */
2277
11.2k
                  if (scale_width > scale_height)
2278
2.81k
                    scale_factor=scale_height;
2279
11.2k
                }
2280
11.2k
            }
2281
11.2k
          *width=(unsigned long) floor(scale_factor*former_width+0.5);
2282
11.2k
          *height=(unsigned long) floor(scale_factor*former_height+0.5);
2283
2284
          /* Width and height can not be zero! */
2285
11.2k
          *width=Max(*width,1);
2286
11.2k
          *height=Max(*height,1);
2287
11.2k
        }
2288
33.9k
      if (flags & GreaterValue) /* > */
2289
2.15k
        {
2290
2.15k
          if (former_width < *width)
2291
884
            *width=former_width;
2292
2.15k
          if (former_height < *height)
2293
869
            *height=former_height;
2294
2.15k
        }
2295
33.9k
      if (flags & LessValue) /* < */
2296
0
        {
2297
0
          if (former_width > *width)
2298
0
            *width=former_width;
2299
0
          if (former_height > *height)
2300
0
            *height=former_height;
2301
0
        }
2302
33.9k
    }
2303
2304
33.9k
  return(flags);
2305
33.9k
}
2306

2307
/*
2308
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2309
%                                                                             %
2310
%                                                                             %
2311
%                                                                             %
2312
%  G e t P a g e G e o m e t r y                                              %
2313
%                                                                             %
2314
%                                                                             %
2315
%                                                                             %
2316
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2317
%
2318
%  GetPageGeometry() returns a new geometry string, with any embedded page
2319
%  mneumonic in the original geometry string replaced with the equivalent
2320
%  size in picas. For example, the geometry string "A4+36+36" is translated
2321
%  to "595x842+36+36" in the returned value.
2322
%
2323
%  The format of the GetPageGeometry method is:
2324
%
2325
%      char *GetPageGeometry(const char *page_geometry)
2326
%
2327
%  A description of each parameter follows.
2328
%
2329
%   o  page_geometry:  The geometry string to translate.
2330
%
2331
%
2332
*/
2333
MagickExport char *GetPageGeometry(const char *page_geometry)
2334
56.5k
{
2335
56.5k
#undef PAGE_SIZE
2336
3.84M
#define PAGE_SIZE(name, geometry) { name, sizeof(name)-1, geometry }
2337
56.5k
  static const struct
2338
56.5k
  {
2339
56.5k
    char
2340
56.5k
    name[12];
2341
2342
56.5k
    unsigned char
2343
56.5k
    name_length;
2344
2345
56.5k
    char
2346
56.5k
    geometry[10];
2347
56.5k
  }
2348
56.5k
    PageSizes[] =
2349
56.5k
    {
2350
56.5k
      PAGE_SIZE("4x6",  "288x432"),
2351
56.5k
      PAGE_SIZE("5x7",  "360x504"),
2352
56.5k
      PAGE_SIZE("7x9",  "504x648"),
2353
56.5k
      PAGE_SIZE("8x10", "576x720"),
2354
56.5k
      PAGE_SIZE("9x11",  "648x792"),
2355
56.5k
      PAGE_SIZE("9x12",  "648x864"),
2356
56.5k
      PAGE_SIZE("10x13",  "720x936"),
2357
56.5k
      PAGE_SIZE("10x14",  "720x1008"),
2358
56.5k
      PAGE_SIZE("11x17",  "792x1224"),
2359
56.5k
      PAGE_SIZE("A0",  "2384x3370"),
2360
56.5k
      PAGE_SIZE("A1",  "1684x2384"),
2361
56.5k
      PAGE_SIZE("A10", "73x105"),
2362
56.5k
      PAGE_SIZE("A2",  "1191x1684"),
2363
56.5k
      PAGE_SIZE("A3",  "842x1191"),
2364
56.5k
      PAGE_SIZE("A4",  "595x842"),
2365
56.5k
      PAGE_SIZE("A4SMALL", "595x842"),
2366
56.5k
      PAGE_SIZE("A5",  "420x595"),
2367
56.5k
      PAGE_SIZE("A6",  "297x420"),
2368
56.5k
      PAGE_SIZE("A7",  "210x297"),
2369
56.5k
      PAGE_SIZE("A8",  "148x210"),
2370
56.5k
      PAGE_SIZE("A9",  "105x148"),
2371
56.5k
      PAGE_SIZE("ARCHA", "648x864"),
2372
56.5k
      PAGE_SIZE("ARCHB", "864x1296"),
2373
56.5k
      PAGE_SIZE("ARCHC", "1296x1728"),
2374
56.5k
      PAGE_SIZE("ARCHD", "1728x2592"),
2375
56.5k
      PAGE_SIZE("ARCHE", "2592x3456"),
2376
56.5k
      PAGE_SIZE("B0",  "2920x4127"),
2377
56.5k
      PAGE_SIZE("B1",  "2064x2920"),
2378
56.5k
      PAGE_SIZE("B10", "91x127"),
2379
56.5k
      PAGE_SIZE("B2",  "1460x2064"),
2380
56.5k
      PAGE_SIZE("B3",  "1032x1460"),
2381
56.5k
      PAGE_SIZE("B4",  "729x1032"),
2382
56.5k
      PAGE_SIZE("B5",  "516x729"),
2383
56.5k
      PAGE_SIZE("B6",  "363x516"),
2384
56.5k
      PAGE_SIZE("B7",  "258x363"),
2385
56.5k
      PAGE_SIZE("B8",  "181x258"),
2386
56.5k
      PAGE_SIZE("B9",  "127x181"),
2387
56.5k
      PAGE_SIZE("C0",  "2599x3676"),
2388
56.5k
      PAGE_SIZE("C1",  "1837x2599"),
2389
56.5k
      PAGE_SIZE("C2",  "1298x1837"),
2390
56.5k
      PAGE_SIZE("C3",  "918x1296"),
2391
56.5k
      PAGE_SIZE("C4",  "649x918"),
2392
56.5k
      PAGE_SIZE("C5",  "459x649"),
2393
56.5k
      PAGE_SIZE("C6",  "323x459"),
2394
56.5k
      PAGE_SIZE("C7",  "230x323"),
2395
56.5k
      PAGE_SIZE("EXECUTIVE", "540x720"),
2396
56.5k
      PAGE_SIZE("FLSA", "612x936"),
2397
56.5k
      PAGE_SIZE("FLSE", "612x936"),
2398
56.5k
      PAGE_SIZE("FOLIO",  "612x936"),
2399
56.5k
      PAGE_SIZE("HALFLETTER", "396x612"),
2400
56.5k
      PAGE_SIZE("ISOB0", "2835x4008"),
2401
56.5k
      PAGE_SIZE("ISOB1", "2004x2835"),
2402
56.5k
      PAGE_SIZE("ISOB10", "88x125"),
2403
56.5k
      PAGE_SIZE("ISOB2", "1417x2004"),
2404
56.5k
      PAGE_SIZE("ISOB3", "1001x1417"),
2405
56.5k
      PAGE_SIZE("ISOB4", "709x1001"),
2406
56.5k
      PAGE_SIZE("ISOB5", "499x709"),
2407
56.5k
      PAGE_SIZE("ISOB6", "354x499"),
2408
56.5k
      PAGE_SIZE("ISOB7", "249x354"),
2409
56.5k
      PAGE_SIZE("ISOB8", "176x249"),
2410
56.5k
      PAGE_SIZE("ISOB9", "125x176"),
2411
56.5k
      PAGE_SIZE("LEDGER",  "1224x792"),
2412
56.5k
      PAGE_SIZE("LEGAL",  "612x1008"),
2413
56.5k
      PAGE_SIZE("LETTER", "612x792"),
2414
56.5k
      PAGE_SIZE("LETTERSMALL",  "612x792"),
2415
56.5k
      PAGE_SIZE("QUARTO",  "610x780"),
2416
56.5k
      PAGE_SIZE("STATEMENT",  "396x612"),
2417
56.5k
      PAGE_SIZE("TABLOID",  "792x1224")
2418
56.5k
    };
2419
2420
56.5k
  char
2421
56.5k
    page[MaxTextExtent];
2422
2423
56.5k
  register size_t
2424
56.5k
    i;
2425
2426
56.5k
  assert(page_geometry != (char *) NULL);
2427
56.5k
  strlcpy(page,page_geometry,MaxTextExtent);
2428
3.18M
  for (i=0; i < ArraySize(PageSizes); i++)
2429
3.14M
    if (LocaleNCompare(PageSizes[i].name,page_geometry,
2430
3.14M
                       PageSizes[i].name_length) == 0)
2431
14.3k
      {
2432
14.3k
        int
2433
14.3k
          flags;
2434
2435
14.3k
        RectangleInfo
2436
14.3k
          geometry;
2437
2438
        /*
2439
          Replace mneumonic with the equivalent size in dots-per-inch.
2440
        */
2441
14.3k
        MagickFormatString(page,sizeof(page),"%s%.80s", PageSizes[i].geometry,
2442
14.3k
                           page_geometry+PageSizes[i].name_length);
2443
14.3k
        flags=GetGeometry(page,&geometry.x,&geometry.y,&geometry.width,
2444
14.3k
                          &geometry.height);
2445
14.3k
        if (!(flags & GreaterValue))
2446
13.7k
          (void) strlcat(page,">",sizeof(page));
2447
14.3k
        break;
2448
14.3k
      }
2449
56.5k
  return (AcquireString(page));
2450
56.5k
}
2451

2452
/*
2453
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2454
%                                                                             %
2455
%                                                                             %
2456
%                                                                             %
2457
%   G e t P a t h C o m p o n e n t                                           %
2458
%                                                                             %
2459
%                                                                             %
2460
%                                                                             %
2461
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2462
%
2463
%  Method GetPathComponent returns the parent directory name, filename,
2464
%  basename, or extension of a file path.  File paths are in the form:
2465
%
2466
%     magick:base.ext[subimage]
2467
%
2468
%  Similar to
2469
%
2470
%      jpg:bar
2471
%      jpg:foo.bar
2472
%      pdf:foo.pdf[2-3]
2473
%      foo.pdf[2-3]
2474
%      C:\path\foo.bar
2475
%      /path/foo.bar
2476
%      pdf:C:\path\foo.pdf[2-3]
2477
%
2478
%  Note that Windows drive letters may be part of paths on Windows systems
2479
%  and such paths include a colon.  Path components in real file paths may
2480
%  include a colon and the file might not exist yet (or ever) so testing
2481
%  for it is not reliable.  This means that determination of the "magick"
2482
%  part is ambiguous and not reliable.
2483
%
2484
%  The format of the GetPathComponent function is:
2485
%
2486
%      GetPathComponent(const char *path,PathType type,char *component)
2487
%
2488
%  A description of each parameter follows:
2489
%
2490
%    o path: Specifies a pointer to a character array that contains the
2491
%      file path.
2492
%
2493
%    o type: Specififies which file path component to return (RootPath,
2494
%              HeadPath, TailPath, BasePath, ExtensionPath, MagickPath,
2495
%              SubImagePath, or FullPath).
2496
%
2497
%    o component: The selected file path component is returned here.
2498
%
2499
*/
2500
static inline unsigned int IsFrame(const char *point)
2501
0
{
2502
0
  char
2503
0
    *p;
2504
2505
0
  long
2506
0
    long_val;
2507
2508
0
  long_val = strtol(point,&p,10);
2509
0
  (void) long_val;
2510
0
  return(p != point);
2511
0
}
2512
2513
MagickExport void GetPathComponent(const char *path,PathType type,
2514
  char *component)
2515
63.2k
{
2516
63.2k
  register char
2517
63.2k
    *p;
2518
2519
63.2k
  char
2520
63.2k
    magick[MaxTextExtent],
2521
63.2k
    subimage[MaxTextExtent];
2522
2523
  /*
2524
    Get basename of client.
2525
  */
2526
63.2k
  assert(path != (const char *) NULL);
2527
63.2k
  assert(component != (const char *) NULL);
2528
63.2k
  if (strlcpy(component,path,MaxTextExtent) >= MaxTextExtent)
2529
0
    MagickFatalError2(ResourceLimitFatalError,"Path buffer overflow",
2530
63.2k
                      path);
2531
63.2k
  if (*path == '\0')
2532
2.26k
    return;
2533
60.9k
  subimage[0]=magick[0]='\0';
2534
2535
  /*
2536
    Remove magic and subimage spec. from the path to make
2537
    it easier to extract filename parts.
2538
  */
2539
876k
  for (p=component; (*p != '\0') && (*p != ':'); p++)
2540
815k
    ;
2541
60.9k
  if (*p == ':')
2542
0
    {
2543
0
      (void) strncpy(magick,component,(size_t)(p-component)+1);
2544
0
      magick[p-component+1]='\0';
2545
0
      if (IsMagickConflict(magick))
2546
0
        {
2547
0
          magick[0]='\0';
2548
0
        }
2549
0
      else
2550
0
        {
2551
0
          register char
2552
0
            *q;
2553
2554
          /*
2555
            Safe-copy the remaining component part on top of the magic part.
2556
          */
2557
0
          magick[p-component]='\0';
2558
0
          p++;
2559
0
          q=component;
2560
0
          while ((*q++=*p++))
2561
0
            ;
2562
0
        }
2563
0
    }
2564
2565
60.9k
  p=component+strlen(component);
2566
60.9k
  if ((p > component) && (*--p == ']'))
2567
0
    {
2568
      /* Look for a '[' matching the ']' */
2569
0
      p--;
2570
0
      while ((p > component) &&
2571
0
             (*p != '[') &&
2572
0
             (strchr("0123456789xX,-+ ", (int)(unsigned char)*p) != 0) )
2573
0
        p--;
2574
2575
      /* Copy to subimage and remove from component */
2576
0
      if ((p > component) && (*p == '[') && IsFrame(p+1))
2577
0
        {
2578
0
          (void) strlcpy(subimage, p,sizeof(subimage));
2579
0
          *p='\0';
2580
0
        }
2581
0
    }
2582
2583
  /* first locate the spot were the filename begins */
2584
615k
  for (p=component+strlen(component); p > component; p--)
2585
615k
    if (IsBasenameSeparator(*p)) /* Is directory delimiter like '/' or '\\' */
2586
60.6k
      break;
2587
2588
60.9k
  switch (type)
2589
60.9k
  {
2590
0
    case MagickPath:
2591
0
    {
2592
      /* this only includes the magick override prefix (if any) */
2593
0
      (void) strlcpy(component,magick,MaxTextExtent);
2594
0
      break;
2595
0
    }
2596
0
    case SubImagePath:
2597
0
    {
2598
      /* this returns only the subimage specification, including
2599
         bracketing '[]', (if any) */
2600
0
      (void) strlcpy(component,subimage,MaxTextExtent);
2601
0
      break;
2602
0
    }
2603
0
    case FullPath:
2604
0
    {
2605
      /* this returns the full path except magic and sub-image spec. */
2606
0
      break;
2607
0
    }
2608
60.1k
    case RootPath:
2609
60.1k
    {
2610
      /* this returns the path including the file part with no extension */
2611
842k
      for (p=component+strlen(component); p > component; p--)
2612
782k
        if (*p == '.')
2613
0
          break;
2614
60.1k
      if (*p == '.')
2615
0
        *p='\0';
2616
60.1k
      break;
2617
0
    }
2618
254
    case HeadPath:
2619
254
    {
2620
      /* this returns the path only with no trailing separator */
2621
254
      *p='\0';
2622
254
      break;
2623
0
    }
2624
254
    case TailPath:
2625
254
    {
2626
      /* this returns the filename and extension only */
2627
254
      if (IsBasenameSeparator(*p))
2628
254
        {
2629
254
          char
2630
254
            scratch[MaxTextExtent];
2631
2632
254
          (void) strlcpy(scratch,p+1,MaxTextExtent);
2633
254
          (void) strlcpy(component,scratch,MaxTextExtent);
2634
254
        }
2635
254
      break;
2636
0
    }
2637
254
    case BasePath:
2638
254
    {
2639
      /* this returns just the filename with no extension */
2640
254
      if (IsBasenameSeparator(*p))
2641
0
        {
2642
0
          char
2643
0
            scratch[MaxTextExtent];
2644
2645
0
          (void) strlcpy(scratch,p+1,MaxTextExtent);
2646
0
          (void) strlcpy(component,scratch,MaxTextExtent);
2647
0
        }
2648
4.48k
      for (p=component+strlen(component); p > component; p--)
2649
4.22k
        if (*p == '.')
2650
0
          {
2651
0
            *p='\0';
2652
0
            break;
2653
0
          }
2654
254
      break;
2655
0
    }
2656
0
    case ExtensionPath:
2657
0
    {
2658
      /* this returns the file extension only */
2659
0
      if (IsBasenameSeparator(*p))
2660
0
        {
2661
0
          char
2662
0
            scratch[MaxTextExtent];
2663
2664
0
          (void) strlcpy(scratch,p+1,MaxTextExtent);
2665
0
          (void) strlcpy(component,scratch,MaxTextExtent);
2666
0
        }
2667
0
      for (p=component+strlen(component); p > component; p--)
2668
0
        if (*p == '.')
2669
0
          break;
2670
0
      *component='\0';
2671
0
      if (*p == '.')
2672
0
        {
2673
0
          char
2674
0
            scratch[MaxTextExtent];
2675
2676
0
          (void) strlcpy(scratch,p+1,MaxTextExtent);
2677
0
          (void) strlcpy(component,scratch,MaxTextExtent);
2678
0
        }
2679
0
      break;
2680
0
    }
2681
60.9k
  }
2682
60.9k
}
2683

2684
/*
2685
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2686
%                                                                             %
2687
%                                                                             %
2688
%                                                                             %
2689
+   G e t T o k e n                                                           %
2690
%                                                                             %
2691
%                                                                             %
2692
%                                                                             %
2693
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2694
%
2695
%  Method GetToken gets a token from the token stream.  A token is defined
2696
%  as sequence of characters delimited by whitespace (e.g. clip-path), a
2697
%  sequence delimited with quotes (.e.g "Quote me"), or a sequence enclosed
2698
%  in parenthesis (e.g. rgb(0,0,0)).  The output to token is constrained to
2699
%  not overflow a buffer of size MaxTextExtent so it should be allocated with
2700
%  that size.
2701
%
2702
%  The format of the GetToken method is:
2703
%
2704
%      void GetToken(const char *start,char **end,char *token)
2705
%
2706
%  A description of each parameter follows:
2707
%
2708
%    o start: the start of the token sequence.
2709
%
2710
%    o end: point to the end of the token sequence (may be NULL).
2711
%
2712
%    o token: copy the token to this buffer.
2713
%
2714
%
2715
*/
2716
MagickExport void GetToken(const char *start,char **end,char *token)
2717
0
{
2718
0
  (void) MagickGetToken(start,end,token, MaxTextExtent);
2719
0
}
2720

2721
/*
2722
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2723
%                                                                             %
2724
%                                                                             %
2725
%                                                                             %
2726
%   G l o b E x p r e s s i o n                                               %
2727
%                                                                             %
2728
%                                                                             %
2729
%                                                                             %
2730
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2731
%
2732
%  Method GlobExpression returns True if the expression matches the pattern.
2733
%  The pattern specification syntax is roughly similar to that supported by
2734
%  POSIX.2 glob().
2735
%
2736
%  Please note that there is a conflict between glob patterns and subimage
2737
%  specifications.  For example, video.mpg[50] or video.mpg[50-75] might
2738
%  refer to video.mpg (page 51, or pages 51-76) or there might be a file
2739
%  named 'video.mpg[50]'.  The IsSubimage() function is used to quickly test
2740
%  if the specification may be a subimage specification.  If the pattern is
2741
%  ultimately determined to be a subimage specification, then globbing is
2742
%  not performed.
2743
%
2744
%
2745
%  The format of the GlobExpression function is:
2746
%
2747
%      int GlobExpression(const char *expression,const char *pattern)
2748
%
2749
%  A description of each parameter follows:
2750
%
2751
%    o expression: Specifies a pointer to a text string containing a file name.
2752
%
2753
%    o pattern: Specifies a pointer to a text string containing a pattern.
2754
%            Patterns supported are roughly equivalent to those supported by
2755
%            POSIX.2 glob().
2756
%
2757
%
2758
*/
2759
MagickExport int GlobExpression(const char *expression,const char *pattern)
2760
0
{
2761
0
  unsigned int
2762
0
    done;
2763
2764
  /*
2765
    Return on empty pattern or '*'.
2766
  */
2767
0
  if (pattern == (char *) NULL)
2768
0
    return(True);
2769
0
  if (strlen(pattern) == 0)
2770
0
    return(True);
2771
0
  if (LocaleCompare(pattern,"*") == 0)
2772
0
    return(True);
2773
  /*
2774
    Evaluate glob expression.
2775
  */
2776
0
  done=False;
2777
0
  while ((*pattern != '\0') && !done)
2778
0
  {
2779
0
    if (*expression == '\0')
2780
0
      if ((*pattern != '{') && (*pattern != '*'))
2781
0
        break;
2782
0
    switch (*pattern)
2783
0
    {
2784
0
      case '\\':
2785
0
      {
2786
0
        pattern++;
2787
0
        if (*pattern != '\0')
2788
0
          pattern++;
2789
0
        break;
2790
0
      }
2791
0
      case '*':
2792
0
      {
2793
0
        int
2794
0
          status;
2795
2796
0
        pattern++;
2797
0
        status=False;
2798
0
        while ((*expression != '\0') && !status)
2799
0
          status=GlobExpression((char *) expression++,pattern);
2800
0
        if (status)
2801
0
          {
2802
0
            while (*expression != '\0')
2803
0
              expression++;
2804
0
            while (*pattern != '\0')
2805
0
              pattern++;
2806
0
          }
2807
0
        break;
2808
0
      }
2809
0
      case '[':
2810
0
      {
2811
0
        char
2812
0
          c;
2813
2814
0
        pattern++;
2815
0
        for ( ; ; )
2816
0
        {
2817
0
          if ((*pattern == '\0') || (*pattern == ']'))
2818
0
            {
2819
0
              done=True;
2820
0
              break;
2821
0
            }
2822
0
          if (*pattern == '\\')
2823
0
            {
2824
0
              pattern++;
2825
0
              if (*pattern == '\0')
2826
0
                {
2827
0
                  done=True;
2828
0
                  break;
2829
0
                }
2830
0
             }
2831
0
          if (*(pattern+1) == '-')
2832
0
            {
2833
0
              c=(*pattern);
2834
0
              pattern+=2;
2835
0
              if (*pattern == ']')
2836
0
                {
2837
0
                  done=True;
2838
0
                  break;
2839
0
                }
2840
0
              if (*pattern == '\\')
2841
0
                {
2842
0
                  pattern++;
2843
0
                  if (*pattern == '\0')
2844
0
                    {
2845
0
                      done=True;
2846
0
                      break;
2847
0
                    }
2848
0
                }
2849
0
              if ((*expression < c) || (*expression > *pattern))
2850
0
                {
2851
0
                  pattern++;
2852
0
                  continue;
2853
0
                }
2854
0
            }
2855
0
          else
2856
0
            if (*pattern != *expression)
2857
0
              {
2858
0
                pattern++;
2859
0
                continue;
2860
0
              }
2861
0
          pattern++;
2862
0
          while ((*pattern != ']') && (*pattern != '\0'))
2863
0
          {
2864
0
            if ((*pattern == '\\') && (*(pattern+1) != '\0'))
2865
0
              pattern++;
2866
0
            pattern++;
2867
0
          }
2868
0
          if (*pattern != '\0')
2869
0
            {
2870
0
              pattern++;
2871
0
              expression++;
2872
0
            }
2873
0
          break;
2874
0
        }
2875
0
        break;
2876
0
      }
2877
0
      case '?':
2878
0
      {
2879
0
        pattern++;
2880
0
        expression++;
2881
0
        break;
2882
0
      }
2883
0
      case '{':
2884
0
      {
2885
0
        int
2886
0
          match;
2887
2888
0
        register const char
2889
0
          *p;
2890
2891
0
        pattern++;
2892
0
        while ((*pattern != '}') && (*pattern != '\0'))
2893
0
        {
2894
0
          p=expression;
2895
0
          match=True;
2896
0
          while ((*p != '\0') && (*pattern != '\0') &&
2897
0
                 (*pattern != ',') && (*pattern != '}') && match)
2898
0
          {
2899
0
            if (*pattern == '\\')
2900
0
              pattern++;
2901
0
            match=(*pattern == *p);
2902
0
            p++;
2903
0
            pattern++;
2904
0
          }
2905
0
          if (*pattern == '\0')
2906
0
            {
2907
0
              match=False;
2908
0
              done=True;
2909
0
              break;
2910
0
            }
2911
0
          else
2912
0
            if (match)
2913
0
              {
2914
0
                expression=p;
2915
0
                while ((*pattern != '}') && (*pattern != '\0'))
2916
0
                {
2917
0
                  pattern++;
2918
0
                  if (*pattern == '\\')
2919
0
                    {
2920
0
                      pattern++;
2921
0
                      if (*pattern == '}')
2922
0
                        pattern++;
2923
0
                    }
2924
0
                }
2925
0
              }
2926
0
            else
2927
0
              {
2928
0
                while ((*pattern != '}') && (*pattern != ',') &&
2929
0
                       (*pattern != '\0'))
2930
0
                {
2931
0
                  pattern++;
2932
0
                  if (*pattern == '\\')
2933
0
                    {
2934
0
                      pattern++;
2935
0
                      if ((*pattern == '}') || (*pattern == ','))
2936
0
                        pattern++;
2937
0
                    }
2938
0
                }
2939
0
              }
2940
0
          if (*pattern != '\0')
2941
0
            pattern++;
2942
0
        }
2943
0
        break;
2944
0
      }
2945
0
      default:
2946
0
      {
2947
0
        if (*expression != *pattern)
2948
0
          done=True;
2949
0
        else
2950
0
          {
2951
0
            expression++;
2952
0
            pattern++;
2953
0
          }
2954
0
      }
2955
0
    }
2956
0
  }
2957
0
  while ((*pattern != '\0') && (*pattern == '*'))
2958
0
    pattern++;
2959
0
  return((*expression == '\0') && (*pattern == '\0'));
2960
0
}
2961

2962
/*
2963
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2964
%                                                                             %
2965
%                                                                             %
2966
%                                                                             %
2967
%  I s A c c e s s i b l e                                                    %
2968
%                                                                             %
2969
%                                                                             %
2970
%                                                                             %
2971
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2972
%
2973
%  IsAccessible() returns MagickTrue if the file as defined by path exists
2974
%  and is readable by the user.
2975
%
2976
%  The format of the IsAccessible method is:
2977
%
2978
%      MagickBool IsAccessible(const char *path)
2979
%
2980
%  A description of each parameter follows.
2981
%
2982
%    o status:  Method IsAccessible returns MagickTrue if the file as defined by
2983
%      path exists and is readable by the user, otherwise MagickFalse is returned.
2984
%
2985
%    o path:  A pointer to an array of characters containing the path.
2986
%
2987
%
2988
*/
2989
MagickExport MagickBool IsAccessible(const char *path)
2990
16.6k
{
2991
16.6k
  if ((path == (const char *) NULL) || (*path == '\0'))
2992
3.12k
    return(MagickFalse);
2993
2994
13.5k
  if ((access(path,R_OK)) != 0)
2995
8.57k
    {
2996
8.57k
      (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
2997
8.57k
        "Tried: %.1024s [%.1024s]",path,strerror(errno));
2998
8.57k
      return(MagickFalse);
2999
8.57k
    }
3000
4.99k
  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
3001
4.99k
                        "Found: %.1024s",path);
3002
4.99k
  return (MagickTrue);
3003
13.5k
}
3004

3005
/*
3006
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3007
%                                                                             %
3008
%                                                                             %
3009
%                                                                             %
3010
%  I s A c c e s s i b l e N o L o g g i n g                                  %
3011
%                                                                             %
3012
%                                                                             %
3013
%                                                                             %
3014
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3015
%
3016
%  IsAccessibleNoLogging() returns MagickTrue if the file as defined by path
3017
%  exists and is accessible by the user. This version is used internally to
3018
%  avoid using the error logging of the normal version.
3019
%
3020
%  The format of the IsAccessibleNoLogging method is:
3021
%
3022
%      MagickBool IsAccessibleNoLogging(const char *path)
3023
%
3024
%  A description of each parameter follows.
3025
%
3026
%    o status:  Method IsAccessibleNoLogging returns MagickTrue if the file as
3027
%      defined by path exists and is a regular file, otherwise Magick False is
3028
%      returned.
3029
%
3030
%    o path:  A pointer to an array of characters containing the path.
3031
%
3032
%
3033
*/
3034
MagickExport MagickBool IsAccessibleNoLogging(const char *path)
3035
1.70M
{
3036
1.70M
  if ((path == (const char *) NULL) || (*path == '\0'))
3037
5
    return(MagickFalse);
3038
3039
1.70M
  if ((access(path,R_OK)) != 0)
3040
1.69M
    return(MagickFalse);
3041
304
  return (MagickTrue);
3042
1.70M
}
3043

3044
/*
3045
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3046
%                                                                             %
3047
%                                                                             %
3048
%                                                                             %
3049
%  I s A c c e s s i b l e A n d N o t E m p t y                              %
3050
%                                                                             %
3051
%                                                                             %
3052
%                                                                             %
3053
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3054
%
3055
%  IsAccessibleAndNotEmpty() returns MagickTrue if the file as defined by path
3056
%  exists, is a regular file, and contains at least one byte of data.
3057
%
3058
%  The format of the IsAccessibleAndNotEmpty method is:
3059
%
3060
%      MagickBool IsAccessibleAndNotEmpty(const char *path)
3061
%
3062
%  A description of each parameter follows.
3063
%
3064
%    o status:  Method IsAccessibleAndNotEmpty returns MagickTrue if the file as
3065
%      defined by path exists, is a regular file, and contains content,
3066
%      otherwise MagickFalse is returned.
3067
%
3068
%    o path:  A pointer to an array of characters containing the path.
3069
%
3070
%
3071
*/
3072
MagickExport MagickBool IsAccessibleAndNotEmpty(const char *path)
3073
9.37k
{
3074
9.37k
  int
3075
9.37k
    status;
3076
3077
9.37k
  MagickStatStruct_t
3078
9.37k
    file_info;
3079
3080
9.37k
  if ((path == (const char *) NULL) || (*path == '\0'))
3081
1
    return(MagickFalse);
3082
9.37k
  status=MagickStat(path,&file_info);
3083
3084
9.37k
  if ((status == 0) && S_ISREG(file_info.st_mode) && (file_info.st_size > 0))
3085
9.34k
    return (MagickTrue);
3086
3087
23
  return (MagickFalse);
3088
9.37k
}
3089

3090
/*
3091
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3092
%                                                                             %
3093
%                                                                             %
3094
%                                                                             %
3095
+  I s D i r e c t o r y                                                      %
3096
%                                                                             %
3097
%                                                                             %
3098
%                                                                             %
3099
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3100
%
3101
%  IsDirectory() returns -1 if the path does not exist, 0 if the
3102
%  path represents a file, and 1 if the path represents a directory.
3103
%
3104
%  The format of the IsDirectory method is:
3105
%
3106
%      int IsDirectory(const char *path)
3107
%
3108
%  A description of each parameter follows.
3109
%
3110
%   o  status:  Method IsDirectory returns -1 if the path does not exist,
3111
%      0 if the path represents a file, and 1 if the path represents
3112
%      a directory.
3113
%
3114
%   o  path:  Path to file or directory.
3115
%
3116
%
3117
*/
3118
static int IsDirectory(const char *path)
3119
0
{
3120
0
  MagickStatStruct_t
3121
0
    file_info;
3122
3123
0
  if ((path == (const char *) NULL) || (*path == '\0'))
3124
0
    return(False);
3125
3126
0
  if ((MagickStat(path,&file_info)) == 0)
3127
0
    {
3128
0
      if (S_ISREG(file_info.st_mode))
3129
0
        return 0;
3130
0
      if (S_ISDIR(file_info.st_mode))
3131
0
        return 1;
3132
0
    }
3133
0
  return -1;
3134
0
}
3135

3136
/*
3137
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3138
%                                                                             %
3139
%                                                                             %
3140
%                                                                             %
3141
+     I s G e o m e t r y                                                     %
3142
%                                                                             %
3143
%                                                                             %
3144
%                                                                             %
3145
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3146
%
3147
%  Method IsGeometry returns MagickTrue if the geometry specification is valid
3148
%  as determined by GetGeometry.
3149
%
3150
%  The format of the IsGeometry method is:
3151
%
3152
%      MagickBool IsGeometry(const char *geometry)
3153
%
3154
%  A description of each parameter follows:
3155
%
3156
%    o status: Method IsGeometry returns MagickTrue if the geometry specification
3157
%      is valid otherwise MagickFalse is returned.
3158
%
3159
%    o geometry: This string is the geometry specification.
3160
%
3161
%
3162
*/
3163
MagickExport MagickBool IsGeometry(const char *geometry)
3164
0
{
3165
0
  long
3166
0
    x,
3167
0
    y;
3168
3169
0
  unsigned int
3170
0
    flags;
3171
3172
0
  unsigned long
3173
0
    height,
3174
0
    width;
3175
3176
0
  if (geometry == (const char *) NULL)
3177
0
    return(False);
3178
0
  flags=GetGeometry(geometry,&x,&y,&width,&height);
3179
0
  return(flags != NoValue);
3180
0
}
3181

3182
/*
3183
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3184
%                                                                             %
3185
%                                                                             %
3186
+     I s G l o b                                                             %
3187
%                                                                             %
3188
%                                                                             %
3189
%                                                                             %
3190
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3191
%
3192
%  IsGlob() returns MagickTrue if the path specification contains a globbing
3193
%  pattern as supported by GlobExpression().  Glob patterns supported are
3194
%  roughly equivalent to those supported by POSIX.2 glob().
3195
%
3196
%  The format of the IsGlob method is:
3197
%
3198
%      MagickBool IsGlob(const char *path)
3199
%
3200
%  A description of each parameter follows:
3201
%
3202
%    o status: Returns MagickTrue if the path specification contains
3203
%      a globbing patten.
3204
%
3205
%    o path: The path.
3206
%
3207
%
3208
*/
3209
MagickExport MagickBool IsGlob(const char *path)
3210
24
{
3211
24
  register const char
3212
24
    *p;
3213
3214
24
  MagickBool
3215
24
    status = MagickFalse;
3216
3217
24
  for (p = path; *p != '\0'; p++)
3218
0
    {
3219
0
      switch (*p)
3220
0
        {
3221
0
        case '*':
3222
0
        case '?':
3223
0
        case '{':
3224
0
        case '}':
3225
0
        case '[':
3226
0
        case ']':
3227
0
          {
3228
0
            status = MagickTrue;
3229
0
            break;
3230
0
          }
3231
0
        }
3232
0
    }
3233
3234
24
  return status ;
3235
24
}
3236

3237
/*
3238
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3239
%                                                                             %
3240
%                                                                             %
3241
%                                                                             %
3242
%  I s W r i t a b l e                                                        %
3243
%                                                                             %
3244
%                                                                             %
3245
%                                                                             %
3246
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3247
%
3248
%  IsWritable() returns True if the file as defined by path exists
3249
%  and is writeable by the user.
3250
%
3251
%  The format of the IsWriteable method is:
3252
%
3253
%      MagickBool IsWriteable(const char *path)
3254
%
3255
%  A description of each parameter follows.
3256
%
3257
%    o status:  Method IsWriteable returns MagickTrue if the file as defined
3258
%      by path exists and is writeable by the user, otherwise MagickFalse is
3259
%      returned.
3260
%
3261
%    o path:  A pointer to an array of characters containing the path.
3262
%
3263
%
3264
*/
3265
MagickExport MagickBool IsWriteable(const char *path)
3266
0
{
3267
0
  if ((path == (const char *) NULL) || (*path == '\0'))
3268
0
    return(MagickFalse);
3269
3270
0
  if ((access(path,W_OK)) != 0)
3271
0
    {
3272
0
      return(MagickFalse);
3273
0
    }
3274
0
  return (MagickTrue);
3275
0
}
3276

3277
/*
3278
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3279
%                                                                             %
3280
%                                                                             %
3281
%                                                                             %
3282
%   L i s t F i l e s                                                         %
3283
%                                                                             %
3284
%                                                                             %
3285
%                                                                             %
3286
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3287
%
3288
%  Method ListFiles reads the directory specified and returns a list
3289
%  of filenames contained in the directory sorted in ascending alphabetic
3290
%  order.
3291
%
3292
%  The format of the ListFiles function is:
3293
%
3294
%      char **ListFiles(const char *directory,const char *pattern,
3295
%        long *number_entries)
3296
%
3297
%  A description of each parameter follows:
3298
%
3299
%    o filelist: Method ListFiles returns a list of filenames contained
3300
%      in the directory.  If the directory specified cannot be read or it is
3301
%      a file a NULL list is returned.
3302
%
3303
%    o directory: Specifies a pointer to a text string containing a directory
3304
%      name.
3305
%
3306
%    o pattern: Specifies a pointer to a text string containing a pattern.
3307
%
3308
%    o number_entries:  This integer returns the number of filenames in the
3309
%      list.
3310
%
3311
%
3312
*/
3313
3314
#if defined(__cplusplus) || defined(c_plusplus)
3315
extern "C" {
3316
#endif
3317
3318
static int FileCompare(const void *x,const void *y)
3319
0
{
3320
0
  register char
3321
0
    **p,
3322
0
    **q;
3323
3324
0
  p=(char **) x;
3325
0
  q=(char **) y;
3326
0
  return(LocaleCompare(*p,*q));
3327
0
}
3328
3329
#if defined(__cplusplus) || defined(c_plusplus)
3330
}
3331
#endif
3332
3333
MagickExport char **ListFiles(const char *directory,const char *pattern,
3334
  long *number_entries)
3335
0
{
3336
0
  char
3337
0
    **filelist,
3338
0
    filename[MaxTextExtent];
3339
3340
0
  DIR
3341
0
    *current_directory;
3342
3343
0
  int
3344
0
    status;
3345
3346
0
  struct dirent
3347
0
    *entry;
3348
3349
0
  unsigned int
3350
0
    max_entries;
3351
3352
  /*
3353
    Open directory.
3354
  */
3355
0
  assert(directory != (const char *) NULL);
3356
0
  assert(pattern != (char *) NULL);
3357
0
  assert(number_entries != (long *) NULL);
3358
0
  *number_entries=0;
3359
0
  status=chdir(directory);
3360
0
  if (status != 0)
3361
0
    return((char **) NULL);
3362
0
  if (getcwd(filename,MaxTextExtent-1) == NULL)
3363
0
    MagickFatalError(ConfigureFatalError,UnableToGetCurrentDirectory,
3364
0
                     NULL);
3365
0
  current_directory=opendir(filename);
3366
0
  if (current_directory == (DIR *) NULL)
3367
0
    return((char **) NULL);
3368
0
  if (chdir(filename) != 0)
3369
0
    {
3370
0
      (void) closedir(current_directory);
3371
0
      return((char **) NULL);
3372
0
    }
3373
  /*
3374
    Allocate filelist.
3375
  */
3376
0
  max_entries=2048U;
3377
0
  filelist=MagickAllocateArray(char **,max_entries,sizeof(char *));
3378
0
  if (filelist == (char **) NULL)
3379
0
    {
3380
0
      (void) closedir(current_directory);
3381
0
      return((char **) NULL);
3382
0
    }
3383
  /*
3384
    Save the current and change to the new directory.
3385
  */
3386
0
  entry=readdir(current_directory);
3387
0
  while (entry != (struct dirent *) NULL)
3388
0
  {
3389
0
    if (*entry->d_name == '.')
3390
0
      {
3391
0
        entry=readdir(current_directory);
3392
0
        continue;
3393
0
      }
3394
0
    if ((IsDirectory(entry->d_name) > 0) ||
3395
0
        GlobExpression(entry->d_name,pattern))
3396
0
      {
3397
0
        if (*number_entries >= (int) max_entries)
3398
0
          {
3399
            /*
3400
              Extend the file list.
3401
            */
3402
0
            max_entries<<=1;
3403
0
            MagickReallocMemory(char **,filelist,max_entries*sizeof(char *));
3404
0
            if (filelist == (char **) NULL)
3405
0
              {
3406
0
                (void) closedir(current_directory);
3407
                /*
3408
                  We simply bail here since our memory reallocator has
3409
                  just leaked lots of memory and returning does not
3410
                  solve the problem.
3411
                */
3412
0
                MagickFatalError3(ResourceLimitFatalError,MemoryAllocationFailed,
3413
0
                                  UnableToAllocateString);
3414
0
              }
3415
0
          }
3416
0
        {
3417
0
          size_t
3418
0
            entry_length;
3419
3420
0
          entry_length=strlen(entry->d_name)+1;
3421
0
          if (IsDirectory(entry->d_name) > 0)
3422
0
            entry_length+=strlen(DirectorySeparator);
3423
3424
0
          filelist[*number_entries]=MagickAllocateMemory(char *,entry_length);
3425
0
          if (filelist[*number_entries] == (char *) NULL)
3426
0
            {
3427
0
              break;
3428
0
            }
3429
0
          (void) strlcpy(filelist[*number_entries],entry->d_name,entry_length);
3430
0
          if (IsDirectory(entry->d_name) > 0)
3431
0
            (void) strlcat(filelist[*number_entries],DirectorySeparator,entry_length);
3432
0
        }
3433
0
        (*number_entries)++;
3434
0
      }
3435
0
    entry=readdir(current_directory);
3436
0
  }
3437
0
  (void) closedir(current_directory);
3438
  /*
3439
    Sort filelist in ascending order.
3440
  */
3441
0
  qsort((void *) filelist,*number_entries,sizeof(filelist[0]),FileCompare);
3442
0
  return(filelist);
3443
0
}
3444

3445
/*
3446
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3447
%                                                                             %
3448
%                                                                             %
3449
%                                                                             %
3450
%   L o c a l e C o m p a r e                                                 %
3451
%                                                                             %
3452
%                                                                             %
3453
%                                                                             %
3454
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3455
%
3456
%  Method LocaleCompare performs a case-insensitive comparison of two strings
3457
%  byte-by-byte, according to the ordering of the current locale encoding.
3458
%  LocaleCompare returns an integer greater than, equal to, or less than 0,
3459
%  if the string pointed to by p is greater than, equal to, or less than the
3460
%  string pointed to by q respectively.  The sign of a non-zero return value
3461
%  is determined by the sign of the difference between the values of the first
3462
%  pair of bytes that differ in the strings being compared.
3463
%
3464
%  The format of the LocaleCompare method is:
3465
%
3466
%      int LocaleCompare(const char *p,const char *q)
3467
%
3468
%  A description of each parameter follows:
3469
%
3470
%    o p: A pointer to a character string.
3471
%
3472
%    o q: A pointer to a character string to compare to p.
3473
%
3474
%
3475
*/
3476
MagickExport int LocaleCompare(const char *p,const char *q)
3477
253M
{
3478
253M
  int
3479
253M
    result=0;
3480
3481
253M
  register size_t
3482
253M
    i;
3483
3484
253M
  if (p == (char *) NULL)
3485
0
    result=-1;
3486
253M
  else if (q == (char *) NULL)
3487
104k
    result=1;
3488
252M
  else
3489
385M
    for (i=0; ; i++)
3490
637M
      {
3491
637M
        if (((result=
3492
637M
              AsciiMap[(unsigned int) ((unsigned char *) p)[i] & 0xff] -
3493
637M
              AsciiMap[(unsigned int) ((unsigned char *) q)[i] & 0xff]) != 0)
3494
418M
            || (p[i] == 0) || (q[i] == 0))
3495
252M
          break;
3496
637M
      }
3497
253M
  return result;
3498
253M
}
3499

3500
/*
3501
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3502
%                                                                             %
3503
%                                                                             %
3504
%                                                                             %
3505
%   L o c a l e L o w e r                                                     %
3506
%                                                                             %
3507
%                                                                             %
3508
%                                                                             %
3509
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3510
%
3511
%  Method LocaleLower transforms all of the characters in the supplied
3512
%  null-terminated string, changing all uppercase letters to lowercase.
3513
%
3514
%  The format of the LocaleLower method is:
3515
%
3516
%      void LocaleLower(char *string)
3517
%
3518
%  A description of each parameter follows:
3519
%
3520
%    o string: A pointer to the string to convert to lower-case Locale.
3521
%
3522
%
3523
*/
3524
MagickExport void LocaleLower(char *string)
3525
7.04k
{
3526
7.04k
  register char
3527
7.04k
    *q;
3528
3529
7.04k
  assert(string != (char *) NULL);
3530
197k
  for (q=string; *q != '\0'; q++)
3531
190k
    *q=(char) tolower((int) *q);
3532
7.04k
}
3533

3534
/*
3535
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3536
%                                                                             %
3537
%                                                                             %
3538
%                                                                             %
3539
%   L o c a l e N C o m p a r e                                               %
3540
%                                                                             %
3541
%                                                                             %
3542
%                                                                             %
3543
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3544
%
3545
%  Method LocaleNCompare performs a case-insensitive comparison of two
3546
%  strings byte-by-byte, according to the ordering of the current locale
3547
%  encoding. LocaleNCompare returns an integer greater than, equal to, or
3548
%  less than 0, if the string pointed to by p is greater than, equal to, or
3549
%  less than the string pointed to by q respectively.  The sign of a non-zero
3550
%  return value is determined by the sign of the difference between the
3551
%  values of the first pair of bytes that differ in the strings being
3552
%  compared.  The LocaleNCompare method makes the same comparison as
3553
%  LocaleCompare but looks at a maximum of n bytes.  Bytes following a
3554
%  null byte are not compared.
3555
%
3556
%  The format of the LocaleNCompare method is:
3557
%
3558
%      int LocaleNCompare(const char *p,const char *q,const size_t n)
3559
%
3560
%  A description of each parameter follows:
3561
%
3562
%    o p: A pointer to a character string.
3563
%
3564
%    o q: A pointer to a character string to compare to p.
3565
%
3566
%    o length: The number of characters to compare in strings p & q.
3567
%
3568
%
3569
*/
3570
MagickExport int LocaleNCompare(const char *p,const char *q,const size_t length)
3571
737M
{
3572
737M
  int
3573
737M
    result=0;
3574
3575
737M
  register size_t
3576
737M
    i;
3577
3578
737M
  if (p == (char *) NULL)
3579
0
    result = -1;
3580
737M
  else if (q == (char *) NULL)
3581
0
    result = 1;
3582
737M
  else
3583
815M
    for (i=0; i < length; i++)
3584
813M
      {
3585
813M
        if (((result=
3586
813M
              AsciiMap[(unsigned int) ((unsigned char *) p)[i] & 0xff] -
3587
813M
              AsciiMap[(unsigned int) ((unsigned char *) q)[i] & 0xff]) != 0)
3588
81.7M
            || (p[i] == 0) || (q[i] == 0))
3589
735M
          break;
3590
813M
      }
3591
737M
  return result;
3592
737M
}
3593

3594
/*
3595
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3596
%                                                                             %
3597
%                                                                             %
3598
%                                                                             %
3599
%   L o c a l e U p p e r                                                     %
3600
%                                                                             %
3601
%                                                                             %
3602
%                                                                             %
3603
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3604
%
3605
%  Method LocaleUpper transforms all of the characters in the supplied
3606
%  null-terminated string, changing all lowercase letters to uppercase.
3607
%
3608
%  The format of the LocaleUpper method is:
3609
%
3610
%      void LocaleUpper(char *string)
3611
%
3612
%  A description of each parameter follows:
3613
%
3614
%    o string: A pointer to the string to convert to upper-case Locale.
3615
%
3616
%
3617
*/
3618
MagickExport void LocaleUpper(char *string)
3619
2.25M
{
3620
2.25M
  register char
3621
2.25M
    *q;
3622
3623
2.25M
  assert(string != (char *) NULL);
3624
10.9M
  for (q=string; *q != '\0'; q++)
3625
8.70M
    *q=(char) toupper((int) *q);
3626
2.25M
}
3627

3628
MagickExport MagickPassFail MagickAtoFChk(const char *str, double *value)
3629
5.26M
{
3630
5.26M
  MagickPassFail status = MagickPass;
3631
5.26M
  char *estr=0;
3632
5.26M
  *value=strtod(str,&estr);
3633
5.26M
  if (str == estr)
3634
13.2k
    {
3635
13.2k
      *value=0.0;
3636
13.2k
      status=MagickFail;
3637
13.2k
    }
3638
5.24M
#if defined(INFINITY)
3639
5.24M
  else if ((*value == +INFINITY) || (*value == -INFINITY))
3640
2.42k
    {
3641
2.42k
      *value=0.0;
3642
2.42k
      status=MagickFail;
3643
2.42k
      errno=ERANGE;
3644
2.42k
    }
3645
5.24M
#endif
3646
5.24M
  else if (isnan(*value))
3647
222
    {
3648
222
      *value=0.0;
3649
222
      status=MagickFail;
3650
222
      errno=ERANGE;
3651
222
    }
3652
5.26M
  return status;
3653
5.26M
}
3654

3655
MagickExport MagickPassFail MagickAtoIChk(const char *str, int *value)
3656
0
{
3657
0
  MagickPassFail status = MagickPass;
3658
0
  char *estr=0;
3659
0
  long lvalue;
3660
0
  lvalue=strtol(str,&estr, 10);
3661
0
  if (str == estr)
3662
0
    {
3663
0
      lvalue=0;
3664
0
      status=MagickFail;
3665
0
      errno=EINVAL;
3666
0
    }
3667
0
  else if ((int) lvalue != lvalue)
3668
0
    {
3669
0
      lvalue=0;
3670
0
      status=MagickFail;
3671
0
      errno=ERANGE;
3672
0
    }
3673
0
  *value=(int) lvalue;
3674
0
  return status;
3675
0
}
3676

3677
MagickExport MagickPassFail MagickAtoUIChk(const char *str, unsigned int *value)
3678
147k
{
3679
147k
  MagickPassFail status = MagickPass;
3680
147k
  char *estr=0;
3681
147k
  long lvalue;
3682
147k
  lvalue=strtol(str,&estr, 10);
3683
147k
  if (str == estr)
3684
79
    {
3685
79
      lvalue=0U;
3686
79
      status=MagickFail;
3687
79
      errno=EINVAL;
3688
79
    }
3689
147k
  else if ((long) ((unsigned int) lvalue) != lvalue)
3690
132
    {
3691
132
      lvalue=0U;
3692
132
      status=MagickFail;
3693
132
      errno=ERANGE;
3694
132
    }
3695
147k
  *value=(unsigned int) lvalue;
3696
147k
  return status;
3697
147k
}
3698

3699
MagickExport MagickPassFail MagickAtoLChk(const char *str, long *value)
3700
0
{
3701
0
  char *estr=0;
3702
0
  *value=strtol(str,&estr, 10);
3703
0
  if (str == estr)
3704
0
    *value=0L;
3705
0
  return (str == estr ? MagickFail : MagickPass);
3706
0
}
3707

3708
MagickExport MagickPassFail MagickAtoULChk(const char *str, unsigned long *value)
3709
5.80k
{
3710
5.80k
  MagickPassFail status = MagickPass;
3711
5.80k
  char *estr=0;
3712
5.80k
  long lvalue;
3713
5.80k
  lvalue=strtol(str,&estr, 10);
3714
5.80k
  if (str == estr)
3715
24
    {
3716
24
      lvalue=0L;
3717
24
      status=MagickFail;
3718
24
      errno=EINVAL;
3719
24
    }
3720
5.77k
  else if ((long) ((unsigned long) lvalue) != lvalue)
3721
0
    {
3722
0
      lvalue=0L;
3723
0
      status=MagickFail;
3724
0
      errno=ERANGE;
3725
0
    }
3726
5.80k
  *value=(unsigned long) lvalue;
3727
5.80k
  return status;
3728
5.80k
}
3729

3730
/*
3731
  Access to the 'long long' type is assured by C'99
3732
*/
3733
MagickExport MagickPassFail MagickAtoULLChk(const char *str, unsigned long long *value)
3734
0
{
3735
0
  MagickPassFail status = MagickPass;
3736
0
  char *estr=0;
3737
0
  long long lvalue;
3738
0
  lvalue=strtoll(str,&estr, 10);
3739
0
  if (str == estr)
3740
0
    {
3741
0
      lvalue=0L;
3742
0
      status=MagickFail;
3743
0
      errno=EINVAL;
3744
0
    }
3745
0
  else if ((long long) ((unsigned long long) lvalue) != lvalue)
3746
0
    {
3747
0
      lvalue=0LL;
3748
0
      status=MagickFail;
3749
0
      errno=ERANGE;
3750
0
    }
3751
0
  *value=(unsigned long long) lvalue;
3752
0
  return status;
3753
0
}
3754

3755
/*
3756
  Convert a double to a long, with clipping.
3757
  Someday a warning or an error may be produced here.
3758
*/
3759
MagickExport long MagickDoubleToLong(const double dval/*, ExceptionInfo *exception*/)
3760
21.0M
{
3761
21.0M
  long lval;
3762
3763
21.0M
  do
3764
21.0M
    {
3765
21.0M
#if defined(INFINITY)
3766
21.0M
      if (dval == +INFINITY)
3767
0
        {
3768
0
          lval=LONG_MAX;
3769
0
          break;
3770
0
        }
3771
21.0M
      if (dval == -INFINITY)
3772
0
        {
3773
0
          lval=LONG_MIN;
3774
0
          break;
3775
0
        }
3776
21.0M
#endif
3777
21.0M
      if (isnan(dval))
3778
0
        {
3779
0
          lval=0;
3780
0
          break;
3781
0
        }
3782
21.0M
      if (floor(dval) > ((double) LONG_MAX - 1))
3783
0
        {
3784
0
          lval=LONG_MAX;
3785
0
          break;
3786
0
        }
3787
21.0M
      if (ceil(dval) < ((double) LONG_MIN + 1))
3788
0
        {
3789
0
          lval=LONG_MIN;
3790
0
          break;
3791
0
        }
3792
21.0M
      lval=(long) dval;
3793
21.0M
    } while (0);
3794
3795
21.0M
  return lval;
3796
21.0M
}
3797

3798
/*
3799
  Convert a double to an int, with clipping.
3800
  Someday a warning or an error may be produced here.
3801
*/
3802
MagickExport int MagickDoubleToInt(const double dval/*, ExceptionInfo *exception*/)
3803
0
{
3804
0
  int lval;
3805
3806
0
  do
3807
0
    {
3808
0
#if defined(INFINITY)
3809
0
      if (dval == +INFINITY)
3810
0
        {
3811
0
          lval=INT_MAX;
3812
0
          break;
3813
0
        }
3814
0
      if (dval == -INFINITY)
3815
0
        {
3816
0
          lval=INT_MIN;
3817
0
          break;
3818
0
        }
3819
0
#endif
3820
0
      if (isnan(dval))
3821
0
        {
3822
0
          lval=0;
3823
0
          break;
3824
0
        }
3825
0
      if (floor(dval) > ((double) INT_MAX - 1))
3826
0
        {
3827
0
          lval=INT_MAX;
3828
0
          break;
3829
0
        }
3830
0
      if (ceil(dval) < ((double) INT_MIN + 1))
3831
0
        {
3832
0
          lval=INT_MIN;
3833
0
          break;
3834
0
        }
3835
0
      lval=(int) dval;
3836
0
    } while (0);
3837
3838
0
  return lval;
3839
0
}
3840

3841
/*
3842
  Convert a double to an unsigned long, with clipping.
3843
  Someday a warning or an error may be produced here.
3844
*/
3845
MagickExport unsigned long MagickDoubleToULong(const double dval/*, ExceptionInfo *exception*/)
3846
0
{
3847
0
  unsigned long lval;
3848
3849
0
  do
3850
0
    {
3851
0
#if defined(INFINITY)
3852
0
      if (dval == +INFINITY)
3853
0
        {
3854
0
          lval=ULONG_MAX;
3855
0
          break;
3856
0
        }
3857
0
      if (dval == -INFINITY)
3858
0
        {
3859
0
          lval=0;
3860
0
          break;
3861
0
        }
3862
0
#endif
3863
0
      if (isnan(dval))
3864
0
        {
3865
0
          lval=0;
3866
0
          break;
3867
0
        }
3868
0
      if (floor(dval) > ((double) ULONG_MAX - 1))
3869
0
        {
3870
0
          lval=ULONG_MAX;
3871
0
          break;
3872
0
        }
3873
0
      if (ceil(dval) < 0.0)
3874
0
        {
3875
0
          lval=0;
3876
0
          break;
3877
0
        }
3878
0
      lval=(unsigned long) dval;
3879
0
    } while (0);
3880
3881
0
  return lval;
3882
0
}
3883

3884
/*
3885
  Convert a double to an unsigned int, with clipping.
3886
  Someday a warning or an error may be produced here.
3887
*/
3888
MagickExport unsigned int MagickDoubleToUInt(const double dval/*, ExceptionInfo *exception*/)
3889
144
{
3890
144
  unsigned int lval;
3891
3892
144
  do
3893
144
    {
3894
144
#if defined(INFINITY)
3895
144
      if (dval == +INFINITY)
3896
0
        {
3897
0
          lval=UINT_MAX;
3898
0
          break;
3899
0
        }
3900
144
      if (dval == -INFINITY)
3901
0
        {
3902
0
          lval=0;
3903
0
          break;
3904
0
        }
3905
144
#endif
3906
144
      if (isnan(dval))
3907
0
        {
3908
0
          lval=0;
3909
0
          break;
3910
0
        }
3911
144
      if (floor(dval) > ((double) UINT_MAX - 1))
3912
25
        {
3913
25
          lval=UINT_MAX;
3914
25
          break;
3915
25
        }
3916
119
      if (ceil(dval) < 0.0)
3917
0
        {
3918
0
          lval=0;
3919
0
          break;
3920
0
        }
3921
119
      lval=(unsigned int) dval;
3922
119
    } while (0);
3923
3924
144
  return lval;
3925
144
}
3926

3927
/*
3928
  Convert a double to a short, with clipping.
3929
  Someday a warning or an error may be produced here.
3930
*/
3931
MagickExport short int MagickDoubleToShort(const double dval/*, ExceptionInfo *exception*/)
3932
0
{
3933
0
  short int lval;
3934
3935
0
  do
3936
0
    {
3937
0
#if defined(INFINITY)
3938
0
      if (dval == +INFINITY)
3939
0
        {
3940
0
          lval=SHRT_MAX;
3941
0
          break;
3942
0
        }
3943
0
      if (dval == -INFINITY)
3944
0
        {
3945
0
          lval=SHRT_MIN;
3946
0
          break;
3947
0
        }
3948
0
#endif
3949
0
      if (isnan(dval))
3950
0
        {
3951
0
          lval=0;
3952
0
          break;
3953
0
        }
3954
0
      if (floor(dval) > ((double) SHRT_MAX - 1))
3955
0
        {
3956
0
          lval=SHRT_MAX;
3957
0
          break;
3958
0
        }
3959
0
      if (ceil(dval) < ((double) SHRT_MIN + 1))
3960
0
        {
3961
0
          lval=SHRT_MIN;
3962
0
          break;
3963
0
        }
3964
0
      lval=(short int) dval;
3965
0
    } while (0);
3966
3967
0
  return lval;
3968
0
}
3969

3970
/*
3971
  Convert a double to an unsigned short, with clipping.
3972
  Someday a warning or an error may be produced here.
3973
*/
3974
MagickExport unsigned short int MagickDoubleToUShort(const double dval/*, ExceptionInfo *exception*/)
3975
0
{
3976
0
  unsigned short int lval;
3977
3978
0
  do
3979
0
    {
3980
0
#if defined(INFINITY)
3981
0
      if (dval == +INFINITY)
3982
0
        {
3983
0
          lval=USHRT_MAX;
3984
0
          break;
3985
0
        }
3986
0
      if (dval == -INFINITY)
3987
0
        {
3988
0
          lval=0;
3989
0
          break;
3990
0
        }
3991
0
#endif
3992
0
      if (isnan(dval))
3993
0
        {
3994
0
          lval=0;
3995
0
          break;
3996
0
        }
3997
0
      if (floor(dval) > ((double) USHRT_MAX - 1))
3998
0
        {
3999
0
          lval=USHRT_MAX;
4000
0
          break;
4001
0
        }
4002
0
      if (ceil(dval) < 0.0)
4003
0
        {
4004
0
          lval=0;
4005
0
          break;
4006
0
        }
4007
0
      lval=(unsigned short int) dval;
4008
0
    } while (0);
4009
4010
0
  return lval;
4011
0
}
4012

4013
/*
4014
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4015
%                                                                             %
4016
%                                                                             %
4017
%                                                                             %
4018
%  M a g i c k F m i n                                                        %
4019
%                                                                             %
4020
%                                                                             %
4021
%                                                                             %
4022
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4023
%
4024
%  Method MagickFmin emulates C'99 fmin(), which returns the minimum of two
4025
%  double values.  This is implemented as a function rather than a macro.
4026
%
4027
%  The format of the MagickFmin method is:
4028
%
4029
%      double MagickFmin(const double x, const double y)
4030
%
4031
%  A description of each parameter follows.
4032
%
4033
%   o  x: first input value
4034
%
4035
%   o  y: second input value
4036
%
4037
%   o  returns: minimum of values x or y
4038
%
4039
%
4040
*/
4041
double MagickFmin(const double x, const double y)
4042
0
{
4043
0
  return Min(x,y);
4044
0
}
4045

4046
/*
4047
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4048
%                                                                             %
4049
%                                                                             %
4050
%                                                                             %
4051
%  M a g i c k F m a x                                                        %
4052
%                                                                             %
4053
%                                                                             %
4054
%                                                                             %
4055
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4056
%
4057
%  Method MagickFmax emulates C'99 fmax(), which returns the maximum of two
4058
%  double values.  This is implemented as a function rather than a macro.
4059
%
4060
%  The format of the MagickFmax method is:
4061
%
4062
%      double MagickFmax(const double x, const double y)
4063
%
4064
%  A description of each parameter follows.
4065
%
4066
%   o  x: first input value
4067
%
4068
%   o  y: second input value
4069
%
4070
%   o  returns: maximum of values x or y
4071
%
4072
%
4073
*/
4074
double MagickFmax(const double x, const double y)
4075
0
{
4076
0
  return Max(x,y);
4077
0
}
4078

4079
/*
4080
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4081
%                                                                             %
4082
%                                                                             %
4083
%                                                                             %
4084
%  M a g i c k F o r m a t S t r i n g                                        %
4085
%                                                                             %
4086
%                                                                             %
4087
%                                                                             %
4088
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4089
%
4090
%  Method MagickFormatString prints formatted output of a variable
4091
%  argument list buffer, limiting its output to a specified buffer size.
4092
%  The formatted size (as would be returned by strlen()) is returned.
4093
%
4094
%  The format of the MagickFormatString method is:
4095
%
4096
%      size_t MagickFormatString(char *string,const size_t length,
4097
%                                const char *format,...)
4098
%
4099
%  A description of each parameter follows.
4100
%
4101
%   o  string:  Method FormatString returns the formatted string in this
4102
%      character buffer. Buffer must be at least MaxTextExtent characters
4103
%      in size.
4104
%
4105
%   o  length:  Maximum number of characters to write into buffer, not
4106
%      including a terminating null byte.  The result is always terminated
4107
%      with a null byte.
4108
%
4109
%   o  format:  A string describing the format to use to write the remaining
4110
%      arguments.
4111
%
4112
%
4113
*/
4114
MagickExport size_t MagickFormatStringList(char *string,
4115
                                           const size_t length,
4116
                                           const char *format,
4117
                                           va_list operands)
4118
351M
{
4119
351M
  size_t
4120
351M
    fls = 0;
4121
4122
351M
  int
4123
351M
    fli;
4124
4125
351M
  if (length > 0)
4126
351M
    {
4127
351M
#if defined(HAVE_VSNPRINTF)
4128
351M
      fli=vsnprintf(string,length,format,operands);
4129
#else
4130
      fli=vsprintf(string,format,operands);
4131
#endif
4132
351M
      if (fli > 0)
4133
351M
        {
4134
351M
          if ((size_t) fli >= length)
4135
2
            fls=length-1;
4136
351M
          else
4137
351M
            fls=(size_t) fli;
4138
351M
        }
4139
351M
    }
4140
351M
  return fls;
4141
351M
}
4142
MagickExport size_t MagickFormatString(char *string,
4143
                                       const size_t length,
4144
                                       const char *format,...)
4145
338M
{
4146
338M
  va_list
4147
338M
    operands;
4148
4149
338M
  size_t
4150
338M
    formatted_len;
4151
4152
#if 0
4153
  assert(length > sizeof(char *)); /* Catch code update errors */
4154
#endif
4155
338M
  va_start(operands,format);
4156
338M
  formatted_len=MagickFormatStringList(string, length, format, operands);
4157
338M
  va_end(operands);
4158
338M
  return formatted_len;
4159
338M
}
4160

4161
/*
4162
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4163
%                                                                             %
4164
%                                                                             %
4165
%                                                                             %
4166
+   M a g i c k G e t T o k e n                                               %
4167
%                                                                             %
4168
%                                                                             %
4169
%                                                                             %
4170
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4171
%
4172
%  Method MagickGetToken gets a token from the token stream given a
4173
%  NUL-terminated buffer.  A token is defined as sequence of characters
4174
%  delimited by whitespace (e.g. clip-path), a sequence delimited with
4175
%  quotes (.e.g "Quote me"), or a sequence enclosed in parenthesis
4176
%  (e.g. rgb(0,0,0)).
4177
%
4178
%  The format of the MagickGetToken method is:
4179
%
4180
%      size_t MagickGetToken(const char *start,char **end,char *token,
4181
%                            const size_t max_token_length)
4182
%
4183
%  A description of each parameter follows:
4184
%
4185
%    o start: the start of the token sequence in a NUL-terminated buffer.
4186
%
4187
%    o end: points to the end of the scanned token sequence (may be NULL).
4188
%
4189
%    o token: copy the token to this buffer.
4190
%
4191
%    o max_token_length: maximum token length which may be returned.
4192
%     If the token exceeds the maximum token size,
4193
%     then the token will be truncated, but the parser will still
4194
%     update the end pointer (constrained by the terminating NUL
4195
%     character) as if the truncation did not occur. This allows
4196
%     using the end pointer as start when scanning a next token.
4197
%
4198
%    o returns: The size of the token returned.
4199
%
4200
%      This function used to "Report the size of the consumed token,
4201
%      not including a terminating null character.  If this is
4202
%      larger or equal to the buffer size then truncation has
4203
%      occurred". The old behavior is not useful given that
4204
%      the difference between 'end' and 'start' may be used to
4205
%      determine how many characters were consumed.
4206
%
4207
*/
4208
MagickExport size_t MagickGetToken(const char *start,char **end,char *token,
4209
                                   const size_t max_token_length)
4210
13.2M
{
4211
13.2M
  register const char
4212
13.2M
    *p;
4213
4214
13.2M
  register size_t
4215
13.2M
    i;
4216
4217
13.2M
  register size_t
4218
13.2M
    length = max_token_length - 1;
4219
4220
13.2M
  double
4221
13.2M
    double_val;
4222
4223
13.2M
  assert(start != (const char *) NULL);
4224
13.2M
  assert(token != (char *) NULL);
4225
4226
13.2M
  i=0;
4227
13.2M
  token[i]='\0';
4228
13.2M
  p=start;
4229
4230
13.2M
  if (*p != '\0')
4231
12.9M
    {
4232
22.7M
      while (isspace((int)(unsigned char) (*p)) && (*p != '\0'))
4233
9.80M
        p++;
4234
12.9M
      switch (*p)
4235
12.9M
        {
4236
8.32k
        case '"':
4237
457k
        case '\'':
4238
522k
        case '{':
4239
522k
          {
4240
522k
            register char
4241
522k
              escape;
4242
4243
522k
            escape=(*p);
4244
522k
            if (escape == '{')
4245
64.6k
              escape='}';
4246
197M
            for (p++; *p != '\0'; p++)
4247
197M
              {
4248
197M
                if ((*p == '\\') && ((*(p+1) == escape) || (*(p+1) == '\\')))
4249
106k
                  p++;
4250
197M
                else
4251
197M
                  if (*p == escape)
4252
494k
                    {
4253
494k
                      p++;
4254
494k
                      break;
4255
494k
                    }
4256
197M
                if (i < length)
4257
197M
                  token[i++]=(*p);
4258
197M
              }
4259
522k
            break;
4260
457k
          }
4261
12.4M
        default:
4262
12.4M
          {
4263
12.4M
            char
4264
12.4M
              *q;
4265
4266
12.4M
            double_val=strtod(p,&q);
4267
12.4M
            (void) double_val;
4268
12.4M
            if (p != q)
4269
6.93M
              {
4270
33.5M
                for ( ; p < q; p++)
4271
26.6M
                  if (i < length)
4272
26.5M
                    token[i++]=(*p);
4273
6.93M
                if (*p == '%')
4274
176k
                  if (i < length)
4275
176k
                    {
4276
176k
                      token[i++]=(*p);
4277
176k
                      p++;
4278
176k
                    }
4279
6.93M
                break;
4280
6.93M
              }
4281
5.50M
            if ((*p != '\0') && !isalpha((int) *p) &&
4282
1.84M
                (*p != *DirectorySeparator) &&
4283
1.83M
                (*p != '#') && (*p != '<'))
4284
1.55M
              {
4285
1.55M
                if (i < length)
4286
1.55M
                  {
4287
1.55M
                    token[i++]=(*p);
4288
1.55M
                    p++;
4289
1.55M
                  }
4290
1.55M
                break;
4291
1.55M
              }
4292
48.3M
            for ( ; *p != '\0'; p++)
4293
48.2M
              {
4294
48.2M
                if ((isspace((int)(unsigned char) *p) ||
4295
44.4M
                     (*p == '=')) && (*(p-1) != '\\'))
4296
3.79M
                  break;
4297
44.4M
                if (i < length)
4298
44.2M
                  token[i++]=(*p);
4299
44.4M
                if (*p == '(')
4300
21.0k
                  {
4301
6.52M
                    for (p++; *p != '\0'; p++)
4302
6.51M
                      {
4303
6.51M
                        if (i < length)
4304
6.29M
                          token[i++]=(*p);
4305
6.51M
                        if ((*p == ')') && (*(p-1) != '\\'))
4306
16.5k
                          break;
4307
6.51M
                      }
4308
21.0k
                  }
4309
44.4M
                if (*p == '\0')
4310
4.45k
                  break;
4311
44.4M
              }
4312
3.95M
            break;
4313
5.50M
          }
4314
12.9M
        }
4315
12.9M
    }
4316
13.2M
  token[i]='\0';
4317
13.2M
  {
4318
13.2M
    char
4319
13.2M
      *r;
4320
4321
    /*
4322
      Parse token in form "url(#%s)"
4323
    */
4324
13.2M
    if ((LocaleNCompare(token,"url(#",5) == 0) &&
4325
18.0k
        ((r = strrchr(token,')')) != NULL))
4326
16.9k
      {
4327
16.9k
        *r='\0';
4328
16.9k
        (void) memmove(token,token+5,r-token-4);
4329
16.9k
      }
4330
13.2M
  }
4331
13.2M
  if (end != (char **) NULL)
4332
12.6M
    *end=(char *)p;
4333
13.2M
  return (i); /* Was (p-start+1) to report consumed text */
4334
13.2M
}
4335

4336
/*
4337
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4338
%                                                                             %
4339
%                                                                             %
4340
%                                                                             %
4341
%   M a g i c k R a n d R e e n t r a n t                                     %
4342
%                                                                             %
4343
%                                                                             %
4344
%                                                                             %
4345
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4346
%
4347
%  Method MagickRandReentrant() is a reentrant version of the standard
4348
%  rand() function but which allows the user to pass a pointer to the
4349
%  'seed'.  Values returned are in the range of 0 - RAND_MAX.
4350
%
4351
%  This function is deprecated, and scheduled for eventual removal.
4352
%
4353
%  The format of the MagickRandReentrant method is:
4354
%
4355
%      int MagickRandReentrant(unsigned int *seed)
4356
%
4357
%  A description of each parameter follows:
4358
%
4359
%    o seed: The random sequence seed value.  Initialized by the user
4360
%            once (e.g. with output from MagickRandNewSeed()) and then
4361
%            passed via pointer thereafter.  If seed is NULL then
4362
%            this function behaves identically to rand(), using the
4363
%            global seed value set via srand().
4364
%
4365
*/
4366
MagickExport int MagickRandReentrant(unsigned int *seed)
4367
0
{
4368
0
  ARG_NOT_USED(seed);
4369
4370
0
  return (int) ((double) RAND_MAX*MagickRandomReal()+0.5);
4371
0
}
4372

4373
/*
4374
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4375
%                                                                             %
4376
%                                                                             %
4377
%                                                                             %
4378
%   M a g i c k R a n d N e w S e e d                                         %
4379
%                                                                             %
4380
%                                                                             %
4381
%                                                                             %
4382
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4383
%
4384
%  Method MagickRandNewSeed() returns a semi-random initial seed value for
4385
%  use with MagickRandReentrant() or rand().
4386
%
4387
%  This function is deprecated, and scheduled for eventual removal.
4388
%
4389
%  The format of the MagickRandNewSeed method is:
4390
%
4391
%      unsigned int MagickRandNewSeed(void)
4392
%
4393
*/
4394
MagickExport unsigned int MagickRandNewSeed(void)
4395
0
{
4396
0
  return (unsigned int) MagickRandomInteger();
4397
0
}
4398

4399
/*
4400
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4401
%                                                                             %
4402
%                                                                             %
4403
%                                                                             %
4404
%   M a g i c k S i z e S t r T o I n t 6 4                                   %
4405
%                                                                             %
4406
%                                                                             %
4407
%                                                                             %
4408
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4409
%
4410
%  MagickSizeStrToInt64() converts a numeric string expressed using a scaling
4411
%  suffix (e.g. "100K" is 100 kilo) to a 64-bit integer type.  Even though
4412
%  this function returns a signed type, it is intended to be used to obtain
4413
%  positive size values so a negative return value indicates an error.
4414
%  Specifically, -1 is returned if there is known to be an conversion error.
4415
%
4416
%  Binary Prefixes: http://en.wikipedia.org/wiki/Binary_prefix
4417
%
4418
%  SI Prefixes: http://en.wikipedia.org/wiki/SI_prefix
4419
%
4420
%  The format of the MagickSizeStrToInt64 method is:
4421
%
4422
%      magick_int64_t MagickSizeStrToInt64(const char *str,
4423
%                                          const unsigned int kilo)
4424
%
4425
%  A description of each parameter follows:
4426
%
4427
%    o str: Input string to convert
4428
%
4429
%    o kilo: The unit of "kilo".  Should be either 1000 (SI units)
4430
%            or 1024 (Binary units).
4431
%
4432
*/
4433
MagickExport magick_int64_t MagickSizeStrToInt64(const char *str,
4434
                                                 const unsigned int kilo)
4435
0
{
4436
0
  char
4437
0
    *end;
4438
4439
0
  magick_int64_t
4440
0
    result;
4441
4442
0
  MagickPassFail
4443
0
    status;
4444
4445
0
  result=-1;
4446
0
  end=(char *) NULL;
4447
0
  if ((status=MagickStrToInt64(str,&end,&result)) == MagickPass)
4448
0
    {
4449
0
      int
4450
0
        c,
4451
0
        mult;
4452
4453
0
      c='\0';
4454
0
      if (end != (char *) NULL)
4455
0
        c=*end;
4456
0
      mult=0;
4457
4458
0
      switch (tolower(c))
4459
0
        {
4460
0
        default: break;
4461
0
        case 'k': mult=1; break; /* kilo, 10^3 */
4462
0
        case 'm': mult=2; break; /* mega, 10^6 */
4463
0
        case 'g': mult=3; break; /* giga, 10^9 */
4464
0
        case 't': mult=4; break; /* tera, 10^12 */
4465
0
        case 'p': mult=5; break; /* peta, 10^15 */
4466
0
        case 'e': mult=6; break; /* exa,  10^18 */
4467
0
        }
4468
4469
0
      while (mult-- > 0)
4470
0
        result *= kilo;
4471
0
    }
4472
4473
0
  return result;
4474
0
}
4475

4476
/*
4477
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4478
%                                                                             %
4479
%                                                                             %
4480
%                                                                             %
4481
%   M a g i c k S p a w n V P                                                 %
4482
%                                                                             %
4483
%                                                                             %
4484
%                                                                             %
4485
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4486
%
4487
%  MagickSpawnVP() executes an external command with arguments provided by
4488
%  an argument vector.  The return status of the executed command is returned
4489
%  if it is executed, or -1 is returned if the command could not be executed.
4490
%  Executed commands will normally return zero if they execute without error.
4491
%
4492
%  The format of the MagickSpawnVP method is:
4493
%
4494
%      int MagickSpawnVP(const char *file, char *const argv[])
4495
%
4496
%  A description of each parameter follows:
4497
%
4498
%    o file:  Name of the command to execute.
4499
%
4500
%    o argv:  Argument vector. First argument in the vector should be
4501
%             the name of the command.  The argument vector is terminated
4502
%             via a NULL pointer.
4503
%
4504
*/
4505
MagickExport int
4506
MagickSpawnVP(const unsigned int verbose,const char *file, char *const argv[])
4507
0
{
4508
0
  int
4509
0
    status;
4510
4511
0
  char
4512
0
    message[MaxTextExtent];
4513
4514
4515
0
  status = -1;
4516
0
  message[0]='\0';
4517
0
  errno=0;
4518
4519
0
  assert(file != (const char *) NULL);
4520
4521
0
  if (strlen(file) == 0)
4522
0
    return -1;
4523
4524
0
  {
4525
    /*
4526
      Verify that we are allowed to run this program.
4527
    */
4528
0
    ExceptionInfo
4529
0
      exception;
4530
4531
0
    GetExceptionInfo(&exception);
4532
0
    if (MagickConfirmAccess(FileExecuteConfirmAccessMode,argv[0],&exception)
4533
0
        == MagickFail)
4534
0
      {
4535
0
        errno=EPERM;
4536
0
        DestroyExceptionInfo(&exception);
4537
0
        return -1;
4538
0
      }
4539
0
  }
4540
4541
#if defined(HAVE_SPAWNVP)
4542
  {
4543
    /* int spawnvp(int mode, const char *path, const char * const *argv); */
4544
#if defined(__MINGW64_VERSION_MAJOR)
4545
    /* MinGW-w64 prototype is lacking */
4546
    status = spawnvp(_P_WAIT, file, (char * const *) argv);
4547
#else
4548
    status = spawnvp(_P_WAIT, file, (const char * const *) argv);
4549
#endif
4550
  }
4551
#else
4552
0
  {
4553
0
    pid_t
4554
0
      child_pid;
4555
4556
0
    child_pid = fork( );
4557
0
    if ( (pid_t)-1 == child_pid)
4558
0
      {
4559
        /* Failed to fork, errno contains reason */
4560
0
        status = -1;
4561
0
        MagickFormatString(message,sizeof(message),"fork failed: %.1024s", strerror(errno));
4562
0
      }
4563
0
    else if ( 0 == child_pid )
4564
0
      {
4565
        /* We are the child process, exec program with arguments. */
4566
0
        status = execvp(file, argv);
4567
4568
        /* If we get here, then execvp must have failed. */
4569
0
        (void) fprintf(stderr, "execvp failed, errno = %d (%s)\n",errno,strerror(errno));
4570
4571
        /* If there is an execvp error, then call _exit() */
4572
0
        _exit(1);
4573
0
      }
4574
0
    else
4575
0
      {
4576
        /* We are the parent process, wait for child. */
4577
0
        pid_t waitpid_status;
4578
0
        int child_status = 0;
4579
0
        waitpid_status = waitpid(child_pid, &child_status, 0);
4580
0
        if ( (pid_t)-1 == waitpid_status )
4581
0
          {
4582
            /* Waitpid error */
4583
0
            status = -1;
4584
0
            MagickFormatString(message, sizeof(message), "waitpid failed: %.1024s", strerror(errno));
4585
0
          }
4586
0
        else if ( waitpid_status == child_pid )
4587
0
          {
4588
            /* Status is available for child process */
4589
0
            if ( WIFEXITED( child_status ) )
4590
0
              {
4591
0
                status =  WEXITSTATUS( child_status );
4592
0
              }
4593
0
            else if ( WIFSIGNALED( child_status ) )
4594
0
              {
4595
0
                int sig_num = WTERMSIG( child_status );
4596
0
                status = -1;
4597
0
                MagickFormatString(message, sizeof(message), "child process quit due to signal %d", sig_num);
4598
0
              }
4599
0
          }
4600
0
      }
4601
0
  }
4602
0
#endif
4603
4604
  /*
4605
    Provide a verbose/dignostic message in a form which is easy for
4606
    the user to understand.
4607
  */
4608
0
  if (verbose || (status != 0))
4609
0
    {
4610
0
      const char
4611
0
        *message_p = (const char *) NULL;
4612
4613
0
      char
4614
0
        *command;
4615
4616
0
      unsigned int
4617
0
        i;
4618
4619
0
      command = AllocateString((const char*) NULL);
4620
0
      for (i = 0; argv[i] != (const char*) NULL; i++)
4621
0
        {
4622
0
          char
4623
0
            buffer[MaxTextExtent];
4624
4625
0
          MagickFormatString(buffer,sizeof(buffer),"\"%.1024s\"", argv[i]);
4626
4627
0
          if (0 != i)
4628
0
            (void) ConcatenateString(&command," ");
4629
4630
0
          (void) ConcatenateString(&command,buffer);
4631
0
        }
4632
0
      if (message[0] != '\0')
4633
0
        message_p = message;
4634
0
      MagickError2(DelegateError,command,message_p);
4635
0
      MagickFreeMemory(command);
4636
0
    }
4637
4638
0
  return status;
4639
0
}
4640

4641
/*
4642
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4643
%                                                                             %
4644
%                                                                             %
4645
%                                                                             %
4646
%   M a g i c k S t r i p S t r i n g                                        %
4647
%                                                                             %
4648
%                                                                             %
4649
%                                                                             %
4650
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4651
%
4652
%  Method MagickStripString strips any whitespace or quotes from the
4653
%  beginning and end of a string of characters.  The final string length
4654
%  is returned.
4655
%
4656
%  The format of the _MagickStripString method is:
4657
%
4658
%      size_t _MagickStripString(char *message)
4659
%
4660
%  A description of each parameter follows:
4661
%
4662
%    o message: Specifies an array of characters.
4663
%
4664
%
4665
*/
4666
MagickExport size_t MagickStripString(char *message)
4667
7.14M
{
4668
7.14M
  register char
4669
7.14M
    *p,
4670
7.14M
    *q;
4671
4672
7.14M
  assert(message != (char *) NULL);
4673
7.14M
  if (*message == '\0')
4674
879k
    return 0;
4675
6.26M
  if (strlen(message) == 1)
4676
85.3k
    return 1;
4677
6.18M
  p=message;
4678
6.18M
  while (isspace((int)(unsigned char) (*p)))
4679
1.97M
    p++;
4680
6.18M
  if ((*p == '\'') || (*p == '"'))
4681
6.08k
    p++;
4682
6.18M
  q=message+strlen(message)-1;
4683
6.21M
  while (isspace((int)(unsigned char) (*q)) && (q > p))
4684
31.6k
    q--;
4685
6.18M
  if (q > p)
4686
6.16M
    if ((*q == '\'') || (*q == '"'))
4687
1.74M
      q--;
4688
6.18M
  (void) memmove(message,p,q-p+1);
4689
6.18M
  message[q-p+1]='\0';
4690
6.18M
  return (size_t) (q-p+1);
4691
6.26M
}
4692

4693
/*
4694
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4695
%                                                                             %
4696
%                                                                             %
4697
%                                                                             %
4698
%   M a g i c k S t r i p S p a c e s F r o m S t r i n g                     %
4699
%                                                                             %
4700
%                                                                             %
4701
%                                                                             %
4702
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4703
%
4704
%  MagickStripSpacesFromString() compacts a NULL-terminated string in-place
4705
%  by removing white space (space and tab) characters) from a string.
4706
%
4707
%  The format of the MagickStripSpacesFromString method is:
4708
%
4709
%      size_t MagickStripSpacesFromString(char *string)
4710
%
4711
%  A description of each parameter follows:
4712
%
4713
%    o string: String buffer to compact.
4714
%
4715
%    o returns: New string length
4716
%
4717
*/
4718
MagickExport size_t
4719
MagickStripSpacesFromString(char *string)
4720
0
{
4721
0
  register char
4722
0
    *w;
4723
4724
0
  register const char
4725
0
    *r;
4726
4727
0
  for (w=string, r=string; *r != '\0'; )
4728
0
    {
4729
0
      if ((*r == ' ') || (*r == '\t'))
4730
0
        {
4731
0
          r++;
4732
0
          continue;
4733
0
        }
4734
0
      if (r != w)
4735
0
        *w = *r;
4736
0
      r++;
4737
0
      w++;
4738
0
    }
4739
0
  *w='\0';
4740
0
  return (size_t) (w - string);
4741
0
}
4742

4743
/*
4744
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4745
%                                                                             %
4746
%                                                                             %
4747
%                                                                             %
4748
%   M a g i c k S t r T o I n t 6 4                                           %
4749
%                                                                             %
4750
%                                                                             %
4751
%                                                                             %
4752
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4753
%
4754
%  MagickStrToInt64() converts a string to a 64-bit integer type.  MagickPass
4755
%  is returned if the conversion succeeds, and MagickFail is returned if
4756
%  the conversion fails.
4757
%
4758
%  The format of the MagickStrToInt64 method is:
4759
%
4760
%      MagickPassFail MagickStrToInt64(const char *start,char **end,
4761
%                                      magick_int64_t *value)
4762
%
4763
%  A description of each parameter follows:
4764
%
4765
%    o start: Start of string
4766
%
4767
%    o end: Pointer to update with address where parsing stopped.
4768
%
4769
%    o value: Pointer to value to update
4770
%
4771
*/
4772
static MagickPassFail MagickStrToInt64(const char *start,char **end,
4773
                                       magick_int64_t *value)
4774
0
{
4775
0
  magick_int64_t
4776
0
    result;
4777
4778
0
  errno=0;
4779
0
  result=MagickStrToL64(start,end,10);
4780
0
  if (errno == 0)
4781
0
    *value=result;
4782
4783
0
  return (errno == 0);
4784
0
}
4785

4786
/*
4787
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4788
%                                                                             %
4789
%                                                                             %
4790
%                                                                             %
4791
%   M a g i c k C r e a t e D i r e c t o r y P a t h                         %
4792
%                                                                             %
4793
%                                                                             %
4794
%                                                                             %
4795
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4796
%
4797
%  MagickCreateDirectoryPath() creates the specified directory path, creating
4798
%  parent directories as required.  MagickPass is returned on success, and
4799
%  MagickFail is returned if there is a failure, with error information set
4800
%  in the user-provided ExceptionInfo structure.
4801
%
4802
%  The format of the MagickCreateDirectoryPath method is:
4803
%
4804
%      MagickPassFail MagickCreateDirectoryPath(const char *dir,
4805
%                                               ExceptionInfo *exception)
4806
%
4807
%  A description of each parameter follows:
4808
%
4809
%    o dir: Path to create.
4810
%
4811
%    o exception: Return any errors or warnings in this structure.
4812
%
4813
*/
4814
MagickExport MagickPassFail MagickCreateDirectoryPath(const char *dir,
4815
                                                      ExceptionInfo *exception)
4816
0
{
4817
0
  char
4818
0
    path[MaxTextExtent];
4819
4820
0
  size_t
4821
0
    dir_len;
4822
4823
0
  int
4824
0
    status = MagickPass;
4825
4826
0
  const char
4827
0
    *end,
4828
0
    *p;
4829
4830
0
  unsigned int
4831
0
    directory_mode;
4832
4833
0
#if !defined(MSWINDOWS)
4834
4835
0
#  if defined(S_IRWXU)
4836
0
  directory_mode = S_IRWXU;
4837
#  else
4838
  directory_mode = 0777;
4839
#  endif /* if defined(S_IRWXU) */
4840
4841
0
#  if defined(S_IRGRP)
4842
0
  directory_mode |= S_IRGRP;
4843
0
#  endif /* if defined(S_IRGRP) */
4844
0
#  if defined(S_IXGRP)
4845
0
  directory_mode |= S_IXGRP;
4846
0
#  endif /*if defined(S_IXGRP) */
4847
0
#  if defined(S_IROTH)
4848
0
  directory_mode |= S_IROTH;
4849
0
#  endif /* if defined(S_IROTH) */
4850
0
#  if defined(S_IXOTH)
4851
0
  directory_mode |= S_IXOTH;
4852
0
#  endif /* if defined(S_IXOTH) */
4853
4854
#else
4855
4856
  (void) directory_mode;
4857
4858
#endif /* if !defined(MSWINDOWS) */
4859
4860
0
  dir_len = strlen(dir);
4861
0
  end = dir + dir_len;
4862
4863
  /*
4864
    Walk back to find part of path which already exists.
4865
  */
4866
0
  for (p = end; p > dir ; p--)
4867
0
    {
4868
0
      if ((p == end) || (DirectorySeparator[0] == *p))
4869
0
        {
4870
0
          (void) strlcpy(path,dir,p-dir+1);
4871
0
          if (IsAccessibleNoLogging(path))
4872
0
            break;
4873
0
        }
4874
0
    }
4875
4876
0
  if (p != end)
4877
0
    {
4878
      /*
4879
        Create part of path which does not already exist.
4880
      */
4881
0
      for ( p++; p <= end ; p++)
4882
0
        {
4883
0
          if ((*p == '\0') || (DirectorySeparator[0] == *p))
4884
0
            {
4885
0
              (void) strlcpy(path,dir,p-dir+1);
4886
0
              if (-1 == mkdir(path,directory_mode))
4887
0
                {
4888
0
                  if (EEXIST != errno)
4889
0
                    {
4890
                      /*
4891
                        Throw exception.
4892
                      */
4893
0
                      ThrowException2(exception,FileOpenError,dir,strerror(errno));
4894
0
                      status = MagickFail;
4895
0
                      break;
4896
0
                    }
4897
0
                }
4898
0
              errno = 0;
4899
0
            }
4900
0
        }
4901
0
    }
4902
0
  return status;
4903
0
}
4904

4905
/*
4906
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4907
%                                                                             %
4908
%                                                                             %
4909
%                                                                             %
4910
%   M a g i c k S c e n e F i l e N a m e                                     %
4911
%                                                                             %
4912
%                                                                             %
4913
%                                                                             %
4914
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4915
%
4916
%  MagickSceneFileName() uses a filename template and scene number
4917
%  in order to produce a unique filename for the scene.  If force is
4918
%  MagickFalse, then a substitution is only performed if the template
4919
%  contains a valid substitution specification.  If force is MagickTrue,
4920
%  then the additional scene template is applied so that the generated
4921
%  filename is assured to be distinguished by the scene number.
4922
%
4923
%  The format of the MagickSceneFileName method is:
4924
%
4925
%      MagickBool MagickSceneFileName(char *filename, const char* template,
4926
%                                     unsigned long scene)
4927
%
4928
%  A description of each parameter follows:
4929
%
4930
%    o filename: Buffer to update with generated filename.  Buffer must
4931
%                be at least MaxTextExtent bytes long.
4932
%
4933
%    o filename_template: Filename generation template (e.g. "image%02d.miff").
4934
%
4935
%    o scene_template: Template for scene part which is appended to
4936
%                template if template does not contain a scene format
4937
%                specification  (e.g. ".%lu" or "[%lu]").
4938
%
4939
%    o force:    If there is no embedded template in filename, then apply
4940
%                the scene template.
4941
%
4942
%    o scene:    Scene number.
4943
%
4944
*/
4945
MagickExport MagickBool MagickSceneFileName(char *filename,
4946
                                            const char* filename_template,
4947
                                            const char* scene_template,
4948
                                            const MagickBool force,
4949
                                            unsigned long scene)
4950
0
{
4951
0
  const char
4952
0
    *p;
4953
4954
0
  MagickBool
4955
0
    status;
4956
4957
0
  status = MagickFalse;
4958
0
  (void) strlcpy(filename,filename_template,MaxTextExtent);
4959
0
  p=strchr(filename_template,'%');
4960
0
  if ((p != (char *) NULL) && ((strchr(p+1,'%') == (char *) NULL)))
4961
0
    {
4962
0
      for ( p=p+1; *p ; p++)
4963
0
        {
4964
0
          register const int c = *p;
4965
0
          if ('d' == c)
4966
0
            {
4967
0
              MagickFormatString(filename,MaxTextExtent,filename_template,scene);
4968
0
              break;
4969
0
            }
4970
0
          if (!isdigit(c))
4971
0
            {
4972
0
              status = MagickFalse;
4973
0
              break;
4974
0
            }
4975
0
        }
4976
0
    }
4977
4978
0
  if ((force) && (LocaleCompare(filename,filename_template) == 0))
4979
0
    {
4980
0
      char format[MaxTextExtent];
4981
0
      (void) strlcpy(format,"%.1024s",sizeof(format));
4982
0
      (void) strlcat(format,scene_template,sizeof(format));
4983
0
      MagickFormatString(filename,MaxTextExtent,format,filename_template,scene);
4984
0
    }
4985
0
  if (LocaleCompare(filename,filename_template) != 0)
4986
0
    status = MagickTrue;
4987
4988
0
  return status;
4989
0
}
4990

4991
/*
4992
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4993
%                                                                             %
4994
%                                                                             %
4995
%                                                                             %
4996
%  M a g i c k S t r l C a t                                                  %
4997
%                                                                             %
4998
%                                                                             %
4999
%                                                                             %
5000
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5001
%
5002
%  Method MagickStrlCat appends the NULL-terminated string src to the end
5003
%  of dst.  It will append at most size - strlen(dst) - 1 bytes, NULL-
5004
%  terminating the result. If size is zero, then the result is not NULL
5005
%  terminated. The total length of the string which would have been created
5006
%  given sufficient buffer size (may be longer than size) is returned.  This
5007
%  function substitutes for strlcat() which is available under FreeBSD,
5008
%  Apple's OS-X, and Solaris 8.
5009
%
5010
%  Buffer overflow can be checked as  follows:
5011
%
5012
%    if (MagickStrlCat(dst, src, dstsize) >= dstsize)
5013
%      return -1;
5014
%
5015
%  The format of the MagickStrlCat method is:
5016
%
5017
%      size_t MagickStrlCat(char *dst, const char *src, size_t size)
5018
%
5019
%  A description of each parameter follows.
5020
%
5021
%   o  dst:  Destination string.
5022
%
5023
%   o  src:  Source string.
5024
%
5025
%   o  size: Maximum string length, including the terminating null.
5026
%
5027
*/
5028
MagickExport size_t MagickStrlCat(char *dst, const char *src, const size_t size)
5029
17.0M
{
5030
17.0M
  size_t
5031
17.0M
    length;
5032
5033
17.0M
  const char
5034
17.0M
    *q;
5035
5036
17.0M
  assert(dst != NULL);
5037
17.0M
  assert(src != (const char *) NULL);
5038
17.0M
  assert(size >= 1);
5039
5040
17.0M
  length=strlen(dst);
5041
5042
  /*
5043
    Copy remaining characters from src while constraining length to
5044
    size - 1.
5045
  */
5046
17.0M
  q = src;
5047
17.0M
  if (size >= 1)
5048
17.0M
    {
5049
17.0M
      char
5050
17.0M
        *p;
5051
5052
#if defined(MAGICK_STRL_CHECK)
5053
      (void) memset(dst+length,0,size-length);
5054
#endif /* if defined(MAGICK_STRL_CHECK) */
5055
5056
17.0M
      for ( p = dst + length ;
5057
68.2M
            (*q != 0) && (length < size - 1) ;
5058
51.2M
            length++, p++, q++ )
5059
51.2M
        *p = *q;
5060
5061
17.0M
      dst[length]='\0';
5062
17.0M
    }
5063
5064
  /*
5065
    Add remaining length of src to length.
5066
  */
5067
17.1M
  while (*q++)
5068
105k
    length++;
5069
5070
17.0M
  return length;
5071
17.0M
}
5072

5073
/*
5074
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5075
%                                                                             %
5076
%                                                                             %
5077
%                                                                             %
5078
%  M a g i c k S t r l C p y                                                  %
5079
%                                                                             %
5080
%                                                                             %
5081
%                                                                             %
5082
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5083
%
5084
%  Method MagickStrlCpy copies up to size - 1 characters from the NULL-
5085
%  terminated string src to dst, NULL-terminating the result. If size is
5086
%  zero, then the result is not NULL terminated.  The total length of the
5087
%  string which would have been created given sufficient buffer size (may
5088
%  be longer than size) is returned. This function is similar to strlcpy()
5089
%  which is available under FreeBSD, Apple's OS-X, and Solaris 8 except
5090
%  that it is assured to work with overlapping objects.  FreeBSD does not
5091
%  document if strlcpy() handles overlapping objects, but Solaris strlcpy()
5092
%  does not.
5093
%
5094
%  Buffer overflow can be checked as  follows:
5095
%
5096
%    if (MagickStrlCpy(dst, src, dstsize) >= dstsize)
5097
%      return -1;
5098
%
5099
%  The format of the MagickStrlCpy method is:
5100
%
5101
%      size_t MagickStrlCpy(char *dst, const char *src, size_t size)
5102
%
5103
%  A description of each parameter follows.
5104
%
5105
%   o  dst:  Destination string.
5106
%
5107
%   o  src:  Source string.
5108
%
5109
%   o  size: Maximum string length, including the terminating null.
5110
%
5111
*/
5112
MagickExport size_t MagickStrlCpy(char *dst, const char *src, const size_t size)
5113
243M
{
5114
243M
  size_t
5115
243M
    length;
5116
5117
243M
  const char
5118
243M
    *q;
5119
5120
243M
  assert(dst != NULL);
5121
243M
  assert(src != (const char *) NULL);
5122
243M
  assert(size >= 1);
5123
  /* assert(((dst+size) <= src) || (dst >= (src+size))); */
5124
5125
#if defined(MAGICK_STRL_CHECK)
5126
  (void) memset(dst,0,size);
5127
#endif /* if defined(MAGICK_STRL_CHECK) */
5128
5129
  /*
5130
    Copy src to dst within bounds of size-1.
5131
  */
5132
243M
  length=0;
5133
243M
  q=src;
5134
243M
  if (size >= 1)
5135
243M
    {
5136
243M
      char
5137
243M
        *p;
5138
5139
243M
      for ( p=dst ;
5140
2.89G
            (*q != 0) && (length < size-1) ;
5141
2.65G
            length++, p++, q++ )
5142
2.65G
        *p = *q;
5143
5144
243M
      dst[length]='\0';
5145
243M
    }
5146
5147
  /*
5148
    Add remaining length of src to length.
5149
  */
5150
267M
  while (*q++)
5151
23.9M
    length++;
5152
5153
243M
  return length;
5154
243M
}
5155

5156
/*
5157
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5158
%                                                                             %
5159
%                                                                             %
5160
%                                                                             %
5161
%  M a g i c k S t r l C p y T r u n c                                        %
5162
%                                                                             %
5163
%                                                                             %
5164
%                                                                             %
5165
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5166
%
5167
%  Method MagickStrlCpyTrunc copies up to size - 1 characters from the NULL-
5168
%  terminated string src to dst, NULL-terminating the result.  If size is
5169
%  zero, then the result is not NULL terminated.  The number of bytes copied
5170
%  (not including the terminating NULL) is returned.  This function is a
5171
%  useful alternative to using MagickStrlCpy() when the actual size copied
5172
%  is more useful than knowledge that truncation occurred.
5173
%
5174
%  The format of the MagickStrlCat method is:
5175
%
5176
%      size_t MagickStrlCpyTrunc(char *dst, const char *src, size_t size)
5177
%
5178
%  A description of each parameter follows.
5179
%
5180
%   o  dst:  Destination string.
5181
%
5182
%   o  src:  Source string.
5183
%
5184
%   o  size: Maximum string length, including the terminating null.
5185
%
5186
*/
5187
MagickExport size_t MagickStrlCpyTrunc(char *dst, const char *src, const size_t size)
5188
0
{
5189
0
  size_t
5190
0
    length;
5191
5192
0
  const char
5193
0
    *q;
5194
5195
0
  assert(dst != NULL);
5196
0
  assert(src != (const char *) NULL);
5197
0
  assert(size >= 1);
5198
5199
  /*
5200
    Copy src to dst within bounds of size-1.
5201
  */
5202
0
  length=0;
5203
0
  if (size >= 1)
5204
0
    {
5205
0
      char
5206
0
        *p;
5207
5208
0
      for ( p=dst, q=src;
5209
0
            (*q != 0) && (length < size-1) ;
5210
0
            length++, p++, q++ )
5211
0
        *p = *q;
5212
5213
0
      dst[length]='\0';
5214
0
    }
5215
5216
0
  return length;
5217
0
}
5218

5219
/*
5220
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5221
%                                                                             %
5222
%                                                                             %
5223
%                                                                             %
5224
%  M u l t i l i n e C e n s u s                                              %
5225
%                                                                             %
5226
%                                                                             %
5227
%                                                                             %
5228
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5229
%
5230
%  Method MultilineCensus returns the number of lines within a label.  A line
5231
%  is represented by a \n character.
5232
%
5233
%  The format of the MultilineCenus method is:
5234
%
5235
%      unsigned long MultilineCensus(const char *label)
5236
%
5237
%  A description of each parameter follows.
5238
%
5239
%   o  label:  This character string is the label.
5240
%
5241
%
5242
*/
5243
MagickExport unsigned long MultilineCensus(const char *label)
5244
1.44k
{
5245
1.44k
  long
5246
1.44k
    number_lines;
5247
5248
  /*
5249
    Determine the number of lines within this label.
5250
  */
5251
1.44k
  if (label == (char *) NULL)
5252
0
    return(0);
5253
25.5k
  for (number_lines=1; *label != '\0'; label++)
5254
24.1k
    if (*label == '\n')
5255
2.89k
      number_lines++;
5256
1.44k
  return(number_lines);
5257
1.44k
}
5258

5259
/*
5260
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5261
%                                                                             %
5262
%                                                                             %
5263
%                                                                             %
5264
%   S e t C l i e n t F i l e n a m e                                         %
5265
%                                                                             %
5266
%                                                                             %
5267
%                                                                             %
5268
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5269
%
5270
%  Method SetClientFilename sets the client filename if the name is specified.
5271
%  Otherwise the current client filename is returned. On a UNIX system the
5272
%  client name and filename are often the same since file extensions are not
5273
%  very important, but on windows the distinction is very important.
5274
%
5275
%  The format of the SetClientFilename method is:
5276
%
5277
%      char *SetClientFilname(const char *name)
5278
%
5279
%  A description of each parameter follows:
5280
%
5281
%    o client_name: Method SetClientFilename returns the current client name.
5282
%
5283
%    o status: Specifies the new client name.
5284
%
5285
%
5286
*/
5287
MagickExport const char *GetClientFilename(void)
5288
254
{
5289
254
  return(SetClientFilename((char *) NULL));
5290
254
}
5291
5292
MagickExport const char *SetClientFilename(const char *name)
5293
508
{
5294
508
  static char
5295
508
    client_filename[256] = "";
5296
5297
508
  if ((name != (char *) NULL) && (*name != '\0'))
5298
254
    {
5299
254
      (void) strlcpy(client_filename,name,sizeof(client_filename));
5300
254
      (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
5301
254
        "Client Filename was set to: %s",client_filename);
5302
254
    }
5303
508
  return(client_filename);
5304
508
}
5305

5306
/*
5307
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5308
%                                                                             %
5309
%                                                                             %
5310
%                                                                             %
5311
%   S e t C l i e n t N a m e                                                 %
5312
%                                                                             %
5313
%                                                                             %
5314
%                                                                             %
5315
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5316
%
5317
%  Method SetClientName sets the client name if the name is specified.
5318
%  Otherwise the current client name is returned.  The default value
5319
%  returned if a value was never set is "Magick".
5320
%
5321
%  The format of the SetClientName method is:
5322
%
5323
%      char *SetClientName(const char *name)
5324
%
5325
%  A description of each parameter follows:
5326
%
5327
%    o client_name: Method SetClientName returns the current client name.
5328
%
5329
%    o status: Specifies the new client name.
5330
%
5331
%
5332
*/
5333
MagickExport const char *GetClientName(void)
5334
34.5k
{
5335
34.5k
  return SetClientName((char *) NULL);
5336
34.5k
}
5337
5338
MagickExport const char *SetClientName(const char *name)
5339
533k
{
5340
533k
  static char
5341
533k
    client_name[256] = "";
5342
5343
533k
  if ((name != (char *) NULL) && (*name != '\0'))
5344
254
    {
5345
254
      (void) strlcpy(client_name,name,sizeof(client_name));
5346
254
      (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
5347
254
        "Client Name was set to: %s",client_name);
5348
254
    }
5349
533k
  return (client_name[0] == '\0' ? "Magick" : client_name);
5350
533k
}
5351

5352
/*
5353
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5354
%                                                                             %
5355
%                                                                             %
5356
%                                                                             %
5357
%   S e t C l i e n t P a t h                                                 %
5358
%                                                                             %
5359
%                                                                             %
5360
%                                                                             %
5361
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5362
%
5363
%  Method SetClientPath sets the client path if the name is specified.
5364
%  Otherwise the current client path is returned. A zero-length string
5365
%  is returned if the client path has never been set.
5366
%
5367
%  The format of the SetClientPath method is:
5368
%
5369
%      char *SetClientPath(const char *path)
5370
%
5371
%  A description of each parameter follows:
5372
%
5373
%    o client_path: Method SetClientPath returns the current client path.
5374
%
5375
%    o status: Specifies the new client path.
5376
%
5377
%
5378
*/
5379
MagickExport const char *GetClientPath(void)
5380
254
{
5381
254
  return(SetClientPath((char *) NULL));
5382
254
}
5383
5384
MagickExport const char *SetClientPath(const char *path)
5385
1.11k
{
5386
1.11k
  static char
5387
1.11k
    client_path[MaxTextExtent] = "";
5388
5389
1.11k
  if ((path != (char *) NULL) && (*path != '\0'))
5390
254
    {
5391
254
      (void) strlcpy(client_path,path,sizeof(client_path));
5392
254
      (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
5393
254
        "Client Path was set to: %s",path);
5394
254
    }
5395
1.11k
  return(client_path);
5396
1.11k
}
5397

5398
/*
5399
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5400
%                                                                             %
5401
%                                                                             %
5402
%                                                                             %
5403
%   S e t G e o m e t r y                                                     %
5404
%                                                                             %
5405
%                                                                             %
5406
%                                                                             %
5407
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5408
%
5409
%  SetGeometry sets a geometry to its default values.
5410
%
5411
%  The format of the SetGeometry method is:
5412
%
5413
%      SetGeometry(const Image *image,RectangleInfo *geometry)
5414
%
5415
%  A description of each parameter follows:
5416
%
5417
%    o image: The image.
5418
%
5419
%    o geometry: The geometry.
5420
%
5421
%
5422
*/
5423
MagickExport void SetGeometry(const Image *image,RectangleInfo *geometry)
5424
72.6k
{
5425
72.6k
  assert(image != (Image *) NULL);
5426
72.6k
  assert(geometry != (RectangleInfo *) NULL);
5427
72.6k
  (void) memset(geometry,0,sizeof(RectangleInfo));
5428
72.6k
  geometry->width=image->columns;
5429
72.6k
  geometry->height=image->rows;
5430
72.6k
}
5431

5432
/*
5433
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5434
%                                                                             %
5435
%                                                                             %
5436
%                                                                             %
5437
%  S t r i n g T o A r g v                                                    %
5438
%                                                                             %
5439
%                                                                             %
5440
%                                                                             %
5441
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5442
%
5443
%  Method StringToArgv converts a text string into command line arguments.
5444
%
5445
%  The format of the StringToArgv method is:
5446
%
5447
%      char **StringToArgv(const char *text,int *argc)
5448
%
5449
%  A description of each parameter follows:
5450
%
5451
%    o argv:  Method StringToArgv returns the string list unless an error
5452
%      occurs, otherwise NULL.
5453
%
5454
%    o text:  Specifies the string to segment into a list.
5455
%
5456
%    o argc:  This integer pointer returns the number of arguments in the
5457
%      list.
5458
%
5459
%
5460
*/
5461
MagickExport char **StringToArgv(const char *text,int *argc)
5462
0
{
5463
0
  char
5464
0
    **argv;
5465
5466
0
  register char
5467
0
    *p,
5468
0
    *q;
5469
5470
0
  register long
5471
0
    i;
5472
5473
0
  *argc=0;
5474
0
  if (text == (char *) NULL)
5475
0
    return((char **) NULL);
5476
  /*
5477
    Determine the number of arguments.
5478
  */
5479
0
  for (p=(char *) text; *p != '\0'; )
5480
0
  {
5481
0
    while (isspace((int)(unsigned char) (*p)))
5482
0
      p++;
5483
0
    (*argc)++;
5484
0
    if (*p == '"')
5485
0
      for (p++; (*p != '"') && (*p != '\0'); p++);
5486
0
    if (*p == '\'')
5487
0
      for (p++; (*p != '\'') && (*p != '\0'); p++);
5488
0
    while (!isspace((int)(unsigned char) (*p)) && (*p != '\0'))
5489
0
      p++;
5490
0
  }
5491
0
  (*argc)++;
5492
0
  argv=MagickAllocateMemory(char **,MagickArraySize((size_t) *argc+1,sizeof(char *)));
5493
0
  if (argv == (char **) NULL)
5494
0
    {
5495
0
      MagickError3(ResourceLimitError,MemoryAllocationFailed,
5496
0
        UnableToConvertStringToTokens);
5497
0
      return((char **) NULL);
5498
0
    }
5499
  /*
5500
    Convert string to an ASCII list.
5501
  */
5502
0
  argv[0]=AllocateString("magick");
5503
0
  p=(char *) text;
5504
0
  for (i=1; i < *argc; i++)
5505
0
  {
5506
0
    while (isspace((int)(unsigned char) (*p)))
5507
0
      p++;
5508
0
    q=p;
5509
0
    if (*q == '"')
5510
0
      {
5511
0
        p++;
5512
0
        for (q++; (*q != '"') && (*q != '\0'); q++);
5513
0
      }
5514
0
    else
5515
0
      if (*q == '\'')
5516
0
        {
5517
0
          for (q++; (*q != '\'') && (*q != '\0'); q++);
5518
0
          q++;
5519
0
        }
5520
0
      else
5521
0
        while (!isspace((int)(unsigned char) (*q)) && (*q != '\0'))
5522
0
          q++;
5523
0
    argv[i]=MagickAllocateMemory(char *,(size_t) (q-p+MaxTextExtent));
5524
0
    if (argv[i] == (char *) NULL)
5525
0
      {
5526
0
        int
5527
0
          j;
5528
5529
0
        MagickError3(ResourceLimitError,MemoryAllocationFailed,
5530
0
          UnableToConvertStringToTokens);
5531
5532
        /*
5533
          Deallocate allocated data and return.
5534
        */
5535
0
        for (j=0; j<i; j++)
5536
0
          MagickFreeMemory(argv[j]);
5537
0
        MagickFreeMemory(argv);
5538
0
        return((char **) NULL);
5539
0
      }
5540
0
    (void) strlcpy(argv[i],p,q-p+1);
5541
0
    p=q;
5542
0
    while (!isspace((int)(unsigned char) (*p)) && (*p != '\0'))
5543
0
      p++;
5544
0
  }
5545
0
  argv[i]=(char *) NULL;
5546
0
  return(argv);
5547
0
}
5548

5549
/*
5550
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5551
%                                                                             %
5552
%                                                                             %
5553
%                                                                             %
5554
%  S t r i n g T o D o u b l e                                                %
5555
%                                                                             %
5556
%                                                                             %
5557
%                                                                             %
5558
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5559
%
5560
%  Method StringToDouble() converts a text string to a double.  If the string
5561
%  contains a percent sign (e.g. 50%) that percentage of the interval is
5562
%  returned.
5563
%
5564
%  The format of the StringToDouble method is:
5565
%
5566
%      double StringToDouble(const char *text,const double interval)
5567
%
5568
%  A description of each parameter follows:
5569
%
5570
%    o value:  Method StringToDouble returns the converted value.
5571
%
5572
%    o text:  Specifies the string to segment into a list.
5573
%
5574
%    o interval:  Specifies the interval; used for obtaining a percentage.
5575
%
5576
%
5577
*/
5578
MagickExport double StringToDouble(const char *text,const double interval)
5579
0
{
5580
0
  char
5581
0
    *q;
5582
5583
0
  double
5584
0
    value;
5585
5586
0
  if (MagickStrToD(text,&q,&value) == 0)
5587
0
    return 0.0;
5588
0
  if (strchr(q,'%') != (char *) NULL)
5589
0
    value*=interval/100.0;
5590
0
  return(value);
5591
0
}
5592

5593
/*
5594
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5595
%                                                                             %
5596
%                                                                             %
5597
%                                                                             %
5598
%  S t r i n g T o L i s t                                                    %
5599
%                                                                             %
5600
%                                                                             %
5601
%                                                                             %
5602
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5603
%
5604
%  Method StringToList converts a text string into a list by segmenting the
5605
%  text string at each carriage return discovered.  The list is converted to
5606
%  HEX characters if any control characters are discovered within the text
5607
%  string.
5608
%
5609
%  The format of the StringToList method is:
5610
%
5611
%      char **StringToList(const char *text)
5612
%
5613
%  A description of each parameter follows:
5614
%
5615
%    o list:  Method StringToList returns the string list unless an error
5616
%      occurs, otherwise NULL.
5617
%
5618
%    o text:  Specifies the string to segment into a list.
5619
%
5620
%
5621
*/
5622
MagickExport char **StringToList(const char *text)
5623
0
{
5624
0
  char
5625
0
    **textlist;
5626
5627
0
  register char
5628
0
    *q;
5629
5630
0
  register const char
5631
0
    *p;
5632
5633
0
  register size_t
5634
0
    i;
5635
5636
0
  size_t
5637
0
    lines;
5638
5639
0
  if (text == (char *) NULL)
5640
0
    return((char **) NULL);
5641
0
  for (p=text; *p != '\0'; p++)
5642
0
    if (((unsigned char) *p < 32) && !isspace((int)(unsigned char) (*p)))
5643
0
      break;
5644
0
  if (*p == '\0')
5645
0
    {
5646
      /*
5647
        Convert string to an ASCII list.
5648
      */
5649
0
      lines=1;
5650
0
      for (p=text; *p != '\0'; p++)
5651
0
        if (*p == '\n')
5652
0
          lines++;
5653
0
      textlist=MagickAllocateMemory(char **,(lines+1)*sizeof(char *));
5654
0
      if (textlist == (char **) NULL)
5655
0
        MagickFatalError3(ResourceLimitFatalError,MemoryAllocationFailed,
5656
0
                          UnableToConvertText);
5657
0
      p=text;
5658
0
      for (i=0; i < lines; i++)
5659
0
        {
5660
0
          for (q=(char *) p; *q != '\0'; q++)
5661
0
            if ((*q == '\r') || (*q == '\n'))
5662
0
              break;
5663
0
          textlist[i]=MagickAllocateMemory(char *,(size_t) (q-p+1));
5664
0
          if (textlist[i] == (char *) NULL)
5665
0
            MagickFatalError3(ResourceLimitFatalError,MemoryAllocationFailed,
5666
0
                              UnableToConvertText);
5667
0
          (void) memcpy(textlist[i],p,q-p);
5668
0
          textlist[i][q-p]='\0';
5669
0
          if (*q == '\r')
5670
0
            q++;
5671
0
          p=q+1;
5672
0
        }
5673
0
    }
5674
0
  else
5675
0
    {
5676
0
      const size_t
5677
0
        chars_per_line = 0x14;
5678
5679
0
      char
5680
0
        hex_string[MaxTextExtent];
5681
5682
0
      register size_t
5683
0
        j;
5684
5685
      /*
5686
        Convert string to a HEX list.
5687
      */
5688
0
      lines=(strlen(text)/chars_per_line)+1;
5689
0
      textlist=MagickAllocateMemory(char **,(lines+1)*sizeof(char *));
5690
0
      if (textlist == (char **) NULL)
5691
0
        MagickFatalError3(ResourceLimitFatalError,MemoryAllocationFailed,
5692
0
                          UnableToConvertText);
5693
0
      p=text;
5694
0
      for (i=0; i < lines; i++)
5695
0
        {
5696
          /* FIXME: Allocation here is excessively large */
5697
0
          const size_t textlist_size = 2*MaxTextExtent;
5698
0
          textlist[i]=MagickAllocateMemory(char *,textlist_size);
5699
0
          if (textlist[i] == (char *) NULL)
5700
0
            MagickFatalError3(ResourceLimitFatalError,MemoryAllocationFailed,
5701
0
                              UnableToConvertText);
5702
0
          MagickFormatString(textlist[i],textlist_size/2,"0x%08" MAGICK_SIZE_T_F "x: ",
5703
0
                             (MAGICK_SIZE_T) chars_per_line*i);
5704
0
          q=textlist[i]+strlen(textlist[i]);
5705
0
          for (j=1; j <= Min(strlen(p),chars_per_line); j++)
5706
0
            {
5707
0
              MagickFormatString(hex_string,sizeof(hex_string),"%02x",*(p+j));
5708
0
              (void) strlcpy(q,hex_string,MaxTextExtent);
5709
0
              q+=2;
5710
0
              if ((j % 0x04) == 0)
5711
0
                *q++=' ';
5712
0
            }
5713
0
          for (; j <= chars_per_line; j++)
5714
0
            {
5715
0
              *q++=' ';
5716
0
              *q++=' ';
5717
0
              if ((j % 0x04) == 0)
5718
0
                *q++=' ';
5719
0
            }
5720
0
          *q++=' ';
5721
0
          for (j=1; j <= Min(strlen(p),chars_per_line); j++)
5722
0
            {
5723
0
              if (isprint((int)(unsigned char)(*p)))
5724
0
                *q++=(*p);
5725
0
              else
5726
0
                *q++='-';
5727
0
              p++;
5728
0
            }
5729
0
          *q='\0';
5730
0
        }
5731
0
    }
5732
0
  textlist[i]=(char *) NULL;
5733
0
  return(textlist);
5734
0
}
5735

5736
/*
5737
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5738
%                                                                             %
5739
%                                                                             %
5740
%                                                                             %
5741
+   S u b s t i t u t e S t r i n g                                           %
5742
%                                                                             %
5743
%                                                                             %
5744
%                                                                             %
5745
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5746
%
5747
%  SubstituteString() performs string substitution on a buffer, replacing
5748
%  the buffer with the substituted version. Buffer must be allocated from
5749
%  the heap since it may be reallocated (as required). MagickTrue is returned
5750
%  if a replacement was made.
5751
%
5752
%  The format of the SubstituteString method is:
5753
%
5754
%      MagickBool SubstituteString(char **buffer,const char* search,
5755
%        const char *replace)
5756
%
5757
%  A description of each parameter follows:
5758
%
5759
%    o buffer: The buffer to perform replacements on. Replaced with new
5760
%      allocation if a replacement is made.
5761
%
5762
%    o search: String to search for.
5763
%
5764
%    o replace: Replacement string.
5765
%
5766
*/
5767
MagickExport MagickBool
5768
SubstituteString(char **buffer,const char *search,const char *replace)
5769
0
{
5770
0
  register char
5771
0
    *p=*buffer;
5772
5773
0
  register size_t
5774
0
    i;
5775
5776
0
  size_t
5777
0
    search_len=0,
5778
0
    replace_len=0;
5779
5780
0
  MagickBool
5781
0
    replaced=MagickFalse;
5782
5783
0
  search_len=strlen(search);
5784
0
  p=*buffer;
5785
0
  for (i=0; p[i] != '\0'; i++)
5786
0
    {
5787
0
      if ((p[i] == search[0]) && (strncmp(&p[i],search,search_len) == 0))
5788
0
        {
5789
0
          if (0 == replace_len)
5790
0
            {
5791
0
              replace_len=strlen(replace);
5792
0
              if (replace_len == 0)
5793
0
                break;
5794
0
            }
5795
0
          if (replace_len > search_len)
5796
0
            {
5797
0
              size_t
5798
0
                allocation_len;
5799
5800
0
              allocation_len=strlen(p)+(replace_len-search_len)+1;
5801
0
              MagickRoundUpStringLength(allocation_len);
5802
0
              MagickReallocMemory(char *,p,allocation_len);
5803
0
              *buffer=p;
5804
0
              if (p == (char *) NULL)
5805
0
                MagickFatalError3(ResourceLimitFatalError,
5806
0
                                  MemoryAllocationFailed,
5807
0
                                  UnableToAllocateString);
5808
0
            }
5809
0
          if (search_len != replace_len)
5810
0
            (void) MagickCloneMemory(&p[i+replace_len],&p[i+search_len],
5811
0
                                     strlen(&p[i+search_len])+1);
5812
0
          (void) MagickCloneMemory(&p[i],replace,replace_len);
5813
0
          i += (replace_len-1);
5814
0
          replaced=MagickTrue;
5815
0
        }
5816
0
    }
5817
0
  return replaced;
5818
0
}
5819

5820
/*
5821
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5822
%                                                                             %
5823
%                                                                             %
5824
%                                                                             %
5825
%   S y s t e m C o m m a n d                                                 %
5826
%                                                                             %
5827
%                                                                             %
5828
%                                                                             %
5829
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5830
%
5831
%  Method SystemCommand executes the specified command and waits until it
5832
%  terminates.  The returned value is the exit status of the command.
5833
%
5834
%  The format of the SystemCommand method is:
5835
%
5836
%      int SystemCommand(const unsigned int verbose,const char *command)
5837
%
5838
%  A description of each parameter follows:
5839
%
5840
%    o status: Method SystemCommand returns False if the command is
5841
%      executed successfully.
5842
%
5843
%    o verbose: An unsigned integer other than 0 prints the executed
5844
%      command before it is invoked.
5845
%
5846
%    o command: This string is the command to execute.
5847
%
5848
%
5849
*/
5850
MagickExport int SystemCommand(const unsigned int verbose,const char *command)
5851
0
{
5852
0
  int
5853
0
    status;
5854
5855
0
#if defined(POSIX)
5856
0
  char
5857
0
    message[MaxTextExtent];
5858
0
#endif /* POSIX */
5859
5860
0
  const char
5861
0
    *message_p = (const char *) NULL;
5862
5863
0
  {
5864
    /*
5865
      Verify that we are allowed to run this program.
5866
    */
5867
0
    ExceptionInfo
5868
0
      exception;
5869
5870
0
    char
5871
0
      *end,
5872
0
      program[MaxTextExtent];
5873
5874
0
    GetExceptionInfo(&exception);
5875
0
    end=(char *) NULL;
5876
0
    program[0]='\0';
5877
0
    MagickGetToken(command,&end,program,MaxTextExtent);
5878
0
    if (MagickConfirmAccess(FileExecuteConfirmAccessMode,program,&exception)
5879
0
        == MagickFail)
5880
0
      {
5881
0
        errno=EPERM;
5882
0
        DestroyExceptionInfo(&exception);
5883
0
        return -1;
5884
0
      }
5885
0
  }
5886
5887
0
  errno=0;
5888
0
#if defined(POSIX)
5889
0
  status=system(command);
5890
0
  if (status == 1)
5891
0
    {
5892
0
      (void) strlcpy(message,strerror(status),sizeof(message));
5893
0
      message_p=message;
5894
0
    }
5895
0
  else if (WIFSIGNALED(status))
5896
0
    {
5897
0
      MagickFormatString(message,sizeof(message),"terminated due to signal %d",
5898
0
                         WTERMSIG(status));
5899
0
      message[sizeof(message)-1]='\0';
5900
0
      message_p=message;
5901
0
    }
5902
#elif defined(MSWINDOWS)
5903
  status=NTSystemComman(command);
5904
  if (!status)
5905
    message_p=strerror(status);
5906
#else
5907
#  error Do not know how to run system commands.
5908
#endif
5909
0
  if (verbose || (status != 0))
5910
0
    MagickError2(DelegateError,command,message_p);
5911
0
  return(status);
5912
0
}
5913

5914
/*
5915
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5916
%                                                                             %
5917
%                                                                             %
5918
%                                                                             %
5919
%   T o k e n i z e r                                                         %
5920
%                                                                             %
5921
%                                                                             %
5922
%                                                                             %
5923
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5924
%
5925
%  Method Tokenizer is a generalized, finite state token parser.  It extracts
5926
%  tokens one at a time from a string of characters.  The characters used for
5927
%  white space, for break characters, and for quotes can be specified.  Also,
5928
%  characters in the string can be preceded by a specifiable escape character
5929
%  which removes any special meaning the character may have.
5930
%
5931
%  Here is some terminology:
5932
%
5933
%    o token: A single unit of information in the form of a group of
5934
%      characters.
5935
%
5936
%    o white space: Space that gets ignored (except within quotes or when
5937
%      escaped), like blanks and tabs. in addition, white space terminates a
5938
%      non-quoted token.
5939
%
5940
%    o break set: One or more characters that separates non-quoted tokens.
5941
%      Commas are a common break character. The usage of break characters to
5942
%      signal the end of a token is the same as that of white space, except
5943
%      multiple break characters with nothing or only white space between
5944
%      generate a null token for each two break characters together.
5945
%
5946
%      For example, if blank is set to be the white space and comma is set to
5947
%      be the break character, the line
5948
%
5949
%        A, B, C ,  , DEF
5950
%
5951
%        ... consists of 5 tokens:
5952
%
5953
%        1)  "A"
5954
%        2)  "B"
5955
%        3)  "C"
5956
%        4)  "" (the null string)
5957
%        5)  "DEF"
5958
%
5959
%    o Quote character: A character that, when surrounding a group of other
5960
%      characters, causes the group of characters to be treated as a single
5961
%      token, no matter how many white spaces or break characters exist in
5962
%      the group. Also, a token always terminates after the closing quote.
5963
%      For example, if ' is the quote character, blank is white space, and
5964
%      comma is the break character, the following string
5965
%
5966
%        A, ' B, CD'EF GHI
5967
%
5968
%        ... consists of 4 tokens:
5969
%
5970
%        1)  "A"
5971
%        2)  " B, CD" (note the blanks & comma)
5972
%        3)  "EF"
5973
%        4)  "GHI"
5974
%
5975
%      The quote characters themselves do not appear in the resultant
5976
%      tokens.  The double quotes are delimiters i use here for
5977
%      documentation purposes only.
5978
%
5979
%    o Escape character: A character which itself is ignored but which
5980
%      causes the next character to be used as is.  ^ and \ are often used
5981
%      as escape characters. An escape in the last position of the string
5982
%      gets treated as a "normal" (i.e., non-quote, non-white, non-break,
5983
%      and non-escape) character. For example, assume white space, break
5984
%      character, and quote are the same as in the above examples, and
5985
%      further, assume that ^ is the escape character. Then, in the string
5986
%
5987
%        ABC, ' DEF ^' GH' I ^ J K^ L ^
5988
%
5989
%        ... there are 7 tokens:
5990
%
5991
%        1)  "ABC"
5992
%        2)  " DEF ' GH"
5993
%        3)  "I"
5994
%        4)  " "     (a lone blank)
5995
%        5)  "J"
5996
%        6)  "K L"
5997
%        7)  "^"     (passed as is at end of line)
5998
%
5999
%  The format of the Tokenizer method is:
6000
%
6001
%      int Tokenizer(TokenInfo *token_info,unsigned flag,char *token,
6002
%        size_t max_token_length,char *line,char *white,char *break_set,
6003
%        char *quote,char escape,char *breaker,int *next,char *quoted)
6004
%
6005
%  A description of each parameter follows:
6006
%
6007
%    o flag: right now, only the low order 3 bits are used.
6008
%
6009
%        1 => convert non-quoted tokens to upper case
6010
%        2 => convert non-quoted tokens to lower case
6011
%        0 => do not convert non-quoted tokens
6012
%
6013
%    o token: a character string containing the returned next token
6014
%
6015
%    o max_token_length: the maximum size of "token".  Characters beyond
6016
%      "max_token_length" are truncated.
6017
%
6018
%    o string: the string to be parsed.
6019
%
6020
%    o white: a string of the valid white spaces.  example:
6021
%
6022
%        char whitesp[]={" \t"};
6023
%
6024
%      blank and tab will be valid white space.
6025
%
6026
%    o break: a string of the valid break characters. example:
6027
%
6028
%        char breakch[]={";,"};
6029
%
6030
%      semicolon and comma will be valid break characters.
6031
%
6032
%    o quote: a string of the valid quote characters. An example would be
6033
%
6034
%        char whitesp[]={"'\"");
6035
%
6036
%      (this causes single and double quotes to be valid) Note that a
6037
%      token starting with one of these characters needs the same quote
6038
%      character to terminate it.
6039
%
6040
%      for example:
6041
%
6042
%        "ABC '
6043
%
6044
%      is unterminated, but
6045
%
6046
%        "DEF" and 'GHI'
6047
%
6048
%      are properly terminated.  Note that different quote characters
6049
%      can appear on the same line; only for a given token do the quote
6050
%      characters have to be the same.
6051
%
6052
%    o escape: the escape character (NOT a string ... only one
6053
%      allowed). Use zero if none is desired.
6054
%
6055
%    o breaker: the break character used to terminate the current
6056
%      token.  If the token was quoted, this will be the quote used.  If
6057
%      the token is the last one on the line, this will be zero.
6058
%
6059
%    o next: this variable points to the first character of the
6060
%      next token.  it gets reset by "tokenizer" as it steps through the
6061
%      string.  Set it to 0 upon initialization, and leave it alone
6062
%      after that.  You can change it if you want to jump around in the
6063
%      string or re-parse from the beginning, but be careful.
6064
%
6065
%    o quoted: set to True if the token was quoted and False
6066
%      if not.  You may need this information (for example:  in C, a
6067
%      string with quotes around it is a character string, while one
6068
%      without is an identifier).
6069
%
6070
%    o result: 0 if we haven't reached EOS (end of string), and 1
6071
%      if we have.
6072
%
6073
*/
6074
6075
102M
#define IN_WHITE 0
6076
125M
#define IN_TOKEN 1
6077
212M
#define IN_QUOTE 2
6078
22.1M
#define IN_OZONE 3
6079
6080
static long sindex(char c,char *string) MAGICK_FUNC_PURE;
6081
6082
static long sindex(char c,char *string)
6083
379M
{
6084
379M
  register char
6085
379M
    *p;
6086
6087
556M
  for (p=string; *p; p++)
6088
204M
    if (c == (*p))
6089
26.4M
      return(p-string);
6090
352M
  return(-1);
6091
379M
}
6092
6093
static void StoreToken(TokenInfo *token_info,char *string,
6094
  size_t max_token_length,char c)
6095
121M
{
6096
121M
  register long
6097
121M
    i;
6098
6099
121M
  if ((token_info->offset < 0) ||
6100
121M
      ((size_t) token_info->offset >= (max_token_length-1)))
6101
0
    return;
6102
121M
  i=token_info->offset++;
6103
121M
  string[i]=c;
6104
121M
  if (token_info->state == IN_QUOTE)
6105
18.6M
    return;
6106
102M
  switch (token_info->flag & 0x03)
6107
102M
  {
6108
0
    case 1:
6109
0
    {
6110
0
      string[i]=toupper((int) c);
6111
0
      break;
6112
0
    }
6113
0
    case 2:
6114
0
    {
6115
0
      string[i]=tolower((int) c);
6116
0
      break;
6117
0
    }
6118
102M
    default:
6119
102M
      break;
6120
102M
  }
6121
102M
}
6122
6123
MagickExport int Tokenizer(TokenInfo *token_info,unsigned flag,char *token,
6124
  size_t max_token_length,char *line,char *white,char *break_set,char *quote,
6125
  char escape,char *breaker,int *next,char *quoted)
6126
95.7M
{
6127
95.7M
  char
6128
95.7M
    c;
6129
6130
95.7M
  register long
6131
95.7M
    i;
6132
6133
95.7M
  *breaker=False;
6134
95.7M
  *quoted=False;
6135
95.7M
  if (!line[*next])
6136
44.2M
    return(1);
6137
51.4M
  token_info->state=IN_WHITE;
6138
51.4M
  token_info->quote=False;
6139
51.4M
  token_info->flag=flag;
6140
173M
  for (token_info->offset=0; line[*next] != 0; (*next)++)
6141
143M
  {
6142
143M
    c=line[*next];
6143
143M
    i=sindex(c,break_set);
6144
143M
    if (i >= 0)
6145
26.2M
      {
6146
26.2M
        switch (token_info->state)
6147
26.2M
        {
6148
20.8M
          case IN_WHITE:
6149
21.9M
          case IN_TOKEN:
6150
21.9M
          case IN_OZONE:
6151
21.9M
          {
6152
21.9M
            (*next)++;
6153
21.9M
            *breaker=break_set[i];
6154
21.9M
            token[token_info->offset]=0;
6155
21.9M
            return(0);
6156
21.9M
          }
6157
4.23M
          case IN_QUOTE:
6158
4.23M
          {
6159
4.23M
            StoreToken(token_info,token,max_token_length,c);
6160
4.23M
            break;
6161
21.9M
          }
6162
26.2M
        }
6163
4.23M
        continue;
6164
26.2M
      }
6165
117M
    i=sindex(c,quote);
6166
117M
    if (i >= 0)
6167
206k
      {
6168
206k
        switch(token_info->state)
6169
206k
        {
6170
98.3k
          case IN_WHITE:
6171
98.3k
          {
6172
98.3k
            token_info->state=IN_QUOTE;
6173
98.3k
            token_info->quote=quote[i];
6174
98.3k
            *quoted=True;
6175
98.3k
            break;
6176
0
          }
6177
71.3k
          case IN_QUOTE:
6178
71.3k
          {
6179
71.3k
            if (quote[i] != token_info->quote)
6180
0
              StoreToken(token_info,token,max_token_length,c);
6181
71.3k
            else
6182
71.3k
              {
6183
71.3k
                token_info->state=IN_OZONE;
6184
71.3k
                token_info->quote=0;
6185
71.3k
              }
6186
71.3k
            break;
6187
0
          }
6188
27.5k
          case IN_TOKEN:
6189
36.5k
          case IN_OZONE:
6190
36.5k
          {
6191
36.5k
            *breaker=c;
6192
36.5k
            token[token_info->offset]=0;
6193
36.5k
            return(0);
6194
27.5k
          }
6195
206k
        }
6196
169k
        continue;
6197
206k
      }
6198
117M
    i=sindex(c,white);
6199
117M
    if (i >= 0)
6200
0
      {
6201
0
        switch(token_info->state)
6202
0
        {
6203
0
          case IN_WHITE:
6204
0
          case IN_OZONE:
6205
0
            break;
6206
0
          case IN_TOKEN:
6207
0
          {
6208
0
            token_info->state=IN_OZONE;
6209
0
            break;
6210
0
          }
6211
0
          case IN_QUOTE:
6212
0
          {
6213
0
            StoreToken(token_info,token,max_token_length,c);
6214
0
            break;
6215
0
          }
6216
0
        }
6217
0
        continue;
6218
0
      }
6219
117M
    if (c == escape)
6220
0
      {
6221
0
        if (line[(*next)+1] == 0)
6222
0
          {
6223
0
            *breaker=0;
6224
0
            StoreToken(token_info,token,max_token_length,c);
6225
0
            (*next)++;
6226
0
            token[token_info->offset]=0;
6227
0
            return(0);
6228
0
          }
6229
0
        switch(token_info->state)
6230
0
        {
6231
0
          case IN_WHITE:
6232
0
          {
6233
0
            (*next)--;
6234
0
            token_info->state=IN_TOKEN;
6235
0
            break;
6236
0
          }
6237
0
          case IN_TOKEN:
6238
0
          case IN_QUOTE:
6239
0
          {
6240
0
            (*next)++;
6241
0
            c=line[*next];
6242
0
            StoreToken(token_info,token,max_token_length,c);
6243
0
            break;
6244
0
          }
6245
0
          case IN_OZONE:
6246
0
          {
6247
0
            token[token_info->offset]=0;
6248
0
            return(0);
6249
0
          }
6250
0
        }
6251
0
        continue;
6252
0
      }
6253
117M
    switch(token_info->state)
6254
117M
    {
6255
30.5M
      case IN_WHITE:
6256
30.5M
        {
6257
30.5M
          token_info->state=IN_TOKEN;
6258
30.5M
          StoreToken(token_info,token,max_token_length,c);
6259
30.5M
          break;
6260
0
        }
6261
72.4M
      case IN_TOKEN:
6262
86.8M
      case IN_QUOTE:
6263
86.8M
      {
6264
86.8M
        StoreToken(token_info,token,max_token_length,c);
6265
86.8M
        break;
6266
72.4M
      }
6267
59.8k
      case IN_OZONE:
6268
59.8k
      {
6269
59.8k
        token[token_info->offset]=0;
6270
59.8k
        return(0);
6271
72.4M
      }
6272
117M
    }
6273
117M
  }
6274
29.3M
  token[token_info->offset]=0;
6275
29.3M
  return(0);
6276
51.4M
}
6277

6278
/*
6279
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6280
%                                                                             %
6281
%                                                                             %
6282
%                                                                             %
6283
%   T r a n s l a t e T e x t                                                 %
6284
%                                                                             %
6285
%                                                                             %
6286
%                                                                             %
6287
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6288
%
6289
%  Method TranslateText replaces any embedded formatting characters with
6290
%  the appropriate image attribute and returns the translated text.  See
6291
%  the documentation for TranslateTextEx() for the available translations.
6292
%
6293
%  The format of the TranslateText method is:
6294
%
6295
%      char *TranslateText(const ImageInfo *image_info,Image *image,
6296
%        const char *formatted_text)
6297
%
6298
%  A description of each parameter follows:
6299
%
6300
%    o translated_text:  Method TranslateText returns a new allocation
6301
%      containing the translated text string.  If the translated text
6302
%      string would be empty, a NULL pointer is returned instead.
6303
%
6304
%    o image_info: The imageInfo (may be NULL!).
6305
%
6306
%    o image: The image.
6307
%
6308
%    o formatted_text: The address of a character string containing the embedded
6309
%      formatting characters.
6310
%
6311
*/
6312
6313
MagickExport char *TranslateText(const ImageInfo *image_info,
6314
                                 Image *image,
6315
                                 const char *formatted_text)
6316
56
{
6317
56
  return TranslateTextEx(image_info,image,formatted_text,MagickStrlCpyTrunc);
6318
56
}
6319

6320
/*
6321
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6322
%                                                                             %
6323
%                                                                             %
6324
%                                                                             %
6325
%   T r a n s l a t e T e x t E x                                             %
6326
%                                                                             %
6327
%                                                                             %
6328
%                                                                             %
6329
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6330
%
6331
%  Method TranslateTextEx replaces any embedded formatting characters with
6332
%  the appropriate image attribute and returns the translated text, while
6333
%  applying a text transformation for each substitution via a user provided
6334
%  translation function.  The translation function should behave similar to
6335
%  strlcpy() but may translate text while it is copied.
6336
%
6337
%  The currently supported translations are:
6338
%
6339
%    %b   file size
6340
%    %c   comment
6341
%    %d   directory
6342
%    %e   filename extension
6343
%    %f   filename
6344
%    %g   page dimensions and offsets
6345
%    %h   height
6346
%    %i   input filename
6347
%    %k   number of unique colors
6348
%    %l   label
6349
%    %m   magick
6350
%    %n   number of scenes
6351
%    %o   output filename
6352
%    %p   page number
6353
%    %q   image bit depth
6354
%    %r   image type description
6355
%    %s   scene number
6356
%    %t   top of filename
6357
%    %u   first unique temporary filename
6358
%    %w   width
6359
%    %x   horizontal resolution
6360
%    %y   vertical resolution
6361
%    %z   second unique temporary filename
6362
%    %A   transparency supported
6363
%    %C   compression type
6364
%    %D   GIF disposal method
6365
%    %G   Original width and height
6366
%    %H   page height
6367
%    %M   original filename specification
6368
%    %O   page offset (x,y)
6369
%    %P   page dimensions (width,height)
6370
%    %Q   compression quality
6371
%    %T   time delay (in centi-seconds)
6372
%    %U   resolution units
6373
%    %W   page width
6374
%    %X   page horizontal offset (x)
6375
%    %Y   page vertical offset (y)
6376
%    %@   trim bounding box
6377
%    %[a] named attribute 'a'
6378
%    %#   signature
6379
%    \n   newline
6380
%    \r   carriage return
6381
%    %%   % (literal)
6382
%
6383
%  The format of the TranslateTextEx method is:
6384
%
6385
%      char *TranslateTextEx(const ImageInfo *image_info,Image *image,
6386
%        const char *formatted_text, MagickTextTranslate translate)
6387
%
6388
%  A description of each parameter follows:
6389
%
6390
%    o translated_text:  Method TranslateTextEx returns a new allocation
6391
%      containing the translated text string.  If the translated text
6392
%      string would be empty, a NULL pointer is returned instead.
6393
%
6394
%    o image_info: The imageInfo (may be NULL!).
6395
%
6396
%    o image: The image.
6397
%
6398
%    o formatted_text: The address of a character string containing the embedded
6399
%      formatting characters.
6400
%
6401
%    o translate: text translation callback function
6402
%
6403
*/
6404
MagickExport char *TranslateTextEx(const ImageInfo *image_info,
6405
                                   Image *image,
6406
                                   const char *formatted_text,
6407
                                   MagickTextTranslate translate)
6408
56
{
6409
56
  char
6410
56
    buffer[MaxTextExtent],
6411
56
    *text,
6412
56
    *translated_text;
6413
6414
56
  const ImageAttribute
6415
56
    *attribute;
6416
6417
56
  register char
6418
56
    *p,
6419
56
    *q;
6420
6421
56
  register long
6422
56
    i;
6423
6424
56
  size_t
6425
56
    length,
6426
56
    offset;
6427
6428
56
  assert(image != (Image *) NULL);
6429
56
  if ((formatted_text == (const char *) NULL) || (*formatted_text == '\0'))
6430
56
    return((char *) NULL);
6431
0
  text=(char *) formatted_text;
6432
  /*
6433
    Translate any embedded format characters.
6434
  */
6435
0
  length=strlen(text);
6436
0
  translated_text=MagickAllocateMemory(char *,length+MaxTextExtent);
6437
0
  if (translated_text == (char *) NULL)
6438
0
    return NULL;
6439
0
  (void) memcpy(translated_text,text,length);
6440
0
  translated_text[length]='\0';
6441
0
  length=length+MaxTextExtent;
6442
0
  p=text;
6443
0
  for (q=translated_text; *p != '\0'; p++)
6444
0
    {
6445
0
      *q='\0';
6446
0
      if ((size_t) (q-translated_text+MaxTextExtent) >= length)
6447
0
        {
6448
0
          length<<=1;
6449
0
          MagickReallocMemory(char *,translated_text,length);
6450
0
          if (translated_text == (char *) NULL)
6451
0
            break;
6452
0
          q=translated_text+strlen(translated_text);
6453
0
        }
6454
      /*
6455
        Process formatting characters in text.
6456
      */
6457
0
      if ((*p == '\\') && (*(p+1) == 'r'))
6458
0
        {
6459
0
          *q++='\r';
6460
0
          p++;
6461
0
          continue;
6462
0
        }
6463
0
      if ((*p == '\\') && (*(p+1) == 'n'))
6464
0
        {
6465
0
          *q++='\n';
6466
0
          p++;
6467
0
          continue;
6468
0
        }
6469
0
      if (*p != '%')
6470
0
        {
6471
0
          *q++=(*p);
6472
0
          continue;
6473
0
        }
6474
0
      p++;
6475
0
      switch (*p)
6476
0
        {
6477
0
        case 'b':
6478
0
          {
6479
            /* File size */
6480
0
            FormatSize(GetBlobSize(image),buffer);
6481
0
            q+=(translate)(q,buffer,MaxTextExtent);
6482
0
            break;
6483
0
          }
6484
0
        case 'c':
6485
0
          {
6486
            /* Comment */
6487
0
            attribute=GetImageAttribute(image,"comment");
6488
0
            if (attribute != (ImageAttribute *) NULL)
6489
0
              {
6490
                /* Comments may be larger than MaxTextExtent so make sure
6491
                   there is sufficient memory allocated. Make sure that
6492
                   there is at least MaxTextExtent left available after we
6493
                   have concatenated our part. */
6494
0
                offset=q-translated_text;
6495
0
                if ((size_t) (offset+attribute->length+1+MaxTextExtent) >= length)
6496
0
                  {
6497
0
                    length += (attribute->length+1+2*MaxTextExtent);
6498
0
                    MagickReallocMemory(char *,translated_text,length);
6499
0
                    if (translated_text == (char *) NULL)
6500
0
                      break;
6501
0
                    q=translated_text+offset;
6502
0
                  }
6503
0
                q+=(translate)(q,attribute->value,attribute->length+1+MaxTextExtent);
6504
0
              }
6505
0
            break;
6506
0
          }
6507
0
        case 'd':
6508
0
        case 'e':
6509
0
        case 'f':
6510
0
        case 't':
6511
0
          {
6512
            /*
6513
              Label segment is the base of the filename.
6514
            */
6515
0
            if (strlen(image->magick_filename) != 0)
6516
0
              {
6517
0
                (void) strlcpy(buffer,"",MaxTextExtent);
6518
0
                switch (*p)
6519
0
                  {
6520
0
                  case 'd':
6521
0
                    {
6522
                      /* Directory */
6523
0
                      GetPathComponent(image->magick_filename,HeadPath,buffer);
6524
0
                      break;
6525
0
                    }
6526
0
                  case 'e':
6527
0
                    {
6528
                      /* Filename extension */
6529
0
                      GetPathComponent(image->magick_filename,ExtensionPath,buffer);
6530
0
                      break;
6531
0
                    }
6532
0
                  case 'f':
6533
0
                    {
6534
                      /* Filename */
6535
0
                      GetPathComponent(image->magick_filename,TailPath,buffer);
6536
0
                      break;
6537
0
                    }
6538
0
                  case 't':
6539
0
                    {
6540
                      /* Top of filename */
6541
0
                      GetPathComponent(image->magick_filename,BasePath,buffer);
6542
0
                      break;
6543
0
                    }
6544
0
                  }
6545
0
                q+=(translate)(q,buffer,MaxTextExtent);
6546
0
              }
6547
0
            break;
6548
0
          }
6549
0
        case 'g':
6550
0
          {
6551
            /* page dimensions and offsets */
6552
0
            MagickFormatString(buffer,sizeof(buffer),"%lux%lu%+ld%+ld",
6553
0
                               image->page.width,image->page.height,
6554
0
                               image->page.x,image->page.y);
6555
0
            q+=(translate)(q,buffer,MaxTextExtent);
6556
0
            break;
6557
0
          }
6558
0
        case 'h':
6559
0
          {
6560
            /* Image height */
6561
0
            MagickFormatString(buffer,sizeof(buffer),"%lu",image->rows);
6562
0
            q+=(translate)(q,buffer,MaxTextExtent);
6563
0
            break;
6564
0
          }
6565
0
        case 'i':
6566
0
          {
6567
            /* Input filename */
6568
0
            q+=(translate)(q,image->filename,MaxTextExtent);
6569
0
            break;
6570
0
          }
6571
0
        case 'k':
6572
0
          {
6573
            /* Number of unique colors */
6574
0
            if (GetPixelCachePresent(image))
6575
0
              {
6576
0
                MagickFormatString(buffer,sizeof(buffer),"%lu",
6577
0
                                   GetNumberColors(image,(FILE *) NULL,
6578
0
                                                   &image->exception));
6579
0
                q+=(translate)(q,buffer,MaxTextExtent);
6580
0
              }
6581
0
            else
6582
0
              {
6583
0
                *q++='%';
6584
0
                *q++=(*p);
6585
0
              }
6586
0
            break;
6587
0
          }
6588
0
        case 'l':
6589
0
          {
6590
            /* Label */
6591
0
            attribute=GetImageAttribute(image,"label");
6592
0
            if (attribute != (ImageAttribute *) NULL)
6593
0
              q+=(translate)(q,attribute->value,MaxTextExtent);
6594
0
            break;
6595
0
          }
6596
0
        case 'm':
6597
0
          {
6598
            /* File format "magick" */
6599
0
            q+=(translate)(q,image->magick,MaxTextExtent);
6600
0
            break;
6601
0
          }
6602
0
        case 'n':
6603
0
          {
6604
            /* Number of scenes */
6605
0
            MagickFormatString(buffer,sizeof(buffer),"%lu",
6606
0
                               (unsigned long) GetImageListLength(image));
6607
0
            q+=(translate)(q,buffer,MaxTextExtent);
6608
0
            break;
6609
0
          }
6610
0
        case 'o':
6611
0
          {
6612
            /* Output filename */
6613
0
            if (image_info != (const ImageInfo *) NULL)
6614
0
              q+=(translate)(q,image_info->filename,MaxTextExtent);
6615
0
            break;
6616
0
          }
6617
0
        case 'p':
6618
0
          {
6619
            /* Page number */
6620
0
            register const Image
6621
0
              *frame;
6622
6623
0
            unsigned long
6624
0
              page;
6625
6626
0
            frame=image;
6627
0
            for (page=1; frame->previous != (Image *) NULL; page++)
6628
0
              frame=frame->previous;
6629
0
            MagickFormatString(buffer,sizeof(buffer),"%lu",page);
6630
0
            q+=(translate)(q,buffer,MaxTextExtent);
6631
0
            break;
6632
0
          }
6633
0
        case 'q':
6634
0
          {
6635
            /* Quantum depth */
6636
0
            if (GetPixelCachePresent(image))
6637
0
              MagickFormatString(buffer,sizeof(buffer),"%lu",
6638
0
                                 GetImageDepth(image,&image->exception));
6639
0
            else
6640
0
              MagickFormatString(buffer,sizeof(buffer),"%u",image->depth);
6641
0
            q+=(translate)(q,buffer,MaxTextExtent);
6642
0
            break;
6643
0
          }
6644
0
        case 'r':
6645
0
          {
6646
            /* Image type */
6647
0
            q+=(translate)(q,ImageTypeToString(GetImageType(image,&image->exception)),
6648
0
                           MaxTextExtent);
6649
0
            break;
6650
0
          }
6651
0
        case 's':
6652
0
          {
6653
            /* Scene number */
6654
0
            MagickFormatString(buffer,sizeof(buffer),"%lu",image->scene);
6655
0
            if (image_info != (const ImageInfo *) NULL)
6656
0
              if (image_info->subrange != 0)
6657
0
                MagickFormatString(buffer,sizeof(buffer),"%lu",image_info->subimage);
6658
0
            q+=(translate)(q,buffer,MaxTextExtent);
6659
0
            break;
6660
0
          }
6661
0
        case 'u':
6662
0
          {
6663
            /* Unique temporary filename */
6664
0
            if (image_info != (const ImageInfo *) NULL)
6665
0
              {
6666
0
                if (strlcpy(buffer,image_info->unique,MaxTextExtent) == 0)
6667
0
                  if (!AcquireTemporaryFileName(buffer))
6668
0
                    break;
6669
0
                q+=(translate)(q,buffer,MaxTextExtent);
6670
0
              }
6671
0
            break;
6672
0
          }
6673
0
        case 'w':
6674
0
          {
6675
            /* Image width */
6676
0
            MagickFormatString(buffer,sizeof(buffer),"%lu",image->columns);
6677
0
            q+=(translate)(q,buffer,MaxTextExtent);
6678
0
            break;
6679
0
          }
6680
0
        case 'x':
6681
0
          {
6682
            /* Horizontal resolution (default to 72.0 DPI if impossibly small) */
6683
0
            MagickFormatString(buffer,sizeof(buffer),"%g",
6684
0
                               fabs(image->x_resolution) > MagickEpsilon ? image->x_resolution :
6685
0
                               (image->units == PixelsPerCentimeterResolution ? 72.0/2.54 : 72.0));
6686
0
            q+=(translate)(q,buffer,MaxTextExtent);
6687
0
            break;
6688
0
          }
6689
0
        case 'y':
6690
0
          {
6691
            /* Vertical resolution (default to 72.0 DPI if impossibly small) */
6692
0
            MagickFormatString(buffer,sizeof(buffer),"%g",
6693
0
                               fabs(image->y_resolution) > MagickEpsilon ? image->y_resolution :
6694
0
                               (image->units == PixelsPerCentimeterResolution ? 72.0/2.54 : 72.0));
6695
0
            q+=(translate)(q,buffer,MaxTextExtent);
6696
0
            break;
6697
0
          }
6698
0
        case 'z':
6699
0
          {
6700
            /* Second unique temporary filename */
6701
0
            if (image_info != (const ImageInfo *) NULL)
6702
0
              {
6703
0
                if (strlcpy(buffer,image_info->zero,MaxTextExtent) == 0)
6704
0
                  if (!AcquireTemporaryFileName(buffer))
6705
0
                    break;
6706
0
                q+=(translate)(q,buffer,MaxTextExtent);
6707
0
              }
6708
0
            break;
6709
0
          }
6710
0
        case 'A':
6711
0
          {
6712
            /* Transparency supported */
6713
0
            MagickFormatString(buffer,sizeof(buffer),"%s",image->matte? "true" : "false");
6714
0
            q+=(translate)(q,buffer,MaxTextExtent);
6715
0
            break;
6716
0
          }
6717
0
        case 'C':
6718
0
          {
6719
            /* Image compression type */
6720
0
            MagickFormatString(buffer,sizeof(buffer),"%s",CompressionTypeToString(image->compression));
6721
0
            q+=(translate)(q,buffer,MaxTextExtent);
6722
0
            break;
6723
0
          }
6724
0
        case 'D':
6725
0
          {
6726
            /* GIF disposal method */
6727
0
            MagickFormatString(buffer,sizeof(buffer),"%d",image->dispose);
6728
0
            q+=(translate)(q,buffer,MaxTextExtent);
6729
0
            break;
6730
0
          }
6731
0
        case 'G':
6732
0
          {
6733
            /* Original image width and height */
6734
0
            MagickFormatString(buffer,sizeof(buffer),"%lux%lu",
6735
0
                               image->magick_columns,image->magick_rows);
6736
0
            q+=(translate)(q,buffer,MaxTextExtent);
6737
0
            break;
6738
0
          }
6739
0
        case 'H':
6740
0
          {
6741
            /* page height */
6742
0
            MagickFormatString(buffer,sizeof(buffer),"%lu",image->page.height);
6743
0
            q+=(translate)(q,buffer,MaxTextExtent);
6744
0
            break;
6745
0
          }
6746
0
        case 'M':
6747
0
          {
6748
            /* Original filename specification */
6749
0
            q+=(translate)(q,image->magick_filename,MaxTextExtent);
6750
0
            break;
6751
0
          }
6752
0
        case 'O':
6753
0
          {
6754
            /* page offset */
6755
0
            MagickFormatString(buffer,sizeof(buffer),"%+ld%+ld",
6756
0
                               image->page.x,image->page.y);
6757
0
            q+=(translate)(q,buffer,MaxTextExtent);
6758
0
            break;
6759
0
          }
6760
0
        case 'P':
6761
0
          {
6762
            /* page dimensions */
6763
0
            MagickFormatString(buffer,sizeof(buffer),"%lux%lu",
6764
0
                               image->page.width,image->page.height);
6765
0
            q+=(translate)(q,buffer,MaxTextExtent);
6766
0
            break;
6767
0
          }
6768
0
        case 'Q':
6769
0
          {
6770
            /* Compression quality */
6771
0
            attribute=GetImageAttribute(image,"JPEG-Quality");
6772
0
            if (attribute != (ImageAttribute *) NULL)
6773
0
              {
6774
0
                q+=(translate)(q,attribute->value,MaxTextExtent);
6775
0
                break;
6776
0
              }
6777
0
            if (image_info != (const ImageInfo *) NULL)
6778
0
              {
6779
0
                MagickFormatString(buffer,sizeof(buffer),"%lu",image_info->quality);
6780
0
                q+=(translate)(q,buffer,MaxTextExtent);
6781
0
                break;
6782
0
              }
6783
0
            MagickFormatString(buffer,sizeof(buffer),"%u",DefaultCompressionQuality);
6784
0
            q+=(translate)(q,buffer,MaxTextExtent);
6785
0
            break;
6786
0
          }
6787
0
        case 'T':
6788
0
          {
6789
            /* time delay (in centi-seconds) */
6790
0
            MagickFormatString(buffer,sizeof(buffer),"%lu",image->delay);
6791
0
            q+=(translate)(q,buffer,MaxTextExtent);
6792
0
            break;
6793
0
          }
6794
0
        case 'U':
6795
0
          {
6796
            /* resolution units */
6797
0
            MagickFormatString(buffer,sizeof(buffer),"%s",ResolutionTypeToString(image->units));
6798
0
            q+=(translate)(q,buffer,MaxTextExtent);
6799
0
            break;
6800
0
          }
6801
0
        case 'W':
6802
0
          {
6803
            /* page width */
6804
0
            MagickFormatString(buffer,sizeof(buffer),"%lu",image->page.width);
6805
0
            q+=(translate)(q,buffer,MaxTextExtent);
6806
0
            break;
6807
0
          }
6808
0
        case 'X':
6809
0
          {
6810
            /* page x offset */
6811
0
            MagickFormatString(buffer,sizeof(buffer),"%+ld",image->page.x);
6812
0
            q+=(translate)(q,buffer,MaxTextExtent);
6813
0
            break;
6814
0
          }
6815
0
        case 'Y':
6816
0
          {
6817
            /* page y offset */
6818
0
            MagickFormatString(buffer,sizeof(buffer),"%+ld",image->page.y);
6819
0
            q+=(translate)(q,buffer,MaxTextExtent);
6820
0
            break;
6821
0
          }
6822
0
        case '@':
6823
0
          {
6824
            /* trim bounding box */
6825
0
            RectangleInfo bounds = GetImageBoundingBox(image,
6826
0
                                                       &image->exception);
6827
0
            MagickFormatString(buffer,sizeof(buffer),"%lux%lu%+ld%+ld",
6828
0
                               bounds.width,bounds.height,bounds.x,bounds.y);
6829
0
            q+=(translate)(q,buffer,MaxTextExtent);
6830
0
            break;
6831
0
          }
6832
0
        case '[':
6833
0
          {
6834
            /* Image attribute */
6835
0
            char
6836
0
              key[MaxTextExtent];
6837
6838
            /*
6839
              Extract attribute key string.
6840
6841
              FIXME: does not handle nested specification so that
6842
              '%[[MVG]]' results in '[MVG]'.
6843
            */
6844
0
            p++;
6845
0
            for (i=0; (i < MaxTextExtent-1) && (*p) && (*p != ']'); i++)
6846
0
              {
6847
0
                key[i]=(*p++);
6848
0
              }
6849
0
            if (']' != *p)
6850
0
              break;
6851
0
            key[i]='\0';
6852
6853
            /* Try to get the attribute from image */
6854
0
            attribute=GetImageAttribute(image,key);
6855
6856
            /* Try to get the attribute from image_info */
6857
0
            if (attribute == (const ImageAttribute *) NULL)
6858
0
              if (image_info != (const ImageInfo *) NULL)
6859
0
                attribute=GetImageInfoAttribute(image_info,image,key);
6860
6861
0
            if (attribute != (const ImageAttribute *) NULL)
6862
0
              {
6863
                /* Attributes may be larger than MaxTextExtent so make
6864
                   sure there is sufficient memory allocated. Make sure
6865
                   that there is at least MaxTextExtent left available
6866
                   after we have concatenated our part. */
6867
0
                offset=q-translated_text;
6868
0
                if ((size_t) (offset+attribute->length+1+MaxTextExtent) >= length)
6869
0
                  {
6870
0
                    length += (attribute->length+1+2*MaxTextExtent);
6871
0
                    MagickReallocMemory(char *,translated_text,length);
6872
0
                    if (translated_text == (char *) NULL)
6873
0
                      break;
6874
0
                    q=translated_text+offset;
6875
0
                  }
6876
0
                q+=(translate)(q,attribute->value,attribute->length+1+MaxTextExtent);
6877
0
              }
6878
0
            break;
6879
0
          }
6880
0
        case '#':
6881
0
          {
6882
            /* If 'ping' mode was used, then there may be no pixel cache! */
6883
0
            if (GetPixelCachePresent(image))
6884
0
              {
6885
0
                (void) SignatureImage(image);
6886
0
                attribute=GetImageAttribute(image,"signature");
6887
0
                if (attribute != (ImageAttribute *) NULL)
6888
0
                  q+=(translate)(q,attribute->value,MaxTextExtent);
6889
0
              }
6890
0
            else
6891
0
              {
6892
0
                *q++='%';
6893
0
                *q++=(*p);
6894
0
              }
6895
0
            break;
6896
0
          }
6897
0
        case '%':
6898
0
          {
6899
            /* Pass through literal % */
6900
0
            *q++=(*p);
6901
0
            break;
6902
0
          }
6903
0
        default:
6904
0
          {
6905
            /* Pass through unknown codes */
6906
0
            *q++='%';
6907
0
            *q++=(*p);
6908
0
            break;
6909
0
          }
6910
0
        }
6911
0
      if (*p == '\0')
6912
0
        break;
6913
0
    }
6914
0
  *q='\0';
6915
0
  if (text != (char *) formatted_text)
6916
0
    MagickFreeMemory(text);
6917
0
  return(translated_text);
6918
0
}