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