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