/src/graphicsmagick/magick/magick.c
Line | Count | Source |
1 | | /* |
2 | | % Copyright (C) 2003-2026 GraphicsMagick Group |
3 | | % Copyright (C) 2002 ImageMagick Studio |
4 | | % Copyright 1991-1999 E. I. du Pont de Nemours and Company |
5 | | % |
6 | | % This program is covered by multiple licenses, which are described in |
7 | | % Copyright.txt. You should have received a copy of Copyright.txt with this |
8 | | % package; otherwise see http://www.graphicsmagick.org/www/Copyright.html. |
9 | | % |
10 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
11 | | % % |
12 | | % % |
13 | | % % |
14 | | % M M AAA GGGG IIIII CCCC K K % |
15 | | % MM MM A A G I C K K % |
16 | | % M M M AAAAA G GGG I C KKK % |
17 | | % M M A A G G I C K K % |
18 | | % M M A A GGGG IIIII CCCC K K % |
19 | | % % |
20 | | % % |
21 | | % Methods to Read or List GraphicsMagick Image formats % |
22 | | % % |
23 | | % % |
24 | | % Software Design % |
25 | | % Bob Friesenhahn % |
26 | | % John Cristy % |
27 | | % November 1998 % |
28 | | % % |
29 | | % % |
30 | | % % |
31 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
32 | | % |
33 | | % |
34 | | */ |
35 | | |
36 | | /* |
37 | | Include declarations. |
38 | | */ |
39 | | #include "magick/studio.h" |
40 | | #if defined(USE_GLIBC_MTRACE) && USE_GLIBC_MTRACE |
41 | | # include <mcheck.h> |
42 | | #endif /* if defined(USE_GLIBC_MTRACE) && USE_GLIBC_MTRACE */ |
43 | | #if defined(MSWINDOWS) || defined(__CYGWIN__) |
44 | | # include "magick/nt_feature.h" |
45 | | #endif |
46 | | #include "magick/blob.h" |
47 | | #include "magick/color_lookup.h" |
48 | | #include "magick/command.h" |
49 | | #include "magick/constitute.h" |
50 | | #include "magick/delegate.h" |
51 | | #include "magick/log.h" |
52 | | #include "magick/magic.h" |
53 | | #include "magick/magick.h" |
54 | | #include "magick/module.h" |
55 | | #include "magick/monitor.h" |
56 | | #include "magick/pixel_cache.h" |
57 | | #include "magick/random.h" |
58 | | #include "magick/registry.h" |
59 | | #include "magick/resource.h" |
60 | | #include "magick/render.h" |
61 | | #include "magick/semaphore.h" |
62 | | #include "magick/tempfile.h" |
63 | | #include "magick/utility.h" |
64 | | #include "magick/version.h" |
65 | | #if defined(HasX11) |
66 | | #include "magick/xwindow.h" |
67 | | #endif |
68 | | /* watch out here - this include code for simple spinlock semaphore */ |
69 | | #include "magick/spinlock.h" |
70 | | |
71 | | /* |
72 | | Global declarations. |
73 | | */ |
74 | | typedef enum { |
75 | | InitDefault, |
76 | | InitUninitialized, |
77 | | InitInitialized |
78 | | } MagickInitializationState; |
79 | | |
80 | | static void |
81 | | DestroyMagickInfoList(void); |
82 | | |
83 | | static SemaphoreInfo |
84 | | *magick_semaphore = (SemaphoreInfo *) NULL; |
85 | | |
86 | | static SemaphoreInfo |
87 | | *module_semaphore = (SemaphoreInfo *) NULL; |
88 | | |
89 | | static MagickInfo |
90 | | *magick_list = (MagickInfo *) NULL; |
91 | | |
92 | | static unsigned int initialize_magick_options = 0; |
93 | | |
94 | | static unsigned int panic_signal_handler_call_count = 0; |
95 | | static unsigned int quit_signal_handler_call_count = 0; |
96 | | |
97 | | static MagickInitializationState MagickInitialized = InitDefault; |
98 | | static CoderClass MinimumCoderClass = UnstableCoderClass; |
99 | | |
100 | | static void DestroyMagickInfo(MagickInfo** magick_info); |
101 | | static void DestroyMagickInfoList(void); |
102 | | |
103 | | static MagickPassFail InitializeMagickInfoList(void); |
104 | | |
105 | | /* |
106 | | Block size to use when accessing filesystem. |
107 | | |
108 | | Adjust via MAGICK_IOBUF_SIZE environment variable. |
109 | | */ |
110 | | |
111 | | static size_t filesystem_blocksize=16384; |
112 | | |
113 | | /* |
114 | | Get blocksize to use when accessing the filesystem. |
115 | | */ |
116 | | size_t |
117 | | MagickGetFileSystemBlockSize(void) |
118 | 15.9M | { |
119 | 15.9M | return filesystem_blocksize; |
120 | 15.9M | } |
121 | | |
122 | | /* |
123 | | Set blocksize to use when accessing the filesystem. |
124 | | */ |
125 | | void |
126 | | MagickSetFileSystemBlockSize(const size_t block_size) |
127 | 252 | { |
128 | 252 | assert(block_size > 0); |
129 | 252 | filesystem_blocksize=block_size; |
130 | 252 | } |
131 | | |
132 | | |
133 | | /* |
134 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
135 | | % % |
136 | | % % |
137 | | % % |
138 | | % D e s t r o y M a g i c k % |
139 | | % % |
140 | | % % |
141 | | % % |
142 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
143 | | % |
144 | | % DestroyMagick() destroys the GraphicsMagick environment, releasing all |
145 | | % allocated semaphores, memory, and temporary files. This function |
146 | | % should be invoked in the primary (original) thread of the application's |
147 | | % process while shutting down, and only after any threads which might be |
148 | | % using GraphicsMagick functions have terminated. Since GraphicsMagick |
149 | | % may use threads internally via OpenMP, it is also necessary for any |
150 | | % function calls into GraphicsMagick to have already returned so that |
151 | | % OpenMP worker threads are quiesced and won't be accessing any semaphores |
152 | | % or data structures which are destroyed by this function. |
153 | | % |
154 | | % The OpenMP implementation (if present) starts/stops any OpenMP worker |
155 | | % threads and allocates/frees OpenMP resources using its own algorithms. |
156 | | % This means that OpenMP worker threads and OpenMP resources are likely |
157 | | % to remain allocated after DestroyMagick() returns. Since OpenMP 5.0, |
158 | | % invoking omp_pause_resource_all(omp_pause_hard) will assure that any |
159 | | % resources allocated by OpenMP (threads, thread-specific memory, etc.) |
160 | | % are freed, and this may be called after DestroyMagick() has returned. |
161 | | % |
162 | | % The format of the DestroyMagick function is: |
163 | | % |
164 | | % DestroyMagick(void) |
165 | | % |
166 | | % |
167 | | */ |
168 | | MagickExport void |
169 | | DestroyMagick(void) |
170 | 0 | { |
171 | | /* Acquire destruction lock */ |
172 | 0 | SPINLOCK_WAIT; |
173 | |
|
174 | 0 | if (MagickInitialized == InitUninitialized) |
175 | 0 | { |
176 | | /* Release destruction lock */ |
177 | 0 | SPINLOCK_RELEASE; |
178 | 0 | return; |
179 | 0 | } |
180 | | |
181 | 0 | (void) LogMagickEvent(ConfigureEvent,GetMagickModule(), |
182 | 0 | "Destroy Magick"); |
183 | |
|
184 | 0 | MagickDestroyCommandInfo(); /* Command parser */ |
185 | 0 | DestroyMagickMonitor(); /* Progress monitor */ |
186 | | #if defined(HasX11) |
187 | | MagickXDestroyX11Resources(); |
188 | | #endif |
189 | 0 | DestroyColorInfo(); /* Color database */ |
190 | 0 | DestroyDelegateInfo(); /* External delegate information */ |
191 | 0 | DestroyTypeInfo(); /* Font information */ |
192 | | /*DestroyMagicInfo();*/ /* File format detection */ |
193 | 0 | DestroyMagickInfoList(); /* Coder registrations + modules */ |
194 | 0 | DestroyConstitute(); /* Constitute semaphore */ |
195 | 0 | DestroyMagickRegistry(); /* Registered images */ |
196 | 0 | DestroyMagickResources(); /* Resource semaphore */ |
197 | 0 | DestroyMagickRandomGenerator(); /* Random number generator */ |
198 | 0 | DestroyTemporaryFiles(); /* Temporary files */ |
199 | | #if defined(MSWINDOWS) |
200 | | #if defined(HasGS) |
201 | | NTGhostscriptUnLoadDLL(); /* Ghostscript DLL */ |
202 | | #endif /* if defined(HasGS) */ |
203 | | #endif /* defined(MSWINDOWS) */ |
204 | | /* |
205 | | Destroy logging last since some components log their destruction. |
206 | | */ |
207 | 0 | DestroyLogInfo(); /* Logging configuration */ |
208 | 0 | DestroyMagickExceptionHandling(); /* Exception handling */ |
209 | 0 | DestroySemaphore(); /* Semaphores framework */ |
210 | | |
211 | | /* Now uninitialized */ |
212 | 0 | MagickInitialized=InitUninitialized; |
213 | | |
214 | | /* Release destruction lock */ |
215 | 0 | SPINLOCK_RELEASE; |
216 | 0 | } |
217 | | /* |
218 | | Destroy MagickInfo structure. |
219 | | */ |
220 | | |
221 | | /* |
222 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
223 | | % % |
224 | | % % |
225 | | % % |
226 | | % D e s t r o y M a g i c k I n f o % |
227 | | % % |
228 | | % % |
229 | | % % |
230 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
231 | | % |
232 | | % DestroyMagickInfo() destroys a MagickInfo structure. |
233 | | % |
234 | | % The format of the DestroyMagickInfoList method is: |
235 | | % |
236 | | % void DestroyMagickInfo(MagickInfo** magick_info) |
237 | | % |
238 | | */ |
239 | | static void |
240 | | DestroyMagickInfo(MagickInfo** magick_info) |
241 | 0 | { |
242 | 0 | MagickInfo |
243 | 0 | *p; |
244 | |
|
245 | 0 | p=*magick_info; |
246 | 0 | if (p) |
247 | 0 | { |
248 | 0 | p->name=0; |
249 | 0 | p->description=0; |
250 | 0 | p->version=0; |
251 | 0 | p->note=0; |
252 | 0 | p->module=0; |
253 | 0 | MagickFreeMemory(p); |
254 | 0 | *magick_info=p; |
255 | 0 | } |
256 | 0 | } |
257 | | |
258 | | /* |
259 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
260 | | % % |
261 | | % % |
262 | | % % |
263 | | % D e s t r o y M a g i c k I n f o L i s t % |
264 | | % % |
265 | | % % |
266 | | % % |
267 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
268 | | % |
269 | | % DestroyMagickInfo() deallocates memory associated with the MagickInfo list. |
270 | | % |
271 | | % The format of the DestroyMagickInfoList method is: |
272 | | % |
273 | | % void DestroyMagickInfoList(void) |
274 | | % |
275 | | */ |
276 | | static void |
277 | | DestroyMagickInfoList(void) |
278 | 0 | { |
279 | 0 | MagickInfo |
280 | 0 | *magick_info; |
281 | |
|
282 | 0 | register MagickInfo |
283 | 0 | *p; |
284 | |
|
285 | 0 | DestroyMagickModules(); |
286 | | |
287 | | /* |
288 | | At this point, the list should be empty, but check for remaining |
289 | | entries anyway. |
290 | | */ |
291 | 0 | if (magick_list != (MagickInfo *) NULL) |
292 | 0 | (void) printf("Warning: module registrations are still present!\n"); |
293 | 0 | for (p=magick_list; p != (MagickInfo *) NULL; ) |
294 | 0 | { |
295 | 0 | magick_info=p; |
296 | 0 | p=p->next; |
297 | |
|
298 | 0 | #if !defined(BuildMagickModules) |
299 | 0 | (void) printf("Warning: module registration for \"%s\" from module \"%s\" still present!\n", |
300 | 0 | magick_info->name, magick_info->module); |
301 | 0 | #endif /* !defined(BuildMagickModules) */ |
302 | 0 | DestroyMagickInfo(&magick_info); |
303 | 0 | } |
304 | 0 | magick_list=(MagickInfo *) NULL; |
305 | 0 | DestroySemaphoreInfo(&magick_semaphore); |
306 | |
|
307 | 0 | DestroySemaphoreInfo(&module_semaphore); |
308 | 0 | } |
309 | | |
310 | | /* |
311 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
312 | | % % |
313 | | % % |
314 | | % % |
315 | | % G e t I m a g e M a g i c k % |
316 | | % % |
317 | | % % |
318 | | % % |
319 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
320 | | % |
321 | | % GetImageMagick() searches for an image format that matches the specified |
322 | | % magick string. If one is found the name is returned otherwise NULL. |
323 | | % |
324 | | % The format of the GetImageMagick method is: |
325 | | % |
326 | | % const char *GetImageMagick(const unsigned char *magick, |
327 | | % const size_t length) |
328 | | % |
329 | | % A description of each parameter follows: |
330 | | % |
331 | | % o magick: The image format we are searching for. |
332 | | % |
333 | | % o length: The length of the binary string. |
334 | | % |
335 | | % |
336 | | */ |
337 | | MagickExport const char * |
338 | | GetImageMagick(const unsigned char *magick,const size_t length) |
339 | 0 | { |
340 | 0 | register MagickInfo |
341 | 0 | *p; |
342 | |
|
343 | 0 | assert(magick != (const unsigned char *) NULL); |
344 | 0 | LockSemaphoreInfo(magick_semaphore); |
345 | 0 | for (p=magick_list; p != (MagickInfo *) NULL; p=p->next) |
346 | 0 | if (p->magick && p->magick(magick,length)) |
347 | 0 | break; |
348 | 0 | UnlockSemaphoreInfo(magick_semaphore); |
349 | 0 | if (p != (MagickInfo *) NULL) |
350 | 0 | return(p->name); |
351 | 0 | return((char *) NULL); |
352 | 0 | } |
353 | | |
354 | | /* |
355 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
356 | | % % |
357 | | % % |
358 | | % % |
359 | | % G e t M a g i c k I n f o % |
360 | | % % |
361 | | % % |
362 | | % % |
363 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
364 | | % |
365 | | % GetMagickInfo() returns a pointer MagickInfo structure that matches |
366 | | % the specified name. If name is NULL, the head of the image format list |
367 | | % is returned. It is not safe to traverse the list by using the previous and |
368 | | % next pointers in the MagickInfo structure since the list contents or order |
369 | | % may be altered while the list is being traversed. If the list must be |
370 | | % traversed, access it via the GetMagickInfoArray function instead. |
371 | | % |
372 | | % If GraphicsMagick has not been initialized via InitializeMagick() |
373 | | % then this function will not work. |
374 | | % |
375 | | % The format of the GetMagickInfo method is: |
376 | | % |
377 | | % const MagickInfo *GetMagickInfo(const char *name,ExceptionInfo *exception) |
378 | | % |
379 | | % A description of each parameter follows: |
380 | | % |
381 | | % o name: The image format we are looking for. |
382 | | % |
383 | | % o exception: Return any errors or warnings in this structure. |
384 | | % |
385 | | % |
386 | | */ |
387 | | static MagickInfo * |
388 | | GetMagickInfoEntryLocked(const char *name) |
389 | 18.2M | { |
390 | 18.2M | register MagickInfo |
391 | 18.2M | *p; |
392 | | |
393 | 18.2M | LockSemaphoreInfo(magick_semaphore); |
394 | | |
395 | 18.2M | p=magick_list; |
396 | | |
397 | 18.2M | if ((name != (const char *) NULL) && (name[0] != '*')) |
398 | 18.2M | { |
399 | 33.0M | for (p=magick_list; p != (MagickInfo *) NULL; p=p->next) |
400 | 33.0M | if (LocaleCompare(p->name,name) == 0) |
401 | 18.2M | break; |
402 | | |
403 | 18.2M | if (p != (MagickInfo *) NULL) |
404 | 18.2M | if (p != magick_list) |
405 | 2.94M | { |
406 | | /* |
407 | | Self-adjusting list. |
408 | | */ |
409 | 2.94M | if (p->previous != (MagickInfo *) NULL) |
410 | 2.94M | p->previous->next=p->next; |
411 | 2.94M | if (p->next != (MagickInfo *) NULL) |
412 | 2.94M | p->next->previous=p->previous; |
413 | 2.94M | p->previous=(MagickInfo *) NULL; |
414 | 2.94M | p->next=magick_list; |
415 | 2.94M | magick_list->previous=p; |
416 | 2.94M | magick_list=p; |
417 | 2.94M | } |
418 | 18.2M | } |
419 | | |
420 | 18.2M | UnlockSemaphoreInfo(magick_semaphore); |
421 | | |
422 | 18.2M | return p; |
423 | 18.2M | } |
424 | | MagickExport const MagickInfo * |
425 | | GetMagickInfo(const char *name,ExceptionInfo *exception) |
426 | 18.2M | { |
427 | 18.2M | const MagickInfo |
428 | 18.2M | *magick_info=(const MagickInfo *) NULL; |
429 | | |
430 | 18.2M | if ((name != (const char *) NULL) && |
431 | 18.2M | (name[0] != '\0')) |
432 | 18.2M | { |
433 | 18.2M | LockSemaphoreInfo(module_semaphore); |
434 | 18.2M | if (name[0] == '*') |
435 | 0 | { |
436 | | /* |
437 | | If all modules are requested, then use OpenModules to load all |
438 | | modules. |
439 | | */ |
440 | 0 | (void) OpenModules(exception); |
441 | 0 | } |
442 | 18.2M | else |
443 | 18.2M | { |
444 | 18.2M | magick_info=GetMagickInfoEntryLocked(name); |
445 | 18.2M | if (magick_info == (const MagickInfo *) NULL) |
446 | 27.2k | { |
447 | | /* |
448 | | Try to load a supporting module. |
449 | | */ |
450 | 27.2k | (void) OpenModule(name,exception); |
451 | 27.2k | } |
452 | 18.2M | } |
453 | 18.2M | UnlockSemaphoreInfo(module_semaphore); |
454 | 18.2M | } |
455 | | |
456 | | /* |
457 | | Return whatever we've got |
458 | | */ |
459 | 18.2M | if (magick_info == (const MagickInfo *) NULL) |
460 | 27.2k | magick_info=GetMagickInfoEntryLocked(name); |
461 | | |
462 | 18.2M | return magick_info; |
463 | 18.2M | } |
464 | | /* |
465 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
466 | | % % |
467 | | % % |
468 | | % % |
469 | | % G e t M a g i c k I n f o A r r a y % |
470 | | % % |
471 | | % % |
472 | | % % |
473 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
474 | | % |
475 | | % GetMagickInfoArray() returns a sorted null-terminated array of MagickInfo |
476 | | % pointers corresponding to the available format registrations. If necessarly |
477 | | % all modules are loaded in order to return a complete list. This function |
478 | | % should be used to access the entire list rather than GetMagickInfo since |
479 | | % the list returned by GetMagickInfo may be re-ordered every time it is |
480 | | % invoked. Once the returned array is no longer needed, the allocated array |
481 | | % should be deallocated. Do not attempt to deallocate the MagickInfo |
482 | | % structures based on pointers in the array! |
483 | | % |
484 | | % The format of the GetMagickList method is: |
485 | | % |
486 | | % MagickInfo **GetMagickInfoArray(ExceptionInfo *exception) |
487 | | % |
488 | | % A description of each parameter follows: |
489 | | % |
490 | | % o exception: Return any errors or warnings in this structure. |
491 | | % |
492 | | % |
493 | | */ |
494 | | /* |
495 | | Compare two MagickInfo structures based on their name |
496 | | */ |
497 | | static int |
498 | | MagickInfoCompare(const void *x, const void *y) |
499 | 0 | { |
500 | 0 | const MagickInfo |
501 | 0 | *xx=*((const MagickInfo **) x), |
502 | 0 | *yy=*((const MagickInfo **) y); |
503 | |
|
504 | 0 | return (strcmp(xx->name, yy->name)); |
505 | 0 | } |
506 | | MagickExport MagickInfo ** |
507 | | GetMagickInfoArray(ExceptionInfo *exception) |
508 | 0 | { |
509 | 0 | MagickInfo |
510 | 0 | **array; |
511 | |
|
512 | 0 | MagickInfo |
513 | 0 | *p; |
514 | |
|
515 | 0 | MagickInfo |
516 | 0 | *list; |
517 | |
|
518 | 0 | size_t |
519 | 0 | entries=0; |
520 | |
|
521 | 0 | int |
522 | 0 | i; |
523 | | |
524 | | /* |
525 | | Load all modules and obtain pointer to head of list |
526 | | */ |
527 | 0 | (void) GetMagickInfo("*",exception); |
528 | |
|
529 | 0 | LockSemaphoreInfo(magick_semaphore); |
530 | 0 | if (!magick_list) |
531 | 0 | { |
532 | 0 | UnlockSemaphoreInfo(magick_semaphore); |
533 | 0 | return ((MagickInfo **) NULL); |
534 | 0 | } |
535 | | |
536 | 0 | list=magick_list; |
537 | | |
538 | | /* |
539 | | Count number of list entries |
540 | | */ |
541 | 0 | for (p=list; p != 0; p=p->next) |
542 | 0 | entries++; |
543 | | |
544 | | /* |
545 | | Allocate array memory |
546 | | */ |
547 | 0 | array=MagickAllocateArray(MagickInfo **,(entries+1),sizeof(MagickInfo *)); |
548 | 0 | if (!array) |
549 | 0 | { |
550 | 0 | UnlockSemaphoreInfo(magick_semaphore); |
551 | 0 | ThrowException(exception,ResourceLimitError,MemoryAllocationFailed,0); |
552 | 0 | return ((MagickInfo **) NULL); |
553 | 0 | } |
554 | | |
555 | | /* |
556 | | Add entries to array |
557 | | */ |
558 | 0 | i=0; |
559 | 0 | for (p=list; p != 0; p=p->next) |
560 | 0 | array[i++]=p; |
561 | 0 | array[i]=(MagickInfo *) NULL; |
562 | |
|
563 | 0 | UnlockSemaphoreInfo(magick_semaphore); |
564 | | |
565 | | /* |
566 | | Sort array entries |
567 | | */ |
568 | 0 | qsort((void *) array, entries, sizeof(MagickInfo *), MagickInfoCompare); |
569 | |
|
570 | 0 | return (array); |
571 | 0 | } |
572 | | |
573 | | /* |
574 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
575 | | % % |
576 | | % % |
577 | | % % |
578 | | % I n i t i a l i z e M a g i c k % |
579 | | % % |
580 | | % % |
581 | | % % |
582 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
583 | | % |
584 | | % InitializeMagick() initializes the GraphicsMagick environment. |
585 | | % |
586 | | % InitializeMagick() or InitializeMagickEx() MUST be invoked by the using |
587 | | % program before making use of GraphicsMagick functions or else the library |
588 | | % will be unusable and any usage is likely to cause a crash. |
589 | | % |
590 | | % This function should be invoked in the primary (original) thread of the |
591 | | % application's process, and before starting any OpenMP threads, as part |
592 | | % of program initialization. |
593 | | % |
594 | | % If alternate memory allocations are provided via MagickAllocFunctions() |
595 | | % then that function should be invoked before InitializeMagickEx() since |
596 | | % the memory allocation functions need to be consistent. |
597 | | % |
598 | | % The format of the InitializeMagick function is: |
599 | | % |
600 | | % InitializeMagick(const char *path) |
601 | | % |
602 | | % A description of each parameter follows: |
603 | | % |
604 | | % o path: The execution path of the current GraphicsMagick client (or NULL) |
605 | | % |
606 | | % |
607 | | */ |
608 | | |
609 | | /* |
610 | | Due to legacy compilers, POSIX.1 actually allows the signal function |
611 | | to return 'int' or 'void'. The compiler is not so lenient so we must |
612 | | ensure that the return type matches the prototype in the headers. |
613 | | */ |
614 | | #if !defined(RETSIGTYPE) |
615 | | # define RETSIGTYPE void |
616 | | #endif |
617 | | typedef RETSIGTYPE Sigfunc(int); |
618 | | |
619 | | #if !defined(SIG_ERR) |
620 | | # define SIG_ERR (Sigfunc *)-1 |
621 | | #endif |
622 | | #if !defined(SIG_DFL) |
623 | | # define SIG_DFL (Sigfunc *)0 |
624 | | #endif |
625 | | |
626 | | static RETSIGTYPE MagickPanicSignalHandler(int signo); |
627 | | static RETSIGTYPE MagickSignalHandler(int signo); |
628 | | |
629 | | /* |
630 | | Signal function which only sets the signal handler if it its handling |
631 | | is still set to SIG_DFL. This ensures that signal handlers are not |
632 | | registered for signals which are being ignored, or that the API |
633 | | user has already registered before invoking InitializeMagick. |
634 | | |
635 | | Due to a weakness in the POSIX APIs, the only way to see the handler |
636 | | which was registered before is by registering a new handler. |
637 | | |
638 | | If an API user registers its own signal handler, then it is responsible |
639 | | for invoking DestroyMagick when a signal is received. |
640 | | */ |
641 | | static void |
642 | | MagickCondSignal(int signo, Sigfunc *func) |
643 | 2.52k | { |
644 | 2.52k | #if defined(HAVE_SIGACTION) && defined(HAVE_SIGEMPTYSET) |
645 | 2.52k | struct sigaction |
646 | 2.52k | act, |
647 | 2.52k | oact; |
648 | | |
649 | | /* |
650 | | Signal set-up code which prevents interrupted system calls from |
651 | | automatically being restarted. From W. Richard Stevens "Advanced |
652 | | Programming in the UNIX Environment", Chapter 10.14. |
653 | | */ |
654 | 2.52k | act.sa_handler=func; |
655 | 2.52k | (void) sigemptyset(&act.sa_mask); |
656 | 2.52k | act.sa_flags=0; |
657 | 2.52k | # if defined(SA_INTERRUPT) /* SunOS */ |
658 | 2.52k | act.sa_flags |= SA_INTERRUPT; |
659 | 2.52k | # endif /* if defined(SA_INTERRUPT) */ |
660 | 2.52k | # if defined(SA_ONSTACK) /* Use alternate signal stack if available */ |
661 | 2.52k | act.sa_flags |= SA_ONSTACK; |
662 | 2.52k | # endif /* if defined(SA_ONSTACK) */ |
663 | | |
664 | 2.52k | (void) memset(&oact, 0, sizeof(oact)); |
665 | 2.52k | if (sigaction(signo, &act, &oact) == 0) |
666 | 2.52k | { |
667 | 2.52k | if ((oact.sa_flags & SA_SIGINFO) || |
668 | 1.76k | (oact.sa_handler != SIG_DFL)) |
669 | 756 | { |
670 | | /* Restore prior handler! */ |
671 | 756 | if (sigaction(signo, &oact, &act) != 0) |
672 | 0 | (void) LogMagickEvent(ConfigureEvent,GetMagickModule(), |
673 | 0 | "Failed to restore prior signal handler for signal ID %d!",signo); |
674 | 756 | else |
675 | 756 | (void) LogMagickEvent(ConfigureEvent,GetMagickModule(), |
676 | 756 | "Restored prior signal handler for signal ID %d!",signo); |
677 | 756 | } |
678 | 1.76k | else |
679 | 1.76k | { |
680 | 1.76k | (void) LogMagickEvent(ConfigureEvent,GetMagickModule(), |
681 | 1.76k | "Registered signal handler for signal ID %d",signo); |
682 | 1.76k | } |
683 | 2.52k | } |
684 | 0 | else |
685 | 0 | { |
686 | 0 | (void) LogMagickEvent(ConfigureEvent,GetMagickModule(), |
687 | 0 | "Failed to register signal handler for signal ID %d!",signo); |
688 | 0 | } |
689 | | |
690 | | #else |
691 | | Sigfunc * |
692 | | o_handler; |
693 | | |
694 | | if ((o_handler=signal(signo, func)) != SIG_ERR) |
695 | | { |
696 | | if (o_handler != SIG_DFL) |
697 | | { |
698 | | /* Restore prior handler! */ |
699 | | if (signal(signo, o_handler) == SIG_ERR) |
700 | | (void) LogMagickEvent(ConfigureEvent,GetMagickModule(), |
701 | | "Failed to restore prior signal handler for signal ID %d!",signo); |
702 | | else |
703 | | (void) LogMagickEvent(ConfigureEvent,GetMagickModule(), |
704 | | "Restored prior signal handler for signal ID %d!",signo); |
705 | | } |
706 | | else |
707 | | { |
708 | | (void) LogMagickEvent(ConfigureEvent,GetMagickModule(), |
709 | | "Registered signal handler for signal ID %d",signo); |
710 | | } |
711 | | } |
712 | | else |
713 | | { |
714 | | (void) LogMagickEvent(ConfigureEvent,GetMagickModule(), |
715 | | "Failed to register signal handler for signal ID %d!",signo); |
716 | | } |
717 | | #endif |
718 | 2.52k | } |
719 | | |
720 | | /* |
721 | | Signal handler which does nothing. |
722 | | */ |
723 | | #if 0 |
724 | | static RETSIGTYPE |
725 | | MagickIgnoreSignalHandler(int signo) |
726 | | { |
727 | | fprintf(stderr,"Caught ignored signal %d\n", signo); |
728 | | } |
729 | | #endif |
730 | | |
731 | | /* |
732 | | Write a message about the signal to stderr. |
733 | | */ |
734 | | static void |
735 | | MagickSignalHandlerMessage(const int signo, const char *subtext) |
736 | 0 | { |
737 | | /* |
738 | | Signals we might handle, to map to their common description. |
739 | | |
740 | | May use strsignal() on POSIX.1-2008-compliant systems, but it is |
741 | | not documented to be async-safe. |
742 | | |
743 | | */ |
744 | 0 | static const struct { |
745 | 0 | const int signo; |
746 | 0 | const char name[8]; |
747 | 0 | const char *descr; |
748 | 0 | } signal_descr[] = { |
749 | 0 | #if defined(SIGHUP) |
750 | 0 | { SIGHUP, "SIGHUP","Hangup" }, |
751 | 0 | #endif |
752 | 0 | #if defined(SIGINT) |
753 | 0 | { SIGINT, "SIGINT", "Interrupt" }, |
754 | 0 | #endif |
755 | 0 | #if defined(SIGQUIT) |
756 | 0 | { SIGQUIT, "SIGQUIT", "Quit" }, |
757 | 0 | #endif |
758 | 0 | #if defined(SIGILL) |
759 | 0 | { SIGILL, "SIGILL", "Illegal Instruction" }, |
760 | 0 | #endif |
761 | 0 | #if defined(SIGABRT) |
762 | 0 | { SIGABRT, "SIGABRT", "Abort" }, |
763 | 0 | #endif |
764 | 0 | #if defined(SIGFPE) |
765 | 0 | { SIGFPE, "SIGFPE", "Arithmetic Exception" }, |
766 | 0 | #endif |
767 | 0 | #if defined(SIGBUS) |
768 | 0 | { SIGBUS, "SIGBUS", "Bus Error" }, |
769 | 0 | #endif |
770 | 0 | #if defined(SIGSEGV) |
771 | 0 | { SIGSEGV, "SIGSEGV", "Segmentation Fault" }, |
772 | 0 | #endif |
773 | 0 | #if defined(SIGPIPE) |
774 | 0 | { SIGPIPE, "SIGPIPE", "Broken Pipe" }, |
775 | 0 | #endif |
776 | 0 | #if defined(SIGALRM) |
777 | 0 | { SIGALRM, "SIGALRM", "Alarm Clock" }, |
778 | 0 | #endif |
779 | 0 | #if defined(SIGTERM) |
780 | 0 | { SIGTERM, "SIGTERM", "Terminated" }, |
781 | 0 | #endif |
782 | 0 | #if defined(SIGCHLD) |
783 | 0 | { SIGCHLD, "SIGCHLD", "Child Status Changed" }, |
784 | 0 | #endif |
785 | 0 | #if defined(SIGXCPU) |
786 | 0 | { SIGXCPU, "SIGXCPU", "CPU time limit exceeded" }, |
787 | 0 | #endif |
788 | 0 | #if defined(SIGXFSZ) |
789 | 0 | { SIGXFSZ, "SIGXFSZ", "File size limit exceeded" } |
790 | 0 | #endif |
791 | 0 | }; |
792 | |
|
793 | 0 | static char |
794 | 0 | message[128]; |
795 | |
|
796 | 0 | size_t |
797 | 0 | i; |
798 | |
|
799 | 0 | int |
800 | 0 | num=signo; |
801 | | |
802 | | /* |
803 | | Output messages like: |
804 | | |
805 | | gm convert: quitting due to signal 2 (SIGINT) "Interrupt"... |
806 | | gm convert: abort due to signal 11 (SIGSEGV) "Segmentation Fault"... |
807 | | */ |
808 | 0 | (void) strlcpy(message, GetClientName(), sizeof(message)); |
809 | 0 | (void) strlcat(message,": ", sizeof(message)); |
810 | 0 | (void) strlcat(message,subtext,sizeof(message)); |
811 | 0 | (void) strlcat(message," due to signal ",sizeof(message)); |
812 | 0 | i=strlen(message); |
813 | 0 | for ( ; (num != 0) && (i < sizeof(message)-1) ; i++) |
814 | 0 | { |
815 | 0 | int rem = num % 10; |
816 | 0 | message[i] = rem + '0'; |
817 | 0 | num = num/10; |
818 | 0 | } |
819 | 0 | message[i] = '\0'; |
820 | 0 | for ( i=0; i < (sizeof(signal_descr)/sizeof(signal_descr[0])); i++) |
821 | 0 | { |
822 | 0 | if (signo == signal_descr[i].signo) |
823 | 0 | { |
824 | 0 | (void) strlcat(message," (",sizeof(message)); |
825 | 0 | (void) strlcat(message,signal_descr[i].name,sizeof(message)); |
826 | 0 | (void) strlcat(message,") \"",sizeof(message)); |
827 | 0 | (void) strlcat(message,signal_descr[i].descr,sizeof(message)); |
828 | 0 | (void) strlcat(message,"\"",sizeof(message)); |
829 | 0 | } |
830 | 0 | } |
831 | 0 | (void) strlcat(message,"...\n",sizeof(message)); |
832 | |
|
833 | 0 | if (write(STDERR_FILENO,message, |
834 | 0 | (MAGICK_POSIX_IO_SIZE_T) strlen(message)) == -1) |
835 | 0 | { |
836 | | /* Exists to quench warning */ |
837 | 0 | } |
838 | 0 | } |
839 | | |
840 | | |
841 | | /* |
842 | | Signal handler to ensure that DestroyMagick is invoked in case the |
843 | | user aborts the program. |
844 | | |
845 | | The WIN32 documentation says that SIGINT is not supported under any |
846 | | version of Windows. It also says that a new thread is created to |
847 | | handle the interrupt caused by CNTRL+C. The Windows signal |
848 | | documentation also says that it is unsafe to do anything useful from |
849 | | within a signal handler. This means that malloc/free and any system |
850 | | call should not be executed. Theoretically DestroyMagick() should |
851 | | not be executed since its purpose is to invoke unsafe functions. |
852 | | SIGILL, SIGSEGV, and SIGTERM are documented to never be generated by |
853 | | Windows NT. |
854 | | |
855 | | While support for signal is definitely broken under Windows, the good |
856 | | news is that it seems to be unlikely to generate a signal we care about. |
857 | | */ |
858 | | |
859 | | static RETSIGTYPE |
860 | | MagickPanicSignalHandler(int signo) |
861 | 0 | { |
862 | 0 | ARG_NOT_USED(signo); |
863 | |
|
864 | 0 | panic_signal_handler_call_count++; |
865 | | |
866 | | /* |
867 | | Only handle signal one time. |
868 | | */ |
869 | 0 | if (1 == panic_signal_handler_call_count) |
870 | 0 | { |
871 | | /* |
872 | | Release persistent resources |
873 | | */ |
874 | 0 | PanicDestroyMagick(); |
875 | | |
876 | | /* |
877 | | Produce a useful message for the user |
878 | | */ |
879 | 0 | MagickSignalHandlerMessage(signo,"abort"); |
880 | | |
881 | | /* |
882 | | Call abort so that we quit with core dump. |
883 | | */ |
884 | 0 | abort(); |
885 | 0 | } |
886 | 0 | } |
887 | | |
888 | | static MagickBool QuitProgressMonitor(const char *task, |
889 | | const magick_int64_t quantum, |
890 | | const magick_uint64_t span, |
891 | | ExceptionInfo *exception) |
892 | 0 | { |
893 | 0 | ARG_NOT_USED(task); |
894 | 0 | ARG_NOT_USED(quantum); |
895 | 0 | ARG_NOT_USED(span); |
896 | | |
897 | | /* Report an error message */ |
898 | 0 | if (exception->severity < FatalErrorException) |
899 | 0 | ThrowException(exception,MonitorFatalError,UserRequestedTerminationBySignal,0); |
900 | |
|
901 | 0 | return MagickFail; |
902 | 0 | } |
903 | | |
904 | | static RETSIGTYPE |
905 | | MagickSignalHandler(int signo) |
906 | 0 | { |
907 | | /* fprintf(stderr,"Caught signal %d\n", signo); */ |
908 | |
|
909 | 0 | quit_signal_handler_call_count++; |
910 | | |
911 | | /* |
912 | | Only handle signal one time. |
913 | | */ |
914 | 0 | if (1 == quit_signal_handler_call_count) |
915 | 0 | { |
916 | 0 | if (MagickInitialized == InitInitialized) |
917 | 0 | { |
918 | | |
919 | | /* |
920 | | Set progress monitor handler to one which always returns |
921 | | MagickFail. |
922 | | */ |
923 | 0 | (void) SetMonitorHandler(QuitProgressMonitor); |
924 | | |
925 | | /* |
926 | | Release persistent resources |
927 | | */ |
928 | 0 | PanicDestroyMagick(); |
929 | | |
930 | | /* |
931 | | Produce a useful message for the user |
932 | | */ |
933 | 0 | if (signo != SIGINT) |
934 | 0 | MagickSignalHandlerMessage(signo,"quitting"); |
935 | 0 | } |
936 | | |
937 | | /* |
938 | | Invoke _exit(signo) (or equivalent) which avoids invoking |
939 | | registered atexit() functions. |
940 | | */ |
941 | 0 | SignalHandlerExit(signo); |
942 | 0 | } |
943 | 0 | } |
944 | | |
945 | | /* |
946 | | The goal of this routine is to determine whether the passed |
947 | | string is a valid and complete path to a file within the |
948 | | filesystem |
949 | | */ |
950 | | #if !defined(UseInstalledMagick) |
951 | | static unsigned int |
952 | | IsValidFilesystemPath(const char *path) |
953 | 252 | { |
954 | 252 | if ((path != (const char *) NULL) && (*path != '\0')) |
955 | 252 | { |
956 | 252 | #if defined(POSIX) |
957 | | /* For POSIX we check the first character to see of it is a file |
958 | | system path separator. If not then we ignore the passed data |
959 | | */ |
960 | 252 | if ((*path == *DirectorySeparator)) |
961 | 252 | return IsAccessibleNoLogging(path); |
962 | | #elif defined(MSWINDOWS) |
963 | | /* For Windows we check to see if the path passed seems to be a |
964 | | pathof any kind (contains delimiters) or seem to be either UNC |
965 | | path or one with a drive letter spec in it: \\Server\share, C:\ |
966 | | */ |
967 | | if (((*path == *DirectorySeparator) && (*(path+1) == *DirectorySeparator)) || |
968 | | (*(path+1) == ':') || |
969 | | (strchr(path,*DirectorySeparator) != (char *) NULL)) |
970 | | return IsAccessibleNoLogging(path); |
971 | | #else |
972 | | /* In any other case, we just look to see if it has path delimiters */ |
973 | | if ((strchr(path,*DirectorySeparator) != (char *) NULL)) |
974 | | return IsAccessibleNoLogging(path); |
975 | | #endif |
976 | 252 | } |
977 | 0 | return False; |
978 | 252 | } |
979 | | #endif /* !defined(UseInstalledMagick) */ |
980 | | |
981 | | /* |
982 | | Try and figure out the path and name of the client |
983 | | */ |
984 | | static void |
985 | | InitializeMagickClientPathAndName(const char *path) |
986 | 252 | { |
987 | 252 | #if !defined(UseInstalledMagick) |
988 | 252 | const char |
989 | 252 | *spath; |
990 | | |
991 | 252 | char |
992 | 252 | execution_path[MaxTextExtent]; |
993 | | |
994 | | /* the following is to make the logging more readable later on */ |
995 | 252 | spath = path; |
996 | 252 | if (spath == (char *) NULL) |
997 | 0 | spath = "NULL"; |
998 | 252 | if (*spath == '\0') |
999 | 0 | spath = "EMPTY"; |
1000 | | |
1001 | 252 | *execution_path='\0'; |
1002 | 252 | if (!IsValidFilesystemPath(path)) |
1003 | 0 | { |
1004 | | /* |
1005 | | If the path passed is NULL or invalid then we try to ask the |
1006 | | OS what the name of the executable is. Callers will often pass |
1007 | | NULL in order to invoke this functionality. |
1008 | | */ |
1009 | 0 | if (GetExecutionPath(execution_path)) |
1010 | 0 | { |
1011 | | /* |
1012 | | The call to the OS worked so we can do all the settings |
1013 | | */ |
1014 | 0 | (void) DefineClientPathAndName(execution_path); |
1015 | 0 | (void) LogMagickEvent(ConfigureEvent,GetMagickModule(), |
1016 | 0 | "Invalid path \"%s\" passed - asking OS worked: \"%s\"",spath, |
1017 | 0 | execution_path); |
1018 | 0 | } |
1019 | 0 | else |
1020 | 0 | { |
1021 | | /* |
1022 | | The call to the OS failed so we try to compute a usable |
1023 | | path based on the current working directory or by |
1024 | | searching the executable search path. |
1025 | | */ |
1026 | 0 | if (path) |
1027 | 0 | (void) strlcpy(execution_path,path,MaxTextExtent); |
1028 | 0 | if (GetExecutionPathUsingName(execution_path)) |
1029 | 0 | { |
1030 | 0 | (void) DefineClientPathAndName(execution_path); |
1031 | 0 | (void) LogMagickEvent(ConfigureEvent,GetMagickModule(), |
1032 | 0 | "Invalid path \"%s\" passed - asking OS failed, getcwd worked: \"%s\"",spath, |
1033 | 0 | execution_path); |
1034 | 0 | } |
1035 | 0 | else |
1036 | 0 | { |
1037 | | /* |
1038 | | At this point we are totally hosed and have nothing to |
1039 | | go on for the path, so all we can do is log the error |
1040 | | */ |
1041 | 0 | (void) LogMagickEvent(ConfigureEvent,GetMagickModule(), |
1042 | 0 | "Invalid path \"%s\" passed - asking OS failed, getcwd also failed",spath); |
1043 | 0 | } |
1044 | 0 | } |
1045 | 0 | } |
1046 | 252 | else |
1047 | 252 | { |
1048 | | /* |
1049 | | This is the easy one. The caller gave us the correct and |
1050 | | working path to the application, so we just use it |
1051 | | */ |
1052 | 252 | (void) strlcpy(execution_path,path,MaxTextExtent); |
1053 | 252 | (void) DefineClientPathAndName(execution_path); |
1054 | 252 | (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),"Valid path \"%s\"",spath); |
1055 | 252 | } |
1056 | | #else |
1057 | | ARG_NOT_USED(path); |
1058 | | #endif |
1059 | 252 | } |
1060 | | |
1061 | | /* |
1062 | | Establish signal handlers for common signals |
1063 | | |
1064 | | */ |
1065 | | static void |
1066 | | InitializeMagickSignalHandlers(void) |
1067 | 252 | { |
1068 | | #if 0 |
1069 | | /* termination of child process */ |
1070 | | #if defined(SIGCHLD) |
1071 | | MagickCondSignal(SIGCHLD,MagickIgnoreSignalHandler); |
1072 | | #endif |
1073 | | #endif |
1074 | | |
1075 | | /* hangup, default terminate */ |
1076 | 252 | #if defined(SIGHUP) |
1077 | 252 | MagickCondSignal(SIGHUP,MagickSignalHandler); |
1078 | 252 | #endif |
1079 | | /* interrupt (CONTROL-c), default terminate */ |
1080 | 252 | #if defined(SIGINT) |
1081 | 252 | MagickCondSignal(SIGINT,MagickSignalHandler); |
1082 | 252 | #endif |
1083 | | /* quit (CONTROL-\), default terminate with core */ |
1084 | 252 | #if defined(SIGQUIT) |
1085 | 252 | MagickCondSignal(SIGQUIT,MagickPanicSignalHandler); |
1086 | 252 | #endif |
1087 | | /* software-triggered abort, default terminate with core */ |
1088 | 252 | #if defined(SIGABRT) |
1089 | 252 | MagickCondSignal(SIGABRT,MagickPanicSignalHandler); |
1090 | 252 | #endif |
1091 | | /* floating point exception, default terminate with core */ |
1092 | 252 | #if defined(SIGFPE) |
1093 | 252 | MagickCondSignal(SIGFPE,MagickPanicSignalHandler); |
1094 | 252 | #endif |
1095 | | /* software termination signal from kill, default terminate */ |
1096 | 252 | #if defined(SIGTERM) |
1097 | 252 | MagickCondSignal(SIGTERM,MagickSignalHandler); |
1098 | 252 | #endif |
1099 | | /* Bus Error */ |
1100 | 252 | #if defined(SIGBUS) |
1101 | 252 | MagickCondSignal(SIGBUS,MagickPanicSignalHandler); |
1102 | 252 | #endif |
1103 | | /* segmentation fault */ |
1104 | 252 | #if defined(SIGSEGV) |
1105 | 252 | MagickCondSignal(SIGSEGV,MagickPanicSignalHandler); |
1106 | 252 | #endif |
1107 | | /* exceeded cpu limit, default terminate */ |
1108 | 252 | #if defined(SIGXCPU) |
1109 | 252 | MagickCondSignal(SIGXCPU,MagickSignalHandler); |
1110 | 252 | #endif |
1111 | | /* exceeded file size limit, default terminate */ |
1112 | 252 | #if defined(SIGXFSZ) |
1113 | 252 | MagickCondSignal(SIGXFSZ,MagickSignalHandler); |
1114 | 252 | #endif |
1115 | 252 | } |
1116 | | |
1117 | | |
1118 | | MagickExport void |
1119 | | InitializeMagick(const char *path) |
1120 | 252 | { |
1121 | 252 | ExceptionInfo exception; |
1122 | 252 | GetExceptionInfo(&exception); |
1123 | 252 | (void) InitializeMagickEx(path,0,&exception); |
1124 | 252 | if (exception.severity != UndefinedException) |
1125 | 0 | CatchException(&exception); |
1126 | 252 | DestroyExceptionInfo(&exception); |
1127 | 252 | } |
1128 | | |
1129 | | /* |
1130 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1131 | | % % |
1132 | | % % |
1133 | | % % |
1134 | | % I n i t i a l i z e M a g i c k E x % |
1135 | | % % |
1136 | | % % |
1137 | | % % |
1138 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1139 | | % |
1140 | | % InitializeMagickEx() initializes the GraphicsMagick environment, |
1141 | | % providing a bit more more control and visibility over initialization |
1142 | | % than the original InitializeMagick(). Use DestroyMagick() to destroy |
1143 | | % the GraphicsMagick environment when it is not longer needed. |
1144 | | % |
1145 | | % InitializeMagick() or InitializeMagickEx() MUST be invoked by the using |
1146 | | % program before making use of GraphicsMagick functions or else the library |
1147 | | % will be unusable and any usage is likely to cause a crash. |
1148 | | % |
1149 | | % This function should be invoked in the primary (original) thread of the |
1150 | | % application's process, and before starting any OpenMP threads, as part |
1151 | | % of program initialization. |
1152 | | % |
1153 | | % If alternate memory allocations are provided via MagickAllocFunctions() |
1154 | | % then that function should be invoked before InitializeMagickEx() since |
1155 | | % the memory allocation functions need to be consistent. |
1156 | | % |
1157 | | % Available options are: |
1158 | | % |
1159 | | % o MAGICK_OPT_NO_SIGNAL_HANDER - Don't register ANSI/POSIX signal handlers |
1160 | | % |
1161 | | % The format of the InitializeMagickEx function is: |
1162 | | % |
1163 | | % MagickPassFail InitializeMagickEx(const char *path, |
1164 | | % unsigned int options, |
1165 | | % ExceptionInfo *exception) |
1166 | | % |
1167 | | % A description of each parameter follows: |
1168 | | % |
1169 | | % o path: The execution path of the current GraphicsMagick client (or NULL) |
1170 | | % |
1171 | | % o options: Options bit flags tailoring initializations performed |
1172 | | % |
1173 | | % o exception: Information about initialization failure is reported here. |
1174 | | % |
1175 | | % |
1176 | | */ |
1177 | | |
1178 | | MagickExport MagickPassFail |
1179 | | InitializeMagickEx(const char *path, unsigned int options, |
1180 | | ExceptionInfo *exception) |
1181 | 252 | { |
1182 | | /* |
1183 | | NOTE: This routine sets up the path to the client which needs to |
1184 | | be determined before almost anything else works right. This also |
1185 | | includes logging!!! So we can't start logging until the path is |
1186 | | actually saved. As soon as we know what the path is we make the |
1187 | | same call to DefineClientSettings to set it up. Please make sure |
1188 | | that this rule is followed in any future updates the this code!!! |
1189 | | */ |
1190 | | |
1191 | 252 | const char |
1192 | 252 | *p; |
1193 | | |
1194 | 252 | MagickPassFail |
1195 | 252 | status = MagickPass; |
1196 | | |
1197 | 252 | (void) exception; |
1198 | | |
1199 | | /* Acquire initialization lock */ |
1200 | 252 | SPINLOCK_WAIT; |
1201 | | |
1202 | 252 | if (MagickInitialized == InitInitialized) |
1203 | 0 | { |
1204 | | /* Release initialization lock */ |
1205 | 0 | SPINLOCK_RELEASE; |
1206 | 0 | return status; |
1207 | 0 | } |
1208 | | |
1209 | | #if defined(USE_GLIBC_MTRACE) && USE_GLIBC_MTRACE |
1210 | | mtrace(); |
1211 | | #endif /* if defined(USE_GLIBC_MTRACE) && USE_GLIBC_MTRACE */ |
1212 | | |
1213 | | /* Save initialization options in case we need them later */ |
1214 | 252 | initialize_magick_options = options; |
1215 | | |
1216 | | #if defined(MSWINDOWS) |
1217 | | # if defined(_DEBUG) && !defined(__BORLANDC__) |
1218 | | { |
1219 | | int |
1220 | | debug; |
1221 | | |
1222 | | debug=_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); |
1223 | | debug|=_CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_DELAY_FREE_MEM_DF | |
1224 | | _CRTDBG_LEAK_CHECK_DF; |
1225 | | /* debug=_CrtSetDbgFlag(debug); */ |
1226 | | /* _ASSERTE(_CrtCheckMemory()); */ |
1227 | | } |
1228 | | # endif /* defined(_DEBUG) */ |
1229 | | #endif /* defined(MSWINDOWS) */ |
1230 | | |
1231 | | /* Initialize semaphores */ |
1232 | 252 | InitializeSemaphore(); |
1233 | | |
1234 | | /* Initialize exception handling */ |
1235 | 252 | InitializeMagickExceptionHandling(); |
1236 | | |
1237 | | /* Initialize logging */ |
1238 | 252 | InitializeLogInfo(); |
1239 | | |
1240 | | /* Initialize our random number generator */ |
1241 | 252 | InitializeMagickRandomGenerator(); |
1242 | | |
1243 | 252 | (void) LogMagickEvent(ConfigureEvent,GetMagickModule(), |
1244 | 252 | "Initialize Magick (path=\"%s\", options = 0x%04x)", |
1245 | 252 | path ? path : "(null)", options); |
1246 | | |
1247 | | /* |
1248 | | Set the filesystem block size. |
1249 | | */ |
1250 | 252 | { |
1251 | 252 | size_t |
1252 | 252 | block_size=16384; |
1253 | | |
1254 | 252 | if ((p=getenv("MAGICK_IOBUF_SIZE")) != (const char *) NULL) |
1255 | 0 | { |
1256 | 0 | long |
1257 | 0 | block_size_long; |
1258 | |
|
1259 | 0 | block_size_long = MagickAtoL(p); |
1260 | 0 | if ((block_size_long > 0L) && (block_size_long <= 2097152L)) |
1261 | 0 | block_size=(size_t) block_size_long; |
1262 | 0 | else |
1263 | 0 | (void) LogMagickEvent(ConfigureEvent,GetMagickModule(), |
1264 | 0 | "Ignoring unreasonable MAGICK_IOBUF_SIZE of " |
1265 | 0 | "%ld bbytes", block_size_long); |
1266 | 0 | } |
1267 | | |
1268 | 252 | MagickSetFileSystemBlockSize(block_size); |
1269 | 252 | } |
1270 | | |
1271 | | /* |
1272 | | Establish the path, filename, and display name of the client app |
1273 | | */ |
1274 | 252 | InitializeMagickClientPathAndName(path); |
1275 | | /* |
1276 | | If the client name did not get setup for any reason, we take one |
1277 | | last shot at it using the data the caller passed us. |
1278 | | */ |
1279 | 252 | if (GetClientName() == (const char *) NULL) |
1280 | 0 | DefineClientName(path); |
1281 | | |
1282 | | /* |
1283 | | Initialize any logging configuration which could not complete |
1284 | | since we did not know the installation directory yet |
1285 | | */ |
1286 | 252 | InitializeLogInfoPost(); |
1287 | | |
1288 | | /* |
1289 | | Adjust minimum coder class if requested. |
1290 | | */ |
1291 | 252 | if ((p=getenv("MAGICK_CODER_STABILITY")) != (const char *) NULL) |
1292 | 0 | { |
1293 | 0 | if (LocaleCompare(p,"BROKEN") == 0) |
1294 | 0 | MinimumCoderClass=BrokenCoderClass; |
1295 | 0 | else if (LocaleCompare(p,"UNSTABLE") == 0) |
1296 | 0 | MinimumCoderClass=UnstableCoderClass; |
1297 | 0 | else if (LocaleCompare(p,"STABLE") == 0) |
1298 | 0 | MinimumCoderClass=StableCoderClass; |
1299 | 0 | else if (LocaleCompare(p,"PRIMARY") == 0) |
1300 | 0 | MinimumCoderClass=PrimaryCoderClass; |
1301 | 0 | } |
1302 | | |
1303 | | #if defined(MSWINDOWS) |
1304 | | NTInitializeExceptionHandlers(); /* WIN32 Exceptions */ |
1305 | | #endif /* defined(MSWINDOWS) */ |
1306 | 252 | if (!(options & MAGICK_OPT_NO_SIGNAL_HANDER)) |
1307 | 252 | InitializeMagickSignalHandlers(); /* Signal handlers */ |
1308 | 252 | InitializeTemporaryFiles(); /* Temporary files (semaphore only) */ |
1309 | 252 | InitializeMagickResources(); /* Resources (semaphore+calculations) */ |
1310 | 252 | InitializeMagickRegistry(); /* Image/blob registry (semaphore+vars only) */ |
1311 | 252 | InitializeConstitute(); /* Constitute (semaphore only) */ |
1312 | 252 | InitializeMagickInfoList(); /* Coder registrations + modules */ |
1313 | | /*InitializeMagicInfo();*/ /* File format detection */ |
1314 | 252 | InitializeTypeInfo(); /* Font information (semaphore only) */ |
1315 | 252 | InitializeDelegateInfo(); /* External delegate information (semaphore only) */ |
1316 | 252 | InitializeColorInfo(); /* Color database (semaphore only) */ |
1317 | 252 | InitializeMagickMonitor(); /* Progress monitor (semaphore only) */ |
1318 | 252 | MagickInitializeCommandInfo(); /* Command parser (semaphore only) */ |
1319 | | |
1320 | | /* Let's log the three important setting as we exit this routine */ |
1321 | 252 | (void) LogMagickEvent(ConfigureEvent,GetMagickModule(), |
1322 | 252 | "Path: \"%s\" Name: \"%s\" Filename: \"%s\"", |
1323 | 252 | GetClientPath(),GetClientName(),GetClientFilename()); |
1324 | | |
1325 | | /* Now initialized */ |
1326 | 252 | MagickInitialized=InitInitialized; |
1327 | | |
1328 | | /* Release initialization lock */ |
1329 | 252 | SPINLOCK_RELEASE; |
1330 | | |
1331 | 252 | return status; |
1332 | 252 | } |
1333 | | |
1334 | | /* |
1335 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1336 | | % % |
1337 | | % % |
1338 | | % % |
1339 | | + I n i t i a l i z e M a g i c k I n f o L i s t % |
1340 | | % % |
1341 | | % % |
1342 | | % % |
1343 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1344 | | % |
1345 | | % Method InitializeMagickInfoList initializes the magick info facility |
1346 | | % |
1347 | | % The format of the InitializeMagickInfoList method is: |
1348 | | % |
1349 | | % MagickPassFail InitializeMagickInfoList(void) |
1350 | | % |
1351 | | % |
1352 | | */ |
1353 | | static MagickPassFail |
1354 | | InitializeMagickInfoList(void) |
1355 | 252 | { |
1356 | 252 | assert(magick_semaphore == (SemaphoreInfo *) NULL); |
1357 | 252 | magick_semaphore=AllocateSemaphoreInfo(); |
1358 | | |
1359 | 252 | assert(module_semaphore == (SemaphoreInfo *) NULL); |
1360 | 252 | module_semaphore=AllocateSemaphoreInfo(); |
1361 | | |
1362 | 252 | InitializeMagickModules(); /* Module loader */ |
1363 | | |
1364 | 252 | return MagickPass; |
1365 | 252 | } |
1366 | | |
1367 | | /* |
1368 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1369 | | % % |
1370 | | % % |
1371 | | % % |
1372 | | % I s M a g i c k C o n f l i c t % |
1373 | | % % |
1374 | | % % |
1375 | | % % |
1376 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1377 | | % |
1378 | | % Method IsMagickConflict returns true if the image format conflicts with |
1379 | | % a logical drive (.e.g. X:). |
1380 | | % |
1381 | | % The format of the IsMagickConflict method is: |
1382 | | % |
1383 | | % MagickBool IsMagickConflict(const char *magick) |
1384 | | % |
1385 | | % A description of each parameter follows: |
1386 | | % |
1387 | | % o status: Method IsMagickConflict returns true if the image format |
1388 | | % conflicts with a logical drive. |
1389 | | % |
1390 | | % o magick: Specifies the image format. |
1391 | | % |
1392 | | % |
1393 | | */ |
1394 | | MagickExport MagickBool |
1395 | | IsMagickConflict(const char *magick) |
1396 | 1.58M | { |
1397 | 1.58M | assert(magick != (char *) NULL); |
1398 | | #if defined(MSWINDOWS) || defined(__CYGWIN__) |
1399 | | return(NTIsMagickConflict(magick)); |
1400 | | #endif |
1401 | 1.58M | ARG_NOT_USED(magick); |
1402 | 1.58M | return(MagickFalse); |
1403 | 1.58M | } |
1404 | | |
1405 | | /* |
1406 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1407 | | % % |
1408 | | % % |
1409 | | % % |
1410 | | % L i s t M a g i c k I n f o % |
1411 | | % % |
1412 | | % % |
1413 | | % % |
1414 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1415 | | % |
1416 | | % ListMagickInfo() lists the image formats to a file. |
1417 | | % |
1418 | | % The format of the ListMagickInfo method is: |
1419 | | % |
1420 | | % MagickPassFail ListMagickInfo(FILE *file,ExceptionInfo *exception) |
1421 | | % |
1422 | | % A description of each parameter follows. |
1423 | | % |
1424 | | % o file: A file handle. |
1425 | | % |
1426 | | % o exception: Return any errors or warnings in this structure. |
1427 | | % |
1428 | | % |
1429 | | */ |
1430 | | MagickExport MagickPassFail |
1431 | | ListMagickInfo(FILE *file,ExceptionInfo *exception) |
1432 | 0 | { |
1433 | |
|
1434 | 0 | MagickInfo |
1435 | 0 | **magick_array; |
1436 | |
|
1437 | 0 | int |
1438 | 0 | i; |
1439 | |
|
1440 | 0 | if (file == (FILE *) NULL) |
1441 | 0 | file=stdout; |
1442 | |
|
1443 | 0 | magick_array=GetMagickInfoArray(exception); |
1444 | 0 | if (!magick_array) |
1445 | 0 | return False; |
1446 | | |
1447 | 0 | (void) fprintf(file," Format L Mode Description\n"); |
1448 | 0 | (void) fprintf(file,"--------------------------------------------------------" |
1449 | 0 | "------------------------\n"); |
1450 | 0 | for (i=0; magick_array[i] != 0; i++) |
1451 | 0 | { |
1452 | 0 | if (magick_array[i]->stealth) |
1453 | 0 | continue; |
1454 | 0 | (void) fprintf(file,"%9s %c %c%c%c", |
1455 | 0 | magick_array[i]->name ? magick_array[i]->name : "", |
1456 | 0 | (magick_array[i]->coder_class == PrimaryCoderClass ? 'P' : |
1457 | 0 | (magick_array[i]->coder_class == StableCoderClass ? 'S' : |
1458 | 0 | 'U')), |
1459 | 0 | (magick_array[i]->decoder ? 'r' : '-'), |
1460 | 0 | (magick_array[i]->encoder ? 'w' : '-'), |
1461 | 0 | ((magick_array[i]->encoder && magick_array[i]->adjoin) ? '+' : '-')); |
1462 | 0 | if (magick_array[i]->description != (char *) NULL) |
1463 | 0 | (void) fprintf(file," %.1024s",magick_array[i]->description); |
1464 | 0 | if (magick_array[i]->version != (char *) NULL) |
1465 | 0 | (void) fprintf(file," (%.1024s)",magick_array[i]->version); |
1466 | 0 | (void) fprintf(file,"\n"); |
1467 | 0 | if (magick_array[i]->note != (char *) NULL) |
1468 | 0 | { |
1469 | 0 | char |
1470 | 0 | **text; |
1471 | |
|
1472 | 0 | text=StringToList(magick_array[i]->note); |
1473 | 0 | if (text != (char **) NULL) |
1474 | 0 | { |
1475 | 0 | register long |
1476 | 0 | j; |
1477 | |
|
1478 | 0 | for (j=0; text[j] != (char *) NULL; j++) |
1479 | 0 | { |
1480 | 0 | (void) fprintf(file," %.1024s\n",text[j]); |
1481 | 0 | MagickFreeMemory(text[j]); |
1482 | 0 | } |
1483 | 0 | MagickFreeMemory(text); |
1484 | 0 | } |
1485 | 0 | } |
1486 | 0 | } |
1487 | 0 | (void) fprintf(file,"\n Meaning of 'L': P=Primary, S=Stable, U=Unstable\n"); |
1488 | 0 | (void) fflush(file); |
1489 | 0 | MagickFreeMemory(magick_array); |
1490 | 0 | return(MagickPass); |
1491 | 0 | } |
1492 | | |
1493 | | /* |
1494 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1495 | | % % |
1496 | | % % |
1497 | | % % |
1498 | | % L i s t M o d u l e M a p % |
1499 | | % % |
1500 | | % % |
1501 | | % % |
1502 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1503 | | % |
1504 | | % Method ListModuleMap lists the module alias info to a file in the XML |
1505 | | % format used by modules.mgk. True is returned on success. |
1506 | | % |
1507 | | % The format of the ListModuleMap method is: |
1508 | | % |
1509 | | % MagickPassFail ListModuleMap(FILE *file,ExceptionInfo *exception) |
1510 | | % |
1511 | | % A description of each parameter follows. |
1512 | | % |
1513 | | % o file: An pointer to a FILE. |
1514 | | % |
1515 | | % o exception: Return any errors or warnings in this structure. |
1516 | | % |
1517 | | % |
1518 | | */ |
1519 | | MagickExport MagickPassFail |
1520 | | ListModuleMap(FILE *file,ExceptionInfo *exception) |
1521 | 0 | { |
1522 | 0 | MagickInfo |
1523 | 0 | **magick_array; |
1524 | |
|
1525 | 0 | int |
1526 | 0 | i; |
1527 | |
|
1528 | 0 | if (file == (const FILE *) NULL) |
1529 | 0 | file=stdout; |
1530 | |
|
1531 | 0 | magick_array=GetMagickInfoArray(exception); |
1532 | 0 | if (!magick_array) |
1533 | 0 | return MagickFail; |
1534 | | |
1535 | 0 | (void) fprintf(file, "<?xml version=\"1.0\"?>\n"); |
1536 | 0 | (void) fprintf(file, "<!-- %s -->\n",GetMagickCopyright()); |
1537 | 0 | (void) fprintf(file, "<!-- Magick Module Alias Map (modules.mgk) -->\n"); |
1538 | 0 | (void) fprintf(file, "<modulemap>\n"); |
1539 | |
|
1540 | 0 | for (i=0; magick_array[i] != 0; i++) |
1541 | 0 | { |
1542 | 0 | if (LocaleCompare(magick_array[i]->name,magick_array[i]->module) != 0) |
1543 | 0 | { |
1544 | 0 | (void) fprintf(file, " <module magick=\"%s\" name=\"%s\" />\n", |
1545 | 0 | magick_array[i]->name, |
1546 | 0 | (magick_array[i]->module == NULL ? "(null)" : |
1547 | 0 | magick_array[i]->module)); |
1548 | 0 | } |
1549 | 0 | } |
1550 | 0 | (void) fprintf(file, "</modulemap>\n"); |
1551 | 0 | (void) fflush(file); |
1552 | |
|
1553 | 0 | MagickFreeMemory(magick_array); |
1554 | |
|
1555 | 0 | return(MagickPass); |
1556 | 0 | } |
1557 | | |
1558 | | /* |
1559 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1560 | | % % |
1561 | | % % |
1562 | | % % |
1563 | | % M a g i c k T o M i m e % |
1564 | | % % |
1565 | | % % |
1566 | | % % |
1567 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1568 | | % |
1569 | | % Method MagickToMime returns the officially registered (or de facto) MIME |
1570 | | % media-type (see https://www.iana.org/assignments/media-types/media-types.xhtml) |
1571 | | % corresponding to a magick string. If there is no registered media-type, |
1572 | | % then the string "image/x-magick" (all lower case) is returned. The returned |
1573 | | % string must be deallocated by the user. |
1574 | | % |
1575 | | % The format of the MagickToMime method is: |
1576 | | % |
1577 | | % char *MagickToMime(const char *magick) |
1578 | | % |
1579 | | % A description of each parameter follows. |
1580 | | % |
1581 | | % o magick: GraphicsMagick format specification "magick" tag. |
1582 | | % |
1583 | | % |
1584 | | */ |
1585 | | MagickExport char * |
1586 | | MagickToMime(const char *magick) |
1587 | 3.12k | { |
1588 | 3.12k | char |
1589 | 3.12k | media[MaxTextExtent]; |
1590 | | |
1591 | 3.12k | unsigned int |
1592 | 3.12k | i; |
1593 | | |
1594 | 3.12k | static const struct |
1595 | 3.12k | { |
1596 | 3.12k | const char |
1597 | 3.12k | magick[14], |
1598 | 3.12k | *media; |
1599 | 3.12k | } |
1600 | 3.12k | MediaTypes[] = |
1601 | 3.12k | { |
1602 | 3.12k | { "apng", "image/apng" }, |
1603 | 3.12k | { "avc", "image/avci" }, |
1604 | 3.12k | { "avi", "video/avi" }, |
1605 | 3.12k | { "avif", "image/avif" }, |
1606 | 3.12k | { "bmp", "image/bmp" }, |
1607 | 3.12k | { "cgm", "image/cgm;Version=4;ProfileId=WebCGM" }, /* W3 WebCGM */ |
1608 | 3.12k | { "dcm", "application/dicom" }, /* Incomplete. See RFC 3240 */ |
1609 | 3.12k | { "dpx", "image/dpx" }, |
1610 | 3.12k | { "emf", "image/emf" }, |
1611 | 3.12k | { "epdf", "application/pdf" }, |
1612 | 3.12k | { "epi", "application/postscript" }, |
1613 | 3.12k | { "eps", "application/postscript" }, |
1614 | 3.12k | { "eps2", "application/postscript" }, |
1615 | 3.12k | { "eps3", "application/postscript" }, |
1616 | 3.12k | { "epsf", "application/postscript" }, |
1617 | 3.12k | { "ept", "application/postscript" }, |
1618 | 3.12k | { "fax", "image/g3fax" }, |
1619 | 3.12k | { "fits", "image/fits" }, |
1620 | 3.12k | { "fpx", "image/vnd.fpx" }, |
1621 | 3.12k | { "g3", "image/g3fax" }, |
1622 | 3.12k | { "gif", "image/gif" }, |
1623 | 3.12k | { "gif87", "image/gif" }, |
1624 | 3.12k | { "heic", "image/heic" }, |
1625 | 3.12k | { "heic-sequence", "image/heic-sequence" }, |
1626 | 3.12k | { "heif", "image/heif" }, |
1627 | 3.12k | { "heif-sequence", "image/heif-sequence" }, |
1628 | 3.12k | { "ico", "image/x-icon" }, |
1629 | 3.12k | { "j2c", "image/j2c" }, |
1630 | 3.12k | { "jpeg", "image/jpeg" }, |
1631 | 3.12k | { "jpg", "image/jpeg" }, |
1632 | 3.12k | { "jxl", "image/jxl" }, |
1633 | 3.12k | { "mng", "video/x-mng" }, |
1634 | 3.12k | { "mpeg", "video/mpeg" }, |
1635 | 3.12k | { "pdf", "application/pdf" }, |
1636 | 3.12k | { "png", "image/png" }, |
1637 | 3.12k | { "ps", "application/postscript" }, |
1638 | 3.12k | { "ps2", "application/postscript" }, |
1639 | 3.12k | { "ps3", "application/postscript" }, |
1640 | 3.12k | { "svg", "image/svg+xml" }, |
1641 | 3.12k | { "tif", "image/tiff" }, |
1642 | 3.12k | { "tiff", "image/tiff" }, |
1643 | 3.12k | { "wbmp", "image/vnd.wap.wbmp" }, |
1644 | 3.12k | { "webp", "image/webp" }, |
1645 | 3.12k | { "wmf", "image/wmf" } |
1646 | 3.12k | }; |
1647 | | |
1648 | 102k | for (i=0; i < ArraySize(MediaTypes); i++) |
1649 | 102k | if (LocaleCompare(MediaTypes[i].magick,magick) == 0) |
1650 | 2.73k | return(AllocateString(MediaTypes[i].media)); |
1651 | 395 | MagickFormatString(media,sizeof(media),"image/x-%.1024s",magick); |
1652 | 395 | LocaleLower(media+8); |
1653 | 395 | return(AllocateString(media)); |
1654 | 3.12k | } |
1655 | | |
1656 | | /* |
1657 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1658 | | % % |
1659 | | % % |
1660 | | % % |
1661 | | % R e g i s t e r M a g i c k I n f o % |
1662 | | % % |
1663 | | % % |
1664 | | % % |
1665 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1666 | | % |
1667 | | % RegisterMagickInfo() adds attributes for a particular image format to the |
1668 | | % list of supported formats. The attributes include the image format name, |
1669 | | % a method to read and/or write the format, whether the format supports the |
1670 | | % saving of more than one frame to the same file or blob, whether the format |
1671 | | % supports native in-memory I/O, and a brief description of the format. |
1672 | | % |
1673 | | % The format of the RegisterMagickInfo method is: |
1674 | | % |
1675 | | % MagickInfo *RegisterMagickInfo(MagickInfo *magick_info) |
1676 | | % |
1677 | | % A description of each parameter follows: |
1678 | | % |
1679 | | % o magick_info: The magick info. |
1680 | | % |
1681 | | */ |
1682 | | MagickExport MagickInfo * |
1683 | | RegisterMagickInfo(MagickInfo *magick_info) |
1684 | 984 | { |
1685 | 984 | assert(magick_info != (MagickInfo *) NULL); |
1686 | 984 | assert(magick_info->signature == MagickSignature); |
1687 | | |
1688 | | /* |
1689 | | Remove any existing entry. |
1690 | | */ |
1691 | 984 | (void) UnregisterMagickInfo(magick_info->name); |
1692 | | |
1693 | | /* |
1694 | | Verify that coder stability level is sufficient. |
1695 | | */ |
1696 | 984 | if (magick_info->coder_class >= MinimumCoderClass) |
1697 | 984 | { |
1698 | | /* |
1699 | | Add to front of list. |
1700 | | */ |
1701 | 984 | LockSemaphoreInfo(magick_semaphore); |
1702 | 984 | magick_info->previous=(MagickInfo *) NULL; |
1703 | 984 | magick_info->next=magick_list; |
1704 | 984 | if (magick_info->next != (MagickInfo *) NULL) |
1705 | 859 | magick_info->next->previous=magick_info; |
1706 | 984 | magick_list=magick_info; |
1707 | 984 | UnlockSemaphoreInfo(magick_semaphore); |
1708 | 984 | return(magick_info); |
1709 | 984 | } |
1710 | | |
1711 | | /* |
1712 | | Discard registration and return NULL. |
1713 | | */ |
1714 | 0 | DestroyMagickInfo(&magick_info); |
1715 | 0 | return(magick_info); |
1716 | 984 | } |
1717 | | |
1718 | | /* |
1719 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1720 | | % % |
1721 | | % % |
1722 | | % % |
1723 | | % P a n i c D e s t r o y M a g i c k % |
1724 | | % % |
1725 | | % % |
1726 | | % % |
1727 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1728 | | % |
1729 | | % PanicDestroyMagick() destroys only persistent allocations such as |
1730 | | % temporary files. Other allocations (e.g. semaphores and heap memory) |
1731 | | % remain allocated. This function is an alternative to DestroyMagick() |
1732 | | % which is async-safe so it may be invoked from signal handers, and |
1733 | | % may be invoked from thread context. No semaphores are taken and no |
1734 | | % additional heap memory is allocated by this function. The program |
1735 | | % must quit immediately after invoking this function. |
1736 | | % |
1737 | | % The format of the PanicDestroyMagick function is: |
1738 | | % |
1739 | | % void PanicDestroyMagick(void) |
1740 | | % |
1741 | | % |
1742 | | */ |
1743 | | /* |
1744 | | Set to 1 to break the memory allocation functions. This is a |
1745 | | debugging aid. In a multi-threaded program, other threads may |
1746 | | still be allocating and deallocating memory while a signal |
1747 | | handler is called. |
1748 | | */ |
1749 | | #define MAGICK_BREAK_HEAP 0 |
1750 | | #if MAGICK_BREAK_HEAP |
1751 | | static void |
1752 | | PanicFreeFunc(void *ptr) |
1753 | | { |
1754 | | char err_str[] = "Attempt to free memory in PanicDestroyMagick()\n"; |
1755 | | ARG_NOT_USED(ptr); |
1756 | | if (write(STDERR_FILENO,err_str,sizeof(err_str)-1) == -1) |
1757 | | { |
1758 | | /* Exists to quench warning */ |
1759 | | } |
1760 | | } |
1761 | | static void * |
1762 | | PanicMallocFunc(size_t size) |
1763 | | { |
1764 | | char err_str[] = "Attempt to malloc memory in PanicDestroyMagick()\n"; |
1765 | | ARG_NOT_USED(size); |
1766 | | if (write(STDERR_FILENO,err_str,sizeof(err_str)-1) == -1) |
1767 | | { |
1768 | | /* Exists to quench warning */ |
1769 | | } |
1770 | | return (void *) NULL; |
1771 | | } |
1772 | | static void * |
1773 | | PanicReallocFunc(void *ptr, size_t size) |
1774 | | { |
1775 | | char err_str[] = "Attempt to realloc memory in PanicDestroyMagick()\n"; |
1776 | | ARG_NOT_USED(ptr); |
1777 | | ARG_NOT_USED(size); |
1778 | | if (write(STDERR_FILENO,err_str,sizeof(err_str)-1) == -1) |
1779 | | { |
1780 | | /* Exists to quench warning */ |
1781 | | } |
1782 | | return (void *) NULL; |
1783 | | } |
1784 | | #endif /* if MAGICK_BREAK_HEAP */ |
1785 | | MagickExport void |
1786 | | PanicDestroyMagick(void) |
1787 | 0 | { |
1788 | 0 | if (MagickInitialized == InitInitialized) |
1789 | 0 | { |
1790 | | #if MAGICK_BREAK_HEAP |
1791 | | /* |
1792 | | Enforce that we don't use the memory allocation functions by |
1793 | | setting them all to dummy functions. |
1794 | | */ |
1795 | | MagickAllocFunctions(PanicFreeFunc,PanicMallocFunc,PanicReallocFunc); |
1796 | | #endif /* if MAGICK_BREAK_HEAP */ |
1797 | | /* |
1798 | | Release persistent resources |
1799 | | */ |
1800 | 0 | PurgeTemporaryFilesAsyncSafe(); |
1801 | 0 | } |
1802 | 0 | } |
1803 | | |
1804 | | /* |
1805 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1806 | | % % |
1807 | | % % |
1808 | | % % |
1809 | | % S e t M a g i c k I n f o % |
1810 | | % % |
1811 | | % % |
1812 | | % % |
1813 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1814 | | % |
1815 | | % Method SetMagickInfo allocates a MagickInfo structure and initializes the |
1816 | | % members to default values. |
1817 | | % |
1818 | | % The format of the SetMagickInfo method is: |
1819 | | % |
1820 | | % MagickInfo *SetMagickInfo(const char *name) |
1821 | | % |
1822 | | % A description of each parameter follows: |
1823 | | % |
1824 | | % o magick_info: Method SetMagickInfo returns the allocated and initialized |
1825 | | % MagickInfo structure. |
1826 | | % |
1827 | | % o name: a character string that represents the image format associated |
1828 | | % with the MagickInfo structure. |
1829 | | % |
1830 | | % |
1831 | | */ |
1832 | | MagickExport MagickInfo * |
1833 | | SetMagickInfo(const char *name) |
1834 | 984 | { |
1835 | 984 | MagickInfo |
1836 | 984 | *magick_info; |
1837 | | |
1838 | 984 | assert(name != (const char *) NULL); |
1839 | 984 | magick_info=MagickAllocateClearedMemory(MagickInfo *,sizeof(MagickInfo)); |
1840 | 984 | if (magick_info == (MagickInfo *) NULL) |
1841 | 0 | MagickFatalError3(ResourceLimitFatalError,MemoryAllocationFailed, |
1842 | 984 | UnableToAllocateMagickInfo); |
1843 | 984 | magick_info->name=name; |
1844 | 984 | magick_info->adjoin=MagickTrue; |
1845 | 984 | magick_info->raw=MagickFalse; |
1846 | 984 | magick_info->stealth=MagickFalse; |
1847 | 984 | magick_info->seekable_stream=MagickFalse; |
1848 | 984 | magick_info->blob_support=MagickTrue; |
1849 | 984 | magick_info->thread_support=MagickTrue; |
1850 | 984 | magick_info->coder_class=StableCoderClass; |
1851 | 984 | magick_info->extension_treatment=HintExtensionTreatment; |
1852 | 984 | magick_info->signature=MagickSignature; |
1853 | 984 | return(magick_info); |
1854 | 984 | } |
1855 | | |
1856 | | /* |
1857 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1858 | | % % |
1859 | | % % |
1860 | | % % |
1861 | | % U n r e g i s t e r M a g i c k I n f o % |
1862 | | % % |
1863 | | % % |
1864 | | % % |
1865 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1866 | | % |
1867 | | % Method UnregisterMagickInfo removes a name from the magick info list. It |
1868 | | % returns MagickFail if the name does not exist in the list otherwise |
1869 | | % MagickPass. |
1870 | | % |
1871 | | % The format of the UnregisterMagickInfo method is: |
1872 | | % |
1873 | | % unsigned int UnregisterMagickInfo(const char *name) |
1874 | | % |
1875 | | % A description of each parameter follows: |
1876 | | % |
1877 | | % o status: Method UnregisterMagickInfo returns False if the name does not |
1878 | | % exist in the list otherwise True. |
1879 | | % |
1880 | | % o name: a character string that represents the image format we are |
1881 | | % looking for. |
1882 | | % |
1883 | | */ |
1884 | | MagickExport MagickPassFail |
1885 | | UnregisterMagickInfo(const char *name) |
1886 | 984 | { |
1887 | 984 | MagickInfo |
1888 | 984 | *magick_info; |
1889 | | |
1890 | 984 | register MagickInfo |
1891 | 984 | *p; |
1892 | | |
1893 | 984 | unsigned int |
1894 | 984 | status; |
1895 | | |
1896 | 984 | assert(name != (const char *) NULL); |
1897 | 984 | status=MagickFail; |
1898 | 984 | LockSemaphoreInfo(magick_semaphore); |
1899 | 23.2k | for (p=magick_list; p != (MagickInfo *) NULL; p=p->next) |
1900 | 22.2k | { |
1901 | 22.2k | if (LocaleCompare(p->name,name) != 0) |
1902 | 22.2k | continue; |
1903 | 0 | if (p->next != (MagickInfo *) NULL) |
1904 | 0 | p->next->previous=p->previous; |
1905 | 0 | if (p->previous != (MagickInfo *) NULL) |
1906 | 0 | p->previous->next=p->next; |
1907 | 0 | else |
1908 | 0 | magick_list=p->next; |
1909 | 0 | magick_info=p; |
1910 | 0 | DestroyMagickInfo(&magick_info); |
1911 | 0 | status=MagickPass; |
1912 | 0 | break; |
1913 | 22.2k | } |
1914 | 984 | UnlockSemaphoreInfo(magick_semaphore); |
1915 | 984 | return(status); |
1916 | 984 | } |