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