utility.c revision 6f008fdcea6389206e36baf0f05c8999c7366f7b
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%             U   U  TTTTT  IIIII  L      IIIII  TTTTT  Y   Y                 %
7%             U   U    T      I    L        I      T     Y Y                  %
8%             U   U    T      I    L        I      T      Y                   %
9%             U   U    T      I    L        I      T      Y                   %
10%              UUU     T    IIIII  LLLLL  IIIII    T      Y                   %
11%                                                                             %
12%                                                                             %
13%                       MagickCore Utility Methods                            %
14%                                                                             %
15%                             Software Design                                 %
16%                                  Cristy                                     %
17%                              January 1993                                   %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization      %
21%  dedicated to making software imaging solutions freely available.           %
22%                                                                             %
23%  You may not use this file except in compliance with the License.  You may  %
24%  obtain a copy of the License at                                            %
25%                                                                             %
26%    http://www.imagemagick.org/script/license.php                            %
27%                                                                             %
28%  Unless required by applicable law or agreed to in writing, software        %
29%  distributed under the License is distributed on an "AS IS" BASIS,          %
30%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31%  See the License for the specific language governing permissions and        %
32%  limitations under the License.                                             %
33%                                                                             %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37*/
38
39/*
40  Include declarations.
41*/
42#include "MagickCore/studio.h"
43#include "MagickCore/property.h"
44#include "MagickCore/blob.h"
45#include "MagickCore/color.h"
46#include "MagickCore/exception.h"
47#include "MagickCore/exception-private.h"
48#include "MagickCore/geometry.h"
49#include "MagickCore/list.h"
50#include "MagickCore/log.h"
51#include "MagickCore/magick-private.h"
52#include "MagickCore/memory_.h"
53#include "MagickCore/nt-base-private.h"
54#include "MagickCore/option.h"
55#include "MagickCore/policy.h"
56#include "MagickCore/random_.h"
57#include "MagickCore/registry.h"
58#include "MagickCore/resource_.h"
59#include "MagickCore/semaphore.h"
60#include "MagickCore/signature-private.h"
61#include "MagickCore/statistic.h"
62#include "MagickCore/string_.h"
63#include "MagickCore/string-private.h"
64#include "MagickCore/token.h"
65#include "MagickCore/token-private.h"
66#include "MagickCore/utility.h"
67#include "MagickCore/utility-private.h"
68#if defined(MAGICKCORE_HAVE_PROCESS_H)
69#include <process.h>
70#endif
71#if defined(MAGICKCORE_HAVE_MACH_O_DYLD_H)
72#include <mach-o/dyld.h>
73#endif
74
75/*
76  Static declarations.
77*/
78static const char
79  Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
80
81/*
82  Forward declaration.
83*/
84static int
85  IsPathDirectory(const char *);
86
87/*
88%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
89%                                                                             %
90%                                                                             %
91%                                                                             %
92%   A c q u i r e U n i q u e F i l e n a m e                                 %
93%                                                                             %
94%                                                                             %
95%                                                                             %
96%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
97%
98%  AcquireUniqueFilename() replaces the contents of path by a unique path name.
99%
100%  The format of the AcquireUniqueFilename method is:
101%
102%      MagickBooleanType AcquireUniqueFilename(char *path)
103%
104%  A description of each parameter follows.
105%
106%   o  path:  Specifies a pointer to an array of characters.  The unique path
107%      name is returned in this array.
108%
109*/
110MagickExport MagickBooleanType AcquireUniqueFilename(char *path)
111{
112  int
113    file;
114
115  file=AcquireUniqueFileResource(path);
116  if (file == -1)
117    return(MagickFalse);
118  file=close(file)-1;
119  return(MagickTrue);
120}
121
122/*
123%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
124%                                                                             %
125%                                                                             %
126%                                                                             %
127%   A c q u i r e U n i q u e S ym b o l i c L i n k                          %
128%                                                                             %
129%                                                                             %
130%                                                                             %
131%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
132%
133%  AcquireUniqueSymbolicLink() creates a unique symbolic link to the specified
134%  source path and returns MagickTrue on success otherwise MagickFalse.  If the
135%  symlink() method fails or is not available, a unique file name is generated
136%  and the source file copied to it.  When you are finished with the file, use
137%  RelinquishUniqueFilename() to destroy it.
138%
139%  The format of the AcquireUniqueSymbolicLink method is:
140%
141%      MagickBooleanType AcquireUniqueSymbolicLink(const char *source,
142%        char destination)
143%
144%  A description of each parameter follows.
145%
146%   o  source:  the source path.
147%
148%   o  destination:  the destination path.
149%
150*/
151
152static inline MagickSizeType MagickMin(const MagickSizeType x,
153  const MagickSizeType y)
154{
155  if (x < y)
156    return(x);
157  return(y);
158}
159
160MagickExport MagickBooleanType AcquireUniqueSymbolicLink(const char *source,
161  char *destination)
162{
163  int
164    destination_file,
165    source_file;
166
167  size_t
168    length,
169    quantum;
170
171  ssize_t
172    count;
173
174  struct stat
175    attributes;
176
177  unsigned char
178    *buffer;
179
180  assert(source != (const char *) NULL);
181  assert(destination != (char *) NULL);
182#if defined(MAGICKCORE_HAVE_SYMLINK)
183  (void) AcquireUniqueFilename(destination);
184  (void) RelinquishUniqueFileResource(destination);
185  if (*source == *DirectorySeparator)
186    {
187      if (symlink(source,destination) == 0)
188        return(MagickTrue);
189    }
190  else
191    {
192      char
193        path[MaxTextExtent];
194
195      *path='\0';
196      if (getcwd(path,MaxTextExtent) == (char *) NULL)
197        return(MagickFalse);
198      (void) ConcatenateMagickString(path,DirectorySeparator,MaxTextExtent);
199      (void) ConcatenateMagickString(path,source,MaxTextExtent);
200      if (symlink(path,destination) == 0)
201        return(MagickTrue);
202    }
203#endif
204  destination_file=AcquireUniqueFileResource(destination);
205  if (destination_file == -1)
206    return(MagickFalse);
207  source_file=open_utf8(source,O_RDONLY | O_BINARY,0);
208  if (source_file == -1)
209    {
210      (void) close(destination_file);
211      (void) RelinquishUniqueFileResource(destination);
212      return(MagickFalse);
213    }
214  quantum=(size_t) MagickMaxBufferExtent;
215  if ((fstat(source_file,&attributes) == 0) && (attributes.st_size != 0))
216    quantum=(size_t) MagickMin((size_t) attributes.st_size,
217      MagickMaxBufferExtent);
218  buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
219  if (buffer == (unsigned char *) NULL)
220    {
221      (void) close(source_file);
222      (void) close(destination_file);
223      (void) RelinquishUniqueFileResource(destination);
224      return(MagickFalse);
225    }
226  for (length=0; ; )
227  {
228    count=(ssize_t) read(source_file,buffer,quantum);
229    if (count <= 0)
230      break;
231    length=(size_t) count;
232    count=(ssize_t) write(destination_file,buffer,length);
233    if ((size_t) count != length)
234      {
235        (void) close(destination_file);
236        (void) close(source_file);
237        buffer=(unsigned char *) RelinquishMagickMemory(buffer);
238        (void) RelinquishUniqueFileResource(destination);
239        return(MagickFalse);
240      }
241  }
242  (void) close(destination_file);
243  (void) close(source_file);
244  buffer=(unsigned char *) RelinquishMagickMemory(buffer);
245  return(MagickTrue);
246}
247
248/*
249%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
250%                                                                             %
251%                                                                             %
252%                                                                             %
253%  A p p e n d I m a g e F o r m a t                                          %
254%                                                                             %
255%                                                                             %
256%                                                                             %
257%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
258%
259%  AppendImageFormat() appends the image format type to the filename.  If an
260%  extension to the file already exists, it is first removed.
261%
262%  The format of the AppendImageFormat method is:
263%
264%      void AppendImageFormat(const char *format,char *filename)
265%
266%  A description of each parameter follows.
267%
268%   o  format:  Specifies a pointer to an array of characters.  This the
269%      format of the image.
270%
271%   o  filename:  Specifies a pointer to an array of characters.  The unique
272%      file name is returned in this array.
273%
274*/
275MagickExport void AppendImageFormat(const char *format,char *filename)
276{
277  char
278    extension[MaxTextExtent],
279    root[MaxTextExtent];
280
281  assert(format != (char *) NULL);
282  assert(filename != (char *) NULL);
283  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",filename);
284  if ((*format == '\0') || (*filename == '\0'))
285    return;
286  if (LocaleCompare(filename,"-") == 0)
287    {
288      char
289        message[MaxTextExtent];
290
291      (void) FormatLocaleString(message,MaxTextExtent,"%s:%s",format,filename);
292      (void) CopyMagickString(filename,message,MaxTextExtent);
293      return;
294    }
295  GetPathComponent(filename,ExtensionPath,extension);
296  if ((LocaleCompare(extension,"Z") == 0) ||
297      (LocaleCompare(extension,"bz2") == 0) ||
298      (LocaleCompare(extension,"gz") == 0) ||
299      (LocaleCompare(extension,"wmz") == 0) ||
300      (LocaleCompare(extension,"svgz") == 0))
301    {
302      GetPathComponent(filename,RootPath,root);
303      (void) CopyMagickString(filename,root,MaxTextExtent);
304      GetPathComponent(filename,RootPath,root);
305      (void) FormatLocaleString(filename,MaxTextExtent,"%s.%s.%s",root,format,
306        extension);
307      return;
308    }
309  GetPathComponent(filename,RootPath,root);
310  (void) FormatLocaleString(filename,MaxTextExtent,"%s.%s",root,format);
311}
312
313/*
314%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
315%                                                                             %
316%                                                                             %
317%                                                                             %
318%   B a s e 6 4 D e c o d e                                                   %
319%                                                                             %
320%                                                                             %
321%                                                                             %
322%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
323%
324%  Base64Decode() decodes Base64-encoded text and returns its binary
325%  equivalent.  NULL is returned if the text is not valid Base64 data, or a
326%  memory allocation failure occurs.
327%
328%  The format of the Base64Decode method is:
329%
330%      unsigned char *Base64Decode(const char *source,length_t *length)
331%
332%  A description of each parameter follows:
333%
334%    o source:  A pointer to a Base64-encoded string.
335%
336%    o length: the number of bytes decoded.
337%
338*/
339MagickExport unsigned char *Base64Decode(const char *source,size_t *length)
340{
341  int
342    state;
343
344  register const char
345    *p,
346    *q;
347
348  register size_t
349    i;
350
351  unsigned char
352    *decode;
353
354  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
355  assert(source != (char *) NULL);
356  assert(length != (size_t *) NULL);
357  *length=0;
358  decode=(unsigned char *) AcquireQuantumMemory(strlen(source)/4+4,
359    3*sizeof(*decode));
360  if (decode == (unsigned char *) NULL)
361    return((unsigned char *) NULL);
362  i=0;
363  state=0;
364  for (p=source; *p != '\0'; p++)
365  {
366    if (isspace((int) ((unsigned char) *p)) != 0)
367      continue;
368    if (*p == '=')
369      break;
370    q=strchr(Base64,*p);
371    if (q == (char *) NULL)
372      {
373        decode=(unsigned char *) RelinquishMagickMemory(decode);
374        return((unsigned char *) NULL);  /* non-Base64 character */
375      }
376    switch (state)
377    {
378      case 0:
379      {
380        decode[i]=(q-Base64) << 2;
381        state++;
382        break;
383      }
384      case 1:
385      {
386        decode[i++]|=(q-Base64) >> 4;
387        decode[i]=((q-Base64) & 0x0f) << 4;
388        state++;
389        break;
390      }
391      case 2:
392      {
393        decode[i++]|=(q-Base64) >> 2;
394        decode[i]=((q-Base64) & 0x03) << 6;
395        state++;
396        break;
397      }
398      case 3:
399      {
400        decode[i++]|=(q-Base64);
401        state=0;
402        break;
403      }
404    }
405  }
406  /*
407    Verify Base-64 string has proper terminal characters.
408  */
409  if (*p != '=')
410    {
411      if (state != 0)
412        {
413          decode=(unsigned char *) RelinquishMagickMemory(decode);
414          return((unsigned char *) NULL);
415        }
416    }
417  else
418    {
419      p++;
420      switch (state)
421      {
422        case 0:
423        case 1:
424        {
425          /*
426            Unrecognized '=' character.
427          */
428          decode=(unsigned char *) RelinquishMagickMemory(decode);
429          return((unsigned char *) NULL);
430        }
431        case 2:
432        {
433          for ( ; *p != '\0'; p++)
434            if (isspace((int) ((unsigned char) *p)) == 0)
435              break;
436          if (*p != '=')
437            {
438              decode=(unsigned char *) RelinquishMagickMemory(decode);
439              return((unsigned char *) NULL);
440            }
441          p++;
442        }
443        case 3:
444        {
445          for ( ; *p != '\0'; p++)
446            if (isspace((int) ((unsigned char) *p)) == 0)
447              {
448                decode=(unsigned char *) RelinquishMagickMemory(decode);
449                return((unsigned char *) NULL);
450              }
451          if ((int) decode[i] != 0)
452            {
453              decode=(unsigned char *) RelinquishMagickMemory(decode);
454              return((unsigned char *) NULL);
455            }
456          break;
457        }
458      }
459    }
460  *length=i;
461  return(decode);
462}
463
464/*
465%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
466%                                                                             %
467%                                                                             %
468%                                                                             %
469%   B a s e 6 4 E n c o d e                                                   %
470%                                                                             %
471%                                                                             %
472%                                                                             %
473%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
474%
475%  Base64Encode() encodes arbitrary binary data to Base64 encoded format as
476%  described by the "Base64 Content-Transfer-Encoding" section of RFC 2045 and
477%  returns the result as a null-terminated ASCII string.  NULL is returned if
478%  a memory allocation failure occurs.
479%
480%  The format of the Base64Encode method is:
481%
482%      char *Base64Encode(const unsigned char *blob,const size_t blob_length,
483%        size_t *encode_length)
484%
485%  A description of each parameter follows:
486%
487%    o blob:  A pointer to binary data to encode.
488%
489%    o blob_length: the number of bytes to encode.
490%
491%    o encode_length:  The number of bytes encoded.
492%
493*/
494MagickExport char *Base64Encode(const unsigned char *blob,
495  const size_t blob_length,size_t *encode_length)
496{
497  char
498    *encode;
499
500  register const unsigned char
501    *p;
502
503  register size_t
504    i;
505
506  size_t
507    remainder;
508
509  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
510  assert(blob != (const unsigned char *) NULL);
511  assert(blob_length != 0);
512  assert(encode_length != (size_t *) NULL);
513  *encode_length=0;
514  encode=(char *) AcquireQuantumMemory(blob_length/3+4,4*sizeof(*encode));
515  if (encode == (char *) NULL)
516    return((char *) NULL);
517  i=0;
518  for (p=blob; p < (blob+blob_length-2); p+=3)
519  {
520    encode[i++]=Base64[(int) (*p >> 2)];
521    encode[i++]=Base64[(int) (((*p & 0x03) << 4)+(*(p+1) >> 4))];
522    encode[i++]=Base64[(int) (((*(p+1) & 0x0f) << 2)+(*(p+2) >> 6))];
523    encode[i++]=Base64[(int) (*(p+2) & 0x3f)];
524  }
525  remainder=blob_length % 3;
526  if (remainder != 0)
527    {
528      ssize_t
529        j;
530
531      unsigned char
532        code[3];
533
534      code[0]='\0';
535      code[1]='\0';
536      code[2]='\0';
537      for (j=0; j < (ssize_t) remainder; j++)
538        code[j]=(*p++);
539      encode[i++]=Base64[(int) (code[0] >> 2)];
540      encode[i++]=Base64[(int) (((code[0] & 0x03) << 4)+(code[1] >> 4))];
541      if (remainder == 1)
542        encode[i++]='=';
543      else
544        encode[i++]=Base64[(int) (((code[1] & 0x0f) << 2)+(code[2] >> 6))];
545      encode[i++]='=';
546    }
547  *encode_length=i;
548  encode[i++]='\0';
549  return(encode);
550}
551
552/*
553%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
554%                                                                             %
555%                                                                             %
556%                                                                             %
557%   C h o p P a t h C o m p o n e n t s                                       %
558%                                                                             %
559%                                                                             %
560%                                                                             %
561%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
562%
563%  ChopPathComponents() removes the number of specified file components from a
564%  path.
565%
566%  The format of the ChopPathComponents method is:
567%
568%      ChopPathComponents(char *path,size_t components)
569%
570%  A description of each parameter follows:
571%
572%    o path:  The path.
573%
574%    o components:  The number of components to chop.
575%
576*/
577MagickPrivate void ChopPathComponents(char *path,const size_t components)
578{
579  register ssize_t
580    i;
581
582  for (i=0; i < (ssize_t) components; i++)
583    GetPathComponent(path,HeadPath,path);
584}
585
586/*
587%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
588%                                                                             %
589%                                                                             %
590%                                                                             %
591%   E x p a n d F i l e n a m e                                               %
592%                                                                             %
593%                                                                             %
594%                                                                             %
595%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
596%
597%  ExpandFilename() expands '~' in a path.
598%
599%  The format of the ExpandFilename function is:
600%
601%      ExpandFilename(char *path)
602%
603%  A description of each parameter follows:
604%
605%    o path: Specifies a pointer to a character array that contains the
606%      path.
607%
608*/
609MagickPrivate void ExpandFilename(char *path)
610{
611  char
612    expand_path[MaxTextExtent];
613
614  if (path == (char *) NULL)
615    return;
616  if (*path != '~')
617    return;
618  (void) CopyMagickString(expand_path,path,MaxTextExtent);
619  if ((*(path+1) == *DirectorySeparator) || (*(path+1) == '\0'))
620    {
621      char
622        *home;
623
624      /*
625        Substitute ~ with $HOME.
626      */
627      (void) CopyMagickString(expand_path,".",MaxTextExtent);
628      (void) ConcatenateMagickString(expand_path,path+1,MaxTextExtent);
629      home=GetEnvironmentValue("HOME");
630      if (home == (char *) NULL)
631        home=GetEnvironmentValue("USERPROFILE");
632      if (home != (char *) NULL)
633        {
634          (void) CopyMagickString(expand_path,home,MaxTextExtent);
635          (void) ConcatenateMagickString(expand_path,path+1,MaxTextExtent);
636          home=DestroyString(home);
637        }
638    }
639  else
640    {
641#if defined(MAGICKCORE_POSIX_SUPPORT) && !defined(__OS2__)
642      char
643        username[MaxTextExtent];
644
645      register char
646        *p;
647
648      struct passwd
649        *entry;
650
651      /*
652        Substitute ~ with home directory from password file.
653      */
654      (void) CopyMagickString(username,path+1,MaxTextExtent);
655      p=strchr(username,'/');
656      if (p != (char *) NULL)
657        *p='\0';
658      entry=getpwnam(username);
659      if (entry == (struct passwd *) NULL)
660        return;
661      (void) CopyMagickString(expand_path,entry->pw_dir,MaxTextExtent);
662      if (p != (char *) NULL)
663        {
664          (void) ConcatenateMagickString(expand_path,"/",MaxTextExtent);
665          (void) ConcatenateMagickString(expand_path,p+1,MaxTextExtent);
666        }
667#endif
668    }
669  (void) CopyMagickString(path,expand_path,MaxTextExtent);
670}
671
672/*
673%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
674%                                                                             %
675%                                                                             %
676%                                                                             %
677%   E x p a n d F i l e n a m e s                                             %
678%                                                                             %
679%                                                                             %
680%                                                                             %
681%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
682%
683%  ExpandFilenames() checks each argument of the given argument array, and
684%  expands it if they have a wildcard character.
685%
686%  Any coder prefix (EG: 'coder:filename') or read modifier postfix (EG:
687%  'filename[...]') are ignored during the file the expansion, but will be
688%  included in the final argument.  If no filename matching the meta-character
689%  'glob' is found the original argument is returned.
690%
691%  For example, an argument of '*.gif[20x20]' will be replaced by the list
692%    'abc.gif[20x20]',  'foobar.gif[20x20]',  'xyzzy.gif[20x20]'
693%  if such filenames exist, (in the current directory in this case).
694%
695%  Meta-characters handled...
696%     @    read a list of filenames (no further expansion performed)
697%     ~    At start of filename expands to HOME environemtn variable
698%     *    matches any string including an empty string
699%     ?    matches by any single character
700%
701%  WARNING: filenames starting with '.' (hidden files in a UNIX file system)
702%  will never be expanded.  Attempting to epand '.*' will produce no change.
703%
704%  Expansion is ignored for coders "label:" "caption:" "pango:" and "vid:".
705%  Which provide their own '@' meta-character handling.
706%
707%  You can see the results of the expansion using "Configure" log events.
708%
709%  The returned list should be freed using  DestroyStringList().
710%
711%  However the strings in the original pointed to argv are not
712%  freed  (TO BE CHECKED).  So a copy of the original pointer (and count)
713%  should be kept separate if they need to be freed later.
714%
715%  The format of the ExpandFilenames function is:
716%
717%      status=ExpandFilenames(int *number_arguments,char ***arguments)
718%
719%  A description of each parameter follows:
720%
721%    o number_arguments: Specifies a pointer to an integer describing the
722%      number of elements in the argument vector.
723%
724%    o arguments: Specifies a pointer to a text array containing the command
725%      line arguments.
726%
727*/
728MagickExport MagickBooleanType ExpandFilenames(int *number_arguments,
729  char ***arguments)
730{
731  char
732    *directory,
733    home_directory[MaxTextExtent],
734    **vector;
735
736  register ssize_t
737    i,
738    j;
739
740  size_t
741    number_files;
742
743  ssize_t
744    count,
745    parameters;
746
747  /*
748    Allocate argument vector.
749  */
750  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
751  assert(number_arguments != (int *) NULL);
752  assert(arguments != (char ***) NULL);
753  vector=(char **) AcquireQuantumMemory((size_t) (*number_arguments+1),
754    sizeof(*vector));
755  if (vector == (char **) NULL)
756    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
757  /*
758    Expand any wildcard filenames.
759  */
760  *home_directory='\0';
761  count=0;
762  for (i=0; i < (ssize_t) *number_arguments; i++)
763  {
764    char
765      **filelist,
766      filename[MaxTextExtent],
767      magick[MaxTextExtent],
768      *option,
769      path[MaxTextExtent],
770      subimage[MaxTextExtent];
771
772    MagickBooleanType
773      destroy;
774
775    option=(*arguments)[i];
776    *magick='\0';
777    *path='\0';
778    *filename='\0';
779    *subimage='\0';
780    number_files=0;
781    vector[count++]=ConstantString(option);
782    destroy=MagickTrue;
783    parameters=ParseCommandOption(MagickCommandOptions,MagickFalse,option);
784    if (parameters > 0)
785      {
786        /*
787          Do not expand command option parameters.
788        */
789        for (j=0; j < parameters; j++)
790        {
791          i++;
792          if (i == (ssize_t) *number_arguments)
793            break;
794          option=(*arguments)[i];
795          vector[count++]=ConstantString(option);
796        }
797        continue;
798      }
799    if ((*option == '"') || (*option == '\''))
800      continue;
801    GetPathComponent(option,TailPath,filename);
802    GetPathComponent(option,MagickPath,magick);
803    if ((LocaleCompare(magick,"CAPTION") == 0) ||
804        (LocaleCompare(magick,"LABEL") == 0) ||
805        (LocaleCompare(magick,"PANGO") == 0) ||
806        (LocaleCompare(magick,"VID") == 0))
807      continue;
808    if ((IsGlob(filename) == MagickFalse) && (*option != '@'))
809      continue;
810    if (*option != '@')
811      {
812        /*
813          Generate file list from wildcard filename (e.g. *.jpg).
814        */
815        GetPathComponent(option,HeadPath,path);
816        GetPathComponent(option,SubimagePath,subimage);
817        ExpandFilename(path);
818        if (*home_directory == '\0')
819          directory=getcwd(home_directory,MaxTextExtent-1);
820        (void) directory;
821        filelist=ListFiles(*path == '\0' ? home_directory : path,filename,
822          &number_files);
823      }
824    else
825      {
826        char
827          *files;
828
829        ExceptionInfo
830          *exception;
831
832        int
833          length;
834
835        /*
836          Generate file list from file list (e.g. @filelist.txt).
837        */
838        exception=AcquireExceptionInfo();
839        files=FileToString(option+1,~0UL,exception);
840        exception=DestroyExceptionInfo(exception);
841        if (files == (char *) NULL)
842          continue;
843        filelist=StringToArgv(files,&length);
844        if (filelist == (char **) NULL)
845          continue;
846        files=DestroyString(files);
847        filelist[0]=DestroyString(filelist[0]);
848        for (j=0; j < (ssize_t) (length-1); j++)
849          filelist[j]=filelist[j+1];
850        number_files=(size_t) length-1;
851      }
852    if (filelist == (char **) NULL)
853      continue;
854    for (j=0; j < (ssize_t) number_files; j++)
855      if (IsPathDirectory(filelist[j]) <= 0)
856        break;
857    if (j == (ssize_t) number_files)
858      {
859        for (j=0; j < (ssize_t) number_files; j++)
860          filelist[j]=DestroyString(filelist[j]);
861        filelist=(char **) RelinquishMagickMemory(filelist);
862        continue;
863      }
864    /*
865      Transfer file list to argument vector.
866    */
867    vector=(char **) ResizeQuantumMemory(vector,(size_t) *number_arguments+
868      count+number_files+1,sizeof(*vector));
869    if (vector == (char **) NULL)
870      return(MagickFalse);
871    for (j=0; j < (ssize_t) number_files; j++)
872    {
873      option=filelist[j];
874      parameters=ParseCommandOption(MagickCommandOptions,MagickFalse,option);
875      if (parameters > 0)
876        {
877          ssize_t
878            k;
879
880          /*
881            Do not expand command option parameters.
882          */
883          vector[count++]=ConstantString(option);
884          for (k=0; k < parameters; k++)
885          {
886            j++;
887            if (j == (ssize_t) number_files)
888              break;
889            option=filelist[j];
890            vector[count++]=ConstantString(option);
891          }
892          continue;
893        }
894      (void) CopyMagickString(filename,path,MaxTextExtent);
895      if (*path != '\0')
896        (void) ConcatenateMagickString(filename,DirectorySeparator,
897          MaxTextExtent);
898      if (filelist[j] != (char *) NULL)
899        (void) ConcatenateMagickString(filename,filelist[j],MaxTextExtent);
900      filelist[j]=DestroyString(filelist[j]);
901      if (strlen(filename) >= (MaxTextExtent-1))
902        ThrowFatalException(OptionFatalError,"FilenameTruncated");
903      if (IsPathDirectory(filename) <= 0)
904        {
905          char
906            path[MaxTextExtent];
907
908          *path='\0';
909          if (*magick != '\0')
910            {
911              (void) ConcatenateMagickString(path,magick,MaxTextExtent);
912              (void) ConcatenateMagickString(path,":",MaxTextExtent);
913            }
914          (void) ConcatenateMagickString(path,filename,MaxTextExtent);
915          if (*subimage != '\0')
916            {
917              (void) ConcatenateMagickString(path,"[",MaxTextExtent);
918              (void) ConcatenateMagickString(path,subimage,MaxTextExtent);
919              (void) ConcatenateMagickString(path,"]",MaxTextExtent);
920            }
921          if (strlen(path) >= (MaxTextExtent-1))
922            ThrowFatalException(OptionFatalError,"FilenameTruncated");
923          if (destroy != MagickFalse)
924            {
925              count--;
926              vector[count]=DestroyString(vector[count]);
927              destroy=MagickFalse;
928            }
929          vector[count++]=ConstantString(path);
930        }
931    }
932    filelist=(char **) RelinquishMagickMemory(filelist);
933  }
934  vector[count]=(char *) NULL;
935  if (IsEventLogging() != MagickFalse)
936    {
937      char
938        *command_line;
939
940      command_line=AcquireString(vector[0]);
941      for (i=1; i < count; i++)
942      {
943        (void) ConcatenateString(&command_line," {");
944        (void) ConcatenateString(&command_line,vector[i]);
945        (void) ConcatenateString(&command_line,"}");
946      }
947      (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
948        "Command line: %s",command_line);
949      command_line=DestroyString(command_line);
950    }
951  *number_arguments=(int) count;
952  *arguments=vector;
953  return(MagickTrue);
954}
955
956/*
957%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
958%                                                                             %
959%                                                                             %
960%                                                                             %
961%   G e t E x e c u t i o n P a t h                                           %
962%                                                                             %
963%                                                                             %
964%                                                                             %
965%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
966%
967%  GetExecutionPath() returns the pathname of the executable that started
968%  the process.  On success MagickTrue is returned, otherwise MagickFalse.
969%
970%  The format of the GetExecutionPath method is:
971%
972%      MagickBooleanType GetExecutionPath(char *path,const size_t extent)
973%
974%  A description of each parameter follows:
975%
976%    o path: the pathname of the executable that started the process.
977%
978%    o extent: the maximum extent of the path.
979%
980*/
981MagickPrivate MagickBooleanType GetExecutionPath(char *path,const size_t extent)
982{
983  char
984    *directory;
985
986  *path='\0';
987  directory=getcwd(path,(unsigned long) extent);
988  (void) directory;
989#if defined(MAGICKCORE_HAVE_GETPID) && defined(MAGICKCORE_HAVE_READLINK) && defined(PATH_MAX)
990  {
991    char
992      link_path[MaxTextExtent],
993      execution_path[PATH_MAX+1];
994
995    ssize_t
996      count;
997
998    (void) FormatLocaleString(link_path,MaxTextExtent,"/proc/%.20g/exe",
999      (double) getpid());
1000    count=readlink(link_path,execution_path,PATH_MAX);
1001    if (count == -1)
1002      {
1003        (void) FormatLocaleString(link_path,MaxTextExtent,"/proc/%.20g/file",
1004          (double) getpid());
1005        count=readlink(link_path,execution_path,PATH_MAX);
1006      }
1007    if ((count > 0) && (count <= (ssize_t) PATH_MAX))
1008      {
1009        execution_path[count]='\0';
1010        (void) CopyMagickString(path,execution_path,extent);
1011      }
1012  }
1013#endif
1014#if defined(MAGICKCORE_HAVE__NSGETEXECUTABLEPATH)
1015  {
1016    char
1017      executable_path[PATH_MAX << 1],
1018      execution_path[PATH_MAX+1];
1019
1020    uint32_t
1021      length;
1022
1023    length=sizeof(executable_path);
1024    if ((_NSGetExecutablePath(executable_path,&length) == 0) &&
1025        (realpath(executable_path,execution_path) != (char *) NULL))
1026      (void) CopyMagickString(path,execution_path,extent);
1027  }
1028#endif
1029#if defined(MAGICKCORE_HAVE_GETEXECNAME)
1030  {
1031    const char
1032      *execution_path;
1033
1034    execution_path=(const char *) getexecname();
1035    if (execution_path != (const char *) NULL)
1036      {
1037        if (*execution_path != *DirectorySeparator)
1038          (void) ConcatenateMagickString(path,DirectorySeparator,extent);
1039        (void) ConcatenateMagickString(path,execution_path,extent);
1040      }
1041  }
1042#endif
1043#if defined(MAGICKCORE_WINDOWS_SUPPORT)
1044  NTGetExecutionPath(path,extent);
1045#endif
1046#if defined(__GNU__)
1047  {
1048    char
1049      *program_name,
1050      *execution_path;
1051
1052    ssize_t
1053      count;
1054
1055    count=0;
1056    execution_path=(char *) NULL;
1057    program_name=program_invocation_name;
1058    if (*program_invocation_name != '/')
1059      {
1060        size_t
1061          extent;
1062
1063        extent=strlen(directory)+strlen(program_name)+2;
1064        program_name=AcquireQuantumMemory(extent,sizeof(*program_name));
1065        if (program_name == (char *) NULL)
1066          program_name=program_invocation_name;
1067        else
1068          count=FormatLocaleString(program_name,extent,"%s/%s",directory,
1069            program_invocation_name);
1070      }
1071    if (count != -1)
1072      {
1073        execution_path=realpath(program_name,NULL);
1074        if (execution_path != (char *) NULL)
1075          (void) CopyMagickString(path,execution_path,extent);
1076      }
1077    if (program_name != program_invocation_name)
1078      program_name=(char *) RelinquishMagickMemory(program_name);
1079    execution_path=(char *) RelinquishMagickMemory(execution_path);
1080  }
1081#endif
1082#if defined(__OpenBSD__)
1083  {
1084    extern char
1085      *__progname;
1086
1087    (void) CopyMagickString(path,__progname,extent);
1088  }
1089#endif
1090  return(IsPathAccessible(path));
1091}
1092
1093/*
1094%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1095%                                                                             %
1096%                                                                             %
1097%                                                                             %
1098%   G e t M a g i c k P a g e S i z e                                         %
1099%                                                                             %
1100%                                                                             %
1101%                                                                             %
1102%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1103%
1104%  GetMagickPageSize() returns the memory page size.
1105%
1106%  The format of the GetMagickPageSize method is:
1107%
1108%      ssize_t GetMagickPageSize()
1109%
1110*/
1111MagickPrivate ssize_t GetMagickPageSize(void)
1112{
1113  static ssize_t
1114    page_size = -1;
1115
1116  if (page_size > 0)
1117    return(page_size);
1118#if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
1119  page_size=(ssize_t) sysconf(_SC_PAGE_SIZE);
1120#else
1121#if defined(MAGICKCORE_HAVE_GETPAGESIZE)
1122  page_size=(ssize_t) getpagesize();
1123#endif
1124#endif
1125  if (page_size <= 0)
1126    page_size=16384;
1127  return(page_size);
1128}
1129
1130/*
1131%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1132%                                                                             %
1133%                                                                             %
1134%                                                                             %
1135%   G e t P a t h A t t r i b u t e s                                         %
1136%                                                                             %
1137%                                                                             %
1138%                                                                             %
1139%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1140%
1141%  GetPathAttributes() returns attributes (e.g. size of file) about a path.
1142%
1143%  The path of the GetPathAttributes method is:
1144%
1145%      MagickBooleanType GetPathAttributes(const char *path,void *attributes)
1146%
1147%  A description of each parameter follows.
1148%
1149%   o  path: the file path.
1150%
1151%   o  attributes: the path attributes are returned here.
1152%
1153*/
1154MagickExport MagickBooleanType GetPathAttributes(const char *path,
1155  void *attributes)
1156{
1157  MagickBooleanType
1158    status;
1159
1160  if (path == (const char *) NULL)
1161    {
1162      errno=EINVAL;
1163      return(MagickFalse);
1164    }
1165  status=stat_utf8(path,(struct stat *) attributes) == 0 ? MagickTrue :
1166    MagickFalse;
1167  return(status);
1168}
1169
1170/*
1171%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1172%                                                                             %
1173%                                                                             %
1174%                                                                             %
1175%   G e t P a t h C o m p o n e n t                                           %
1176%                                                                             %
1177%                                                                             %
1178%                                                                             %
1179%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1180%
1181%  GetPathComponent() returns the parent directory name, filename, basename, or
1182%  extension of a file path.
1183%
1184%  The component string pointed to must have at least MaxTextExtent space
1185%  for the results to be stored.
1186%
1187%  The format of the GetPathComponent function is:
1188%
1189%      GetPathComponent(const char *path,PathType type,char *component)
1190%
1191%  A description of each parameter follows:
1192%
1193%    o path: Specifies a pointer to a character array that contains the
1194%      file path.
1195%
1196%    o type: Specififies which file path component to return.
1197%
1198%    o component: the selected file path component is returned here.
1199%
1200*/
1201MagickExport void GetPathComponent(const char *path,PathType type,
1202  char *component)
1203{
1204  char
1205    magick[MaxTextExtent],
1206    *q,
1207    subimage[MaxTextExtent];
1208
1209  register char
1210    *p;
1211
1212  assert(path != (const char *) NULL);
1213  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",path);
1214  assert(component != (char *) NULL);
1215  if (*path == '\0')
1216    {
1217      *component='\0';
1218      return;
1219    }
1220  (void) CopyMagickString(component,path,MaxTextExtent);
1221  *magick='\0';
1222#if defined(__OS2__)
1223  if (path[1] != ":")
1224#endif
1225  for (p=component; *p != '\0'; p++)
1226  {
1227    if ((*p == '%') && (*(p+1) == '['))
1228      {
1229        /*
1230          Skip over %[...].
1231        */
1232        for (p++; (*p != ']') && (*p != '\0'); p++) ;
1233        if (*p == '\0')
1234          break;
1235      }
1236    if ((*p == ':') && (IsPathDirectory(path) < 0) &&
1237        (IsPathAccessible(path) == MagickFalse))
1238      {
1239        /*
1240          Look for image format specification (e.g. ps3:image).
1241        */
1242        (void) CopyMagickString(magick,component,(size_t) (p-component+1));
1243        if (IsMagickConflict(magick) != MagickFalse)
1244          *magick='\0';
1245        else
1246          for (q=component; *q != '\0'; q++)
1247            *q=(*++p);
1248        break;
1249      }
1250  }
1251  *subimage='\0';
1252  p=component;
1253  if (*p != '\0')
1254    p=component+strlen(component)-1;
1255  if ((*p == ']') && (strchr(component,'[') != (char *) NULL) &&
1256      (IsPathAccessible(path) == MagickFalse))
1257    {
1258      /*
1259        Look for scene specification (e.g. img0001.pcd[4]).
1260      */
1261      for (q=p-1; q > component; q--)
1262        if (*q == '[')
1263          break;
1264      if (*q == '[')
1265        {
1266          (void) CopyMagickString(subimage,q+1,MaxTextExtent);
1267          subimage[p-q-1]='\0';
1268          if ((IsSceneGeometry(subimage,MagickFalse) == MagickFalse) &&
1269              (IsGeometry(subimage) == MagickFalse))
1270            *subimage='\0';
1271          else
1272            *q='\0';
1273        }
1274    }
1275  p=component;
1276  if (*p != '\0')
1277    for (p=component+strlen(component)-1; p > component; p--)
1278      if (IsBasenameSeparator(*p) != MagickFalse)
1279        break;
1280  switch (type)
1281  {
1282    case MagickPath:
1283    {
1284      (void) CopyMagickString(component,magick,MaxTextExtent);
1285      break;
1286    }
1287    case RootPath:
1288    {
1289      for (p=component+(strlen(component)-1); p > component; p--)
1290      {
1291        if (IsBasenameSeparator(*p) != MagickFalse)
1292          break;
1293        if (*p == '.')
1294          break;
1295      }
1296      if (*p == '.')
1297        *p='\0';
1298      break;
1299    }
1300    case HeadPath:
1301    {
1302      *p='\0';
1303      break;
1304    }
1305    case TailPath:
1306    {
1307      if (IsBasenameSeparator(*p) != MagickFalse)
1308        (void) CopyMagickMemory((unsigned char *) component,
1309          (const unsigned char *) (p+1),strlen(p+1)+1);
1310      break;
1311    }
1312    case BasePath:
1313    {
1314      if (IsBasenameSeparator(*p) != MagickFalse)
1315        (void) CopyMagickString(component,p+1,MaxTextExtent);
1316      for (p=component+(strlen(component)-1); p > component; p--)
1317        if (*p == '.')
1318          {
1319            *p='\0';
1320            break;
1321          }
1322      break;
1323    }
1324    case ExtensionPath:
1325    {
1326      if (IsBasenameSeparator(*p) != MagickFalse)
1327        (void) CopyMagickString(component,p+1,MaxTextExtent);
1328      p=component;
1329      if (*p != '\0')
1330        for (p=component+strlen(component)-1; p > component; p--)
1331          if (*p == '.')
1332            break;
1333      *component='\0';
1334      if (*p == '.')
1335        (void) CopyMagickString(component,p+1,MaxTextExtent);
1336      break;
1337    }
1338    case SubimagePath:
1339    {
1340      (void) CopyMagickString(component,subimage,MaxTextExtent);
1341      break;
1342    }
1343    case CanonicalPath:
1344    case UndefinedPath:
1345      break;
1346  }
1347}
1348
1349/*
1350%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1351%                                                                             %
1352%                                                                             %
1353%                                                                             %
1354%  G e t P a t h C o m p o n e n t s                                          %
1355%                                                                             %
1356%                                                                             %
1357%                                                                             %
1358%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1359%
1360%  GetPathComponents() returns a list of path components.
1361%
1362%  The format of the GetPathComponents method is:
1363%
1364%      char **GetPathComponents(const char *path,
1365%        size_t *number_componenets)
1366%
1367%  A description of each parameter follows:
1368%
1369%    o path:  Specifies the string to segment into a list.
1370%
1371%    o number_components:  return the number of components in the list
1372%
1373*/
1374MagickPrivate char **GetPathComponents(const char *path,
1375  size_t *number_components)
1376{
1377  char
1378    **components;
1379
1380  register const char
1381    *p,
1382    *q;
1383
1384  register ssize_t
1385    i;
1386
1387  if (path == (char *) NULL)
1388    return((char **) NULL);
1389  *number_components=1;
1390  for (p=path; *p != '\0'; p++)
1391    if (IsBasenameSeparator(*p))
1392      (*number_components)++;
1393  components=(char **) AcquireQuantumMemory((size_t) *number_components+1UL,
1394    sizeof(*components));
1395  if (components == (char **) NULL)
1396    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1397  p=path;
1398  for (i=0; i < (ssize_t) *number_components; i++)
1399  {
1400    for (q=p; *q != '\0'; q++)
1401      if (IsBasenameSeparator(*q))
1402        break;
1403    components[i]=(char *) AcquireQuantumMemory((size_t) (q-p)+MaxTextExtent,
1404      sizeof(**components));
1405    if (components[i] == (char *) NULL)
1406      ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1407    (void) CopyMagickString(components[i],p,(size_t) (q-p+1));
1408    p=q+1;
1409  }
1410  components[i]=(char *) NULL;
1411  return(components);
1412}
1413
1414/*
1415%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1416%                                                                             %
1417%                                                                             %
1418%                                                                             %
1419%  I s P a t h A c c e s s i b l e                                            %
1420%                                                                             %
1421%                                                                             %
1422%                                                                             %
1423%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1424%
1425%  IsPathAccessible() returns MagickTrue if the file as defined by the path is
1426%  accessible.
1427%
1428%  The format of the IsPathAccessible method is:
1429%
1430%      MagickBooleanType IsPathAccessible(const char *path)
1431%
1432%  A description of each parameter follows.
1433%
1434%    o path:  Specifies a path to a file.
1435%
1436*/
1437MagickExport MagickBooleanType IsPathAccessible(const char *path)
1438{
1439  MagickBooleanType
1440    status;
1441
1442  struct stat
1443    attributes;
1444
1445  if ((path == (const char *) NULL) || (*path == '\0'))
1446    return(MagickFalse);
1447  status=GetPathAttributes(path,&attributes);
1448  if (status == MagickFalse)
1449    return(status);
1450  if (S_ISREG(attributes.st_mode) == 0)
1451    return(MagickFalse);
1452  if (access_utf8(path,F_OK) != 0)
1453    return(MagickFalse);
1454  return(MagickTrue);
1455}
1456
1457/*
1458%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1459%                                                                             %
1460%                                                                             %
1461%                                                                             %
1462+  I s P a t h D i r e c t o r y                                              %
1463%                                                                             %
1464%                                                                             %
1465%                                                                             %
1466%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1467%
1468%  IsPathDirectory() returns -1 if the directory does not exist,  1 is returned
1469%  if the path represents a directory otherwise 0.
1470%
1471%  The format of the IsPathDirectory method is:
1472%
1473%      int IsPathDirectory(const char *path)
1474%
1475%  A description of each parameter follows.
1476%
1477%   o  path:  The directory path.
1478%
1479*/
1480static int IsPathDirectory(const char *path)
1481{
1482  MagickBooleanType
1483    status;
1484
1485  struct stat
1486    attributes;
1487
1488  if ((path == (const char *) NULL) || (*path == '\0'))
1489    return(MagickFalse);
1490  status=GetPathAttributes(path,&attributes);
1491  if (status == MagickFalse)
1492    return(-1);
1493  if (S_ISDIR(attributes.st_mode) == 0)
1494    return(0);
1495  return(1);
1496}
1497
1498/*
1499%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1500%                                                                             %
1501%                                                                             %
1502%                                                                             %
1503%   L i s t F i l e s                                                         %
1504%                                                                             %
1505%                                                                             %
1506%                                                                             %
1507%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1508%
1509%  ListFiles() reads the directory specified and returns a list of filenames
1510%  contained in the directory sorted in ascending alphabetic order.
1511%
1512%  The format of the ListFiles function is:
1513%
1514%      char **ListFiles(const char *directory,const char *pattern,
1515%        ssize_t *number_entries)
1516%
1517%  A description of each parameter follows:
1518%
1519%    o filelist: Method ListFiles returns a list of filenames contained
1520%      in the directory.  If the directory specified cannot be read or it is
1521%      a file a NULL list is returned.
1522%
1523%    o directory: Specifies a pointer to a text string containing a directory
1524%      name.
1525%
1526%    o pattern: Specifies a pointer to a text string containing a pattern.
1527%
1528%    o number_entries:  This integer returns the number of filenames in the
1529%      list.
1530%
1531*/
1532
1533#if defined(__cplusplus) || defined(c_plusplus)
1534extern "C" {
1535#endif
1536
1537static int FileCompare(const void *x,const void *y)
1538{
1539  register const char
1540    **p,
1541    **q;
1542
1543  p=(const char **) x;
1544  q=(const char **) y;
1545  return(LocaleCompare(*p,*q));
1546}
1547
1548#if defined(__cplusplus) || defined(c_plusplus)
1549}
1550#endif
1551
1552static inline int MagickReadDirectory(DIR *directory,struct dirent *entry,
1553  struct dirent **result)
1554{
1555#if defined(MAGICKCORE_HAVE_READDIR_R)
1556  return(readdir_r(directory,entry,result));
1557#else
1558  (void) entry;
1559  errno=0;
1560  *result=readdir(directory);
1561  return(errno);
1562#endif
1563}
1564
1565MagickPrivate char **ListFiles(const char *directory,const char *pattern,
1566  size_t *number_entries)
1567{
1568  char
1569    **filelist;
1570
1571  DIR
1572    *current_directory;
1573
1574  struct dirent
1575    *buffer,
1576    *entry;
1577
1578  size_t
1579    max_entries;
1580
1581  /*
1582    Open directory.
1583  */
1584  assert(directory != (const char *) NULL);
1585  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",directory);
1586  assert(pattern != (const char *) NULL);
1587  assert(number_entries != (size_t *) NULL);
1588  *number_entries=0;
1589  current_directory=opendir(directory);
1590  if (current_directory == (DIR *) NULL)
1591    return((char **) NULL);
1592  /*
1593    Allocate filelist.
1594  */
1595  max_entries=2048;
1596  filelist=(char **) AcquireQuantumMemory((size_t) max_entries,
1597    sizeof(*filelist));
1598  if (filelist == (char **) NULL)
1599    {
1600      (void) closedir(current_directory);
1601      return((char **) NULL);
1602    }
1603  /*
1604    Save the current and change to the new directory.
1605  */
1606  buffer=(struct dirent *) AcquireMagickMemory(sizeof(*buffer)+
1607    FILENAME_MAX+1);
1608  if (buffer == (struct dirent *) NULL)
1609    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1610  while ((MagickReadDirectory(current_directory,buffer,&entry) == 0) &&
1611         (entry != (struct dirent *) NULL))
1612  {
1613    if (*entry->d_name == '.')
1614      continue;
1615    if ((IsPathDirectory(entry->d_name) > 0) ||
1616#if defined(MAGICKCORE_WINDOWS_SUPPORT)
1617        (GlobExpression(entry->d_name,pattern,MagickTrue) != MagickFalse))
1618#else
1619        (GlobExpression(entry->d_name,pattern,MagickFalse) != MagickFalse))
1620#endif
1621      {
1622        if (*number_entries >= max_entries)
1623          {
1624            /*
1625              Extend the file list.
1626            */
1627            max_entries<<=1;
1628            filelist=(char **) ResizeQuantumMemory(filelist,(size_t)
1629              max_entries,sizeof(*filelist));
1630            if (filelist == (char **) NULL)
1631              break;
1632          }
1633#if defined(vms)
1634        {
1635          register char
1636            *p;
1637
1638          p=strchr(entry->d_name,';');
1639          if (p)
1640            *p='\0';
1641          if (*number_entries > 0)
1642            if (LocaleCompare(entry->d_name,filelist[*number_entries-1]) == 0)
1643              continue;
1644        }
1645#endif
1646        filelist[*number_entries]=(char *) AcquireString(entry->d_name);
1647        (*number_entries)++;
1648      }
1649  }
1650  buffer=(struct dirent *) RelinquishMagickMemory(buffer);
1651  (void) closedir(current_directory);
1652  if (filelist == (char **) NULL)
1653    return((char **) NULL);
1654  /*
1655    Sort filelist in ascending order.
1656  */
1657  qsort((void *) filelist,(size_t) *number_entries,sizeof(*filelist),
1658    FileCompare);
1659  return(filelist);
1660}
1661
1662/*
1663%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1664%                                                                             %
1665%                                                                             %
1666%                                                                             %
1667%   M a g i c k D e l a y                                                     %
1668%                                                                             %
1669%                                                                             %
1670%                                                                             %
1671%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1672%
1673%  MagickDelay() suspends program execution for the number of milliseconds
1674%  specified.
1675%
1676%  The format of the Delay method is:
1677%
1678%      void MagickDelay(const MagickSizeType milliseconds)
1679%
1680%  A description of each parameter follows:
1681%
1682%    o milliseconds: Specifies the number of milliseconds to delay before
1683%      returning.
1684%
1685*/
1686MagickPrivate void MagickDelay(const MagickSizeType milliseconds)
1687{
1688  if (milliseconds == 0)
1689    return;
1690#if defined(MAGICKCORE_HAVE_NANOSLEEP)
1691  {
1692    struct timespec
1693      timer;
1694
1695    timer.tv_sec=(time_t) (milliseconds/1000);
1696    timer.tv_nsec=(milliseconds % 1000)*1000*1000;
1697    (void) nanosleep(&timer,(struct timespec *) NULL);
1698  }
1699#elif defined(MAGICKCORE_HAVE_USLEEP)
1700  usleep(1000*milliseconds);
1701#elif defined(MAGICKCORE_HAVE_SELECT)
1702  {
1703    struct timeval
1704      timer;
1705
1706    timer.tv_sec=(long) milliseconds/1000;
1707    timer.tv_usec=(long) (milliseconds % 1000)*1000;
1708    (void) select(0,(XFD_SET *) NULL,(XFD_SET *) NULL,(XFD_SET *) NULL,&timer);
1709  }
1710#elif defined(MAGICKCORE_HAVE_POLL)
1711  (void) poll((struct pollfd *) NULL,0,(int) milliseconds);
1712#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
1713  Sleep((long) milliseconds);
1714#elif defined(vms)
1715  {
1716    float
1717      timer;
1718
1719    timer=milliseconds/1000.0;
1720    lib$wait(&timer);
1721  }
1722#elif defined(__BEOS__)
1723  snooze(1000*milliseconds);
1724#else
1725# error "Time delay method not defined."
1726#endif
1727}
1728
1729/*
1730%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1731%                                                                             %
1732%                                                                             %
1733%                                                                             %
1734%  M u l t i l i n e C e n s u s                                              %
1735%                                                                             %
1736%                                                                             %
1737%                                                                             %
1738%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1739%
1740%  MultilineCensus() returns the number of lines within a label.  A line is
1741%  represented by a \n character.
1742%
1743%  The format of the MultilineCenus method is:
1744%
1745%      size_t MultilineCensus(const char *label)
1746%
1747%  A description of each parameter follows.
1748%
1749%   o  label:  This character string is the label.
1750%
1751*/
1752MagickExport size_t MultilineCensus(const char *label)
1753{
1754  size_t
1755    number_lines;
1756
1757  /*
1758    Determine the number of lines within this label.
1759  */
1760  if (label == (char *) NULL)
1761    return(0);
1762  for (number_lines=1; *label != '\0'; label++)
1763    if (*label == '\n')
1764      number_lines++;
1765  return(number_lines);
1766}
1767
1768/*
1769%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1770%                                                                             %
1771%                                                                             %
1772%                                                                             %
1773%   S h r e a d F i l e                                                       %
1774%                                                                             %
1775%                                                                             %
1776%                                                                             %
1777%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1778%
1779%  ShredFile() overwrites the specified file with zeros or random data and then
1780%  removes it.  The overwrite is optional and is only required to help keep
1781%  the contents of the file private.  On the first pass, the file is zeroed.
1782%  For subsequent passes, random data is written.
1783%
1784%  The format of the ShredFile method is:
1785%
1786%      MagickBooleanType ShredFile(const char *path)
1787%
1788%  A description of each parameter follows.
1789%
1790%    o path:  Specifies a path to a file.
1791%
1792*/
1793MagickPrivate MagickBooleanType ShredFile(const char *path)
1794{
1795  char
1796    *passes;
1797
1798  int
1799    file,
1800    status;
1801
1802  MagickSizeType
1803    length;
1804
1805  register ssize_t
1806    i;
1807
1808  size_t
1809    quantum;
1810
1811  struct stat
1812    file_stats;
1813
1814  if ((path == (const char *) NULL) || (*path == '\0'))
1815    return(MagickFalse);
1816  passes=GetEnvironmentValue("MAGICK_SHRED_PASSES");
1817  if (passes == (char *) NULL)
1818    {
1819      /*
1820        Don't shred the file, just remove it.
1821      */
1822      status=remove_utf8(path);
1823      if (status == -1)
1824        return(MagickFalse);
1825      return(MagickTrue);
1826    }
1827  file=open_utf8(path,O_WRONLY | O_EXCL | O_BINARY,S_MODE);
1828  if (file == -1)
1829    {
1830      /*
1831        Don't shred the file, just remove it.
1832      */
1833      status=remove_utf8(path);
1834      return(MagickFalse);
1835    }
1836  /*
1837    Shred the file.
1838  */
1839  quantum=(size_t) MagickMaxBufferExtent;
1840  if ((fstat(file,&file_stats) == 0) && (file_stats.st_size != 0))
1841    quantum=(size_t) MagickMin((MagickSizeType) file_stats.st_size,
1842      MagickMaxBufferExtent);
1843  length=(MagickSizeType) file_stats.st_size;
1844  for (i=0; i < (ssize_t) StringToInteger(passes); i++)
1845  {
1846    RandomInfo
1847      *random_info;
1848
1849    register MagickOffsetType
1850      j;
1851
1852    ssize_t
1853      count;
1854
1855    if (lseek(file,0,SEEK_SET) < 0)
1856      break;
1857    random_info=AcquireRandomInfo();
1858    for (j=0; j < (MagickOffsetType) length; j+=count)
1859    {
1860      StringInfo
1861        *key;
1862
1863      key=GetRandomKey(random_info,quantum);
1864      if (i == 0)
1865        ResetStringInfo(key);  /* zero on first pass */
1866      count=write(file,GetStringInfoDatum(key),(size_t)
1867        MagickMin(quantum,length-j));
1868      key=DestroyStringInfo(key);
1869      if (count <= 0)
1870        {
1871          count=0;
1872          if (errno != EINTR)
1873            break;
1874        }
1875    }
1876    random_info=DestroyRandomInfo(random_info);
1877    if (j < (MagickOffsetType) length)
1878      break;
1879  }
1880  status=close(file);
1881  status=remove_utf8(path);
1882  if (status == -1)
1883    return(MagickFalse);
1884  return(i < (ssize_t) StringToInteger(passes) ? MagickFalse : MagickTrue);
1885}
1886
1887/*
1888%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1889%                                                                             %
1890%                                                                             %
1891%                                                                             %
1892%   S y s t e m C o m m a n d                                                 %
1893%                                                                             %
1894%                                                                             %
1895%                                                                             %
1896%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1897%
1898%  SystemCommand() executes the specified command and waits until it
1899%  terminates.  The returned value is the exit status of the command.
1900%
1901%  The format of the SystemCommand method is:
1902%
1903%      int SystemCommand(const MagickBooleanType asynchronous,
1904%        const MagickBooleanType verbose,const char *command,
1905%        ExceptionInfo *exception)
1906%
1907%  A description of each parameter follows:
1908%
1909%    o asynchronous: a value other than 0 executes the parent program
1910%      concurrently with the new child process.
1911%
1912%    o verbose: a value other than 0 prints the executed command before it is
1913%      invoked.
1914%
1915%    o command: this string is the command to execute.
1916%
1917%    o exception: return any errors here.
1918%
1919*/
1920
1921static char *SanitizeSystemCommand(const char *command)
1922{
1923  char
1924    *sanitize_command;
1925
1926  const char
1927    *q;
1928
1929  register char
1930    *p;
1931
1932  static char
1933    whitelist[] =
1934      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_- "
1935      ".@&;<>|/\\\'\":%";
1936
1937  sanitize_command=AcquireString(command);
1938  p=sanitize_command;
1939  q=sanitize_command+strlen(sanitize_command);
1940  for (p+=strspn(p,whitelist); p != q; p+=strspn(p,whitelist))
1941    *p='_';
1942  return(sanitize_command);
1943}
1944
1945MagickExport int SystemCommand(const MagickBooleanType asynchronous,
1946  const MagickBooleanType verbose,const char *command,ExceptionInfo *exception)
1947{
1948  char
1949    **arguments,
1950    *sanitize_command;
1951
1952  int
1953    number_arguments,
1954    status;
1955
1956  PolicyDomain
1957    domain;
1958
1959  PolicyRights
1960    rights;
1961
1962  register ssize_t
1963    i;
1964
1965  status=(-1);
1966  arguments=StringToArgv(command,&number_arguments);
1967  if (arguments == (char **) NULL)
1968    return(status);
1969  if (*arguments[1] == '\0')
1970    {
1971      for (i=0; i < (ssize_t) number_arguments; i++)
1972        arguments[i]=DestroyString(arguments[i]);
1973      arguments=(char **) RelinquishMagickMemory(arguments);
1974      return(-1);
1975    }
1976  rights=ExecutePolicyRights;
1977  domain=DelegatePolicyDomain;
1978  if (IsRightsAuthorized(domain,rights,arguments[1]) == MagickFalse)
1979    {
1980      errno=EPERM;
1981      (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
1982        "NotAuthorized","`%s'",arguments[1]);
1983      for (i=0; i < (ssize_t) number_arguments; i++)
1984        arguments[i]=DestroyString(arguments[i]);
1985      arguments=(char **) RelinquishMagickMemory(arguments);
1986      return(-1);
1987    }
1988  if (verbose != MagickFalse)
1989    {
1990      (void) FormatLocaleFile(stderr,"%s\n",command);
1991      (void) fflush(stderr);
1992    }
1993  sanitize_command=SanitizeSystemCommand(command);
1994  if (asynchronous != MagickFalse)
1995    (void) ConcatenateMagickString(sanitize_command,"&",MaxTextExtent);
1996#if defined(MAGICKCORE_POSIX_SUPPORT)
1997#if !defined(MAGICKCORE_HAVE_EXECVP)
1998  status=system(sanitize_command);
1999#else
2000  if ((asynchronous != MagickFalse) ||
2001      (strpbrk(sanitize_command,"&;<>|") != (char *) NULL))
2002    status=system(sanitize_command);
2003  else
2004    {
2005      pid_t
2006        child_pid;
2007
2008      /*
2009        Call application directly rather than from a shell.
2010      */
2011      child_pid=(pid_t) fork();
2012      if (child_pid == (pid_t) -1)
2013        status=system(sanitize_command);
2014      else
2015        if (child_pid == 0)
2016          {
2017            status=execvp(arguments[1],arguments+1);
2018            _exit(1);
2019          }
2020        else
2021          {
2022            int
2023              child_status;
2024
2025            pid_t
2026              pid;
2027
2028            child_status=0;
2029            pid=(pid_t) waitpid(child_pid,&child_status,0);
2030            if (pid == -1)
2031              status=(-1);
2032            else
2033              {
2034                if (WIFEXITED(child_status) != 0)
2035                  status=WEXITSTATUS(child_status);
2036                else
2037                  if (WIFSIGNALED(child_status))
2038                    status=(-1);
2039              }
2040          }
2041    }
2042#endif
2043#elif defined(MAGICKCORE_WINDOWS_SUPPORT)
2044  status=NTSystemCommand(sanitize_command);
2045#elif defined(macintosh)
2046  status=MACSystemCommand(sanitize_command);
2047#elif defined(vms)
2048  status=system(sanitize_command);
2049#else
2050#  error No suitable system() method.
2051#endif
2052  if (status < 0)
2053    (void) ThrowMagickException(exception,GetMagickModule(),DelegateError,
2054      "FailedToExecuteCommand","`%s' (%d)",command,status);
2055  sanitize_command=DestroyString(sanitize_command);
2056  for (i=0; i < (ssize_t) number_arguments; i++)
2057    arguments[i]=DestroyString(arguments[i]);
2058  arguments=(char **) RelinquishMagickMemory(arguments);
2059  return(status);
2060}
2061