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