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