1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % M M IIIII M M EEEEE %
6 % MM MM I MM MM E %
7 % M M M I M M M EEE %
8 % M M I M M E %
9 % M M IIIII M M EEEEE %
10 % %
11 % %
12 % MagickCore Mime Methods %
13 % %
14 % Software Design %
15 % July 2000 %
16 % %
17 % %
18 % Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization %
19 % dedicated to making software imaging solutions freely available. %
20 % %
21 % You may not use this file except in compliance with the License. You may %
22 % obtain a copy of the License at %
23 % %
24 % https://imagemagick.org/script/license.php %
25 % %
26 % Unless required by applicable law or agreed to in writing, software %
27 % distributed under the License is distributed on an "AS IS" BASIS, %
28 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
29 % See the License for the specific language governing permissions and %
30 % limitations under the License. %
31 % %
32 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
33 %
34 %
35 */
36
37 /*
38 Include declarations.
39 */
40 #include "MagickCore/studio.h"
41 #include "MagickCore/blob.h"
42 #include "MagickCore/client.h"
43 #include "MagickCore/configure.h"
44 #include "MagickCore/configure-private.h"
45 #include "MagickCore/exception.h"
46 #include "MagickCore/exception-private.h"
47 #include "MagickCore/linked-list.h"
48 #include "MagickCore/memory_.h"
49 #include "MagickCore/mime.h"
50 #include "MagickCore/mime-private.h"
51 #include "MagickCore/option.h"
52 #include "MagickCore/semaphore.h"
53 #include "MagickCore/string_.h"
54 #include "MagickCore/token.h"
55 #include "MagickCore/utility.h"
56 #include "MagickCore/utility-private.h"
57 #include "MagickCore/xml-tree.h"
58 #include "MagickCore/xml-tree-private.h"
59
60 /*
61 Define declarations.
62 */
63 #define MimeFilename "mime.xml"
64
65 /*
66 Typedef declaration.
67 */
68 struct _MimeInfo
69 {
70 char
71 *path,
72 *type,
73 *description,
74 *pattern;
75
76 ssize_t
77 priority;
78
79 MagickOffsetType
80 offset;
81
82 size_t
83 extent;
84
85 DataType
86 data_type;
87
88 ssize_t
89 mask,
90 value;
91
92 EndianType
93 endian;
94
95 size_t
96 length;
97
98 unsigned char
99 *magic;
100
101 MagickBooleanType
102 stealth;
103
104 size_t
105 signature;
106 };
107
108 /*
109 Static declarations.
110 */
111 static LinkedListInfo
112 *mime_cache = (LinkedListInfo *) NULL;
113
114 static SemaphoreInfo
115 *mime_semaphore = (SemaphoreInfo *) NULL;
116
117 /*
118 Forward declarations.
119 */
120 static MagickBooleanType
121 IsMimeCacheInstantiated(ExceptionInfo *);
122
123 #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
124 static MagickBooleanType
125 LoadMimeCache(LinkedListInfo *,const char *,const char *,const size_t,
126 ExceptionInfo *);
127 #endif
128
129 /*
130 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
131 % %
132 % %
133 % %
134 % A c q u i r e M i m e C a c h e %
135 % %
136 % %
137 % %
138 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
139 %
140 % AcquireMimeCache() caches one or more magic configurations which provides
141 % a mapping between magic attributes and a magic name.
142 %
143 % The format of the AcquireMimeCache method is:
144 %
145 % LinkedListInfo *AcquireMimeCache(const char *filename,
146 % ExceptionInfo *exception)
147 %
148 % A description of each parameter follows:
149 %
150 % o filename: the font file name.
151 %
152 % o exception: return any errors or warnings in this structure.
153 %
154 */
AcquireMimeCache(const char * filename,ExceptionInfo * exception)155 MagickExport LinkedListInfo *AcquireMimeCache(const char *filename,
156 ExceptionInfo *exception)
157 {
158 LinkedListInfo
159 *cache;
160
161 cache=NewLinkedList(0);
162 #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
163 {
164 const StringInfo
165 *option;
166
167 LinkedListInfo
168 *options;
169
170 options=GetConfigureOptions(filename,exception);
171 option=(const StringInfo *) GetNextValueInLinkedList(options);
172 while (option != (const StringInfo *) NULL)
173 {
174 (void) LoadMimeCache(cache,(const char *)
175 GetStringInfoDatum(option),GetStringInfoPath(option),0,exception);
176 option=(const StringInfo *) GetNextValueInLinkedList(options);
177 }
178 options=DestroyConfigureOptions(options);
179 }
180 #else
181 magick_unreferenced(filename);
182 magick_unreferenced(exception);
183 #endif
184 return(cache);
185 }
186
187 /*
188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
189 % %
190 % %
191 % %
192 + G e t M i m e I n f o %
193 % %
194 % %
195 % %
196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
197 %
198 % GetMimeInfo() attempts to classify the content to identify which mime type
199 % is associated with the content, if any.
200 %
201 % The format of the GetMimeInfo method is:
202 %
203 % const MimeInfo *GetMimeInfo(const char *filename,
204 % const unsigned char *magic,const size_t length,
205 % ExceptionInfo *exception)
206 %
207 % A description of each parameter follows:
208 %
209 % o filename: If we cannot not classify the string, we attempt to classify
210 % based on the filename (e.g. *.pdf returns application/pdf).
211 %
212 % o magic: A binary string generally representing the first few characters
213 % of the image file or blob.
214 %
215 % o length: the length of the binary signature.
216 %
217 % o exception: return any errors or warnings in this structure.
218 %
219 */
GetMimeInfo(const char * filename,const unsigned char * magic,const size_t length,ExceptionInfo * exception)220 MagickExport const MimeInfo *GetMimeInfo(const char *filename,
221 const unsigned char *magic,const size_t length,ExceptionInfo *exception)
222 {
223 const MimeInfo
224 *mime_info;
225
226 EndianType
227 endian;
228
229 const MimeInfo
230 *p;
231
232 const unsigned char
233 *q;
234
235 ssize_t
236 i;
237
238 ssize_t
239 value;
240
241 unsigned long
242 lsb_first;
243
244 assert(exception != (ExceptionInfo *) NULL);
245 if (IsMimeCacheInstantiated(exception) == MagickFalse)
246 return((const MimeInfo *) NULL);
247 /*
248 Search for mime tag.
249 */
250 mime_info=(const MimeInfo *) NULL;
251 lsb_first=1;
252 LockSemaphoreInfo(mime_semaphore);
253 ResetLinkedListIterator(mime_cache);
254 p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
255 if ((magic == (const unsigned char *) NULL) || (length == 0))
256 {
257 UnlockSemaphoreInfo(mime_semaphore);
258 return(p);
259 }
260 while (p != (const MimeInfo *) NULL)
261 {
262 assert(p->offset >= 0);
263 if (mime_info != (const MimeInfo *) NULL)
264 if (p->priority > mime_info->priority)
265 {
266 p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
267 continue;
268 }
269 if ((p->pattern != (char *) NULL) && (filename != (char *) NULL))
270 {
271 if (GlobExpression(filename,p->pattern,MagickFalse) != MagickFalse)
272 mime_info=p;
273 p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
274 continue;
275 }
276 switch (p->data_type)
277 {
278 case ByteData:
279 {
280 if ((size_t) (p->offset+4) > length)
281 break;
282 q=magic+p->offset;
283 value=(ssize_t) (*q++);
284 if (p->mask == 0)
285 {
286 if (p->value == value)
287 mime_info=p;
288 }
289 else
290 {
291 if ((p->value & p->mask) == value)
292 mime_info=p;
293 }
294 break;
295 }
296 case ShortData:
297 {
298 if ((size_t) (p->offset+4) > length)
299 break;
300 q=magic+p->offset;
301 endian=p->endian;
302 if (p->endian == UndefinedEndian)
303 endian=(*(char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
304 if (endian == LSBEndian)
305 {
306 value=(ssize_t) (*q++);
307 value|=(*q++) << 8;
308 }
309 else
310 {
311 value=(ssize_t) (*q++) << 8;
312 value|=(*q++);
313 }
314 if (p->mask == 0)
315 {
316 if (p->value == value)
317 mime_info=p;
318 }
319 else
320 {
321 if ((p->value & p->mask) == value)
322 mime_info=p;
323 }
324 break;
325 }
326 case LongData:
327 {
328 if ((size_t) (p->offset+4) > length)
329 break;
330 q=magic+p->offset;
331 endian=p->endian;
332 if (p->endian == UndefinedEndian)
333 endian=(*(char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
334 if (endian == LSBEndian)
335 {
336 value=(ssize_t) (*q++);
337 value|=((ssize_t) *q++) << 8;
338 value|=((ssize_t) *q++) << 16;
339 value|=((ssize_t) *q++) << 24;
340 }
341 else
342 {
343 value=(ssize_t) (*q++) << 24;
344 value|=((ssize_t) *q++) << 16;
345 value|=((ssize_t) *q++) << 8;
346 value|=((ssize_t) *q++);
347 }
348 if (p->mask == 0)
349 {
350 if (p->value == value)
351 mime_info=p;
352 }
353 else
354 {
355 if ((p->value & p->mask) == value)
356 mime_info=p;
357 }
358 break;
359 }
360 case StringData:
361 default:
362 {
363 for (i=0; i <= (ssize_t) p->extent; i++)
364 {
365 if ((size_t) (p->offset+i+p->length) > length)
366 break;
367 if (memcmp(magic+p->offset+i,p->magic,p->length) == 0)
368 {
369 mime_info=p;
370 break;
371 }
372 }
373 break;
374 }
375 }
376 p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
377 }
378 if (mime_info != (const MimeInfo *) NULL)
379 (void) InsertValueInLinkedList(mime_cache,0,
380 RemoveElementByValueFromLinkedList(mime_cache,p));
381 UnlockSemaphoreInfo(mime_semaphore);
382 return(mime_info);
383 }
384
385 /*
386 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
387 % %
388 % %
389 % %
390 % G e t M i m e I n f o L i s t %
391 % %
392 % %
393 % %
394 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
395 %
396 % GetMimeInfoList() returns any image aliases that match the specified
397 % pattern.
398 %
399 % The magic of the GetMimeInfoList function is:
400 %
401 % const MimeInfo **GetMimeInfoList(const char *pattern,
402 % size_t *number_aliases,ExceptionInfo *exception)
403 %
404 % A description of each parameter follows:
405 %
406 % o pattern: Specifies a pointer to a text string containing a pattern.
407 %
408 % o number_aliases: This integer returns the number of magics in the
409 % list.
410 %
411 % o exception: return any errors or warnings in this structure.
412 %
413 */
414
415 #if defined(__cplusplus) || defined(c_plusplus)
416 extern "C" {
417 #endif
418
MimeInfoCompare(const void * x,const void * y)419 static int MimeInfoCompare(const void *x,const void *y)
420 {
421 const MimeInfo
422 **p,
423 **q;
424
425 p=(const MimeInfo **) x,
426 q=(const MimeInfo **) y;
427 if (strcasecmp((*p)->path,(*q)->path) == 0)
428 return(strcasecmp((*p)->type,(*q)->type));
429 return(strcasecmp((*p)->path,(*q)->path));
430 }
431
432 #if defined(__cplusplus) || defined(c_plusplus)
433 }
434 #endif
435
GetMimeInfoList(const char * pattern,size_t * number_aliases,ExceptionInfo * exception)436 MagickExport const MimeInfo **GetMimeInfoList(const char *pattern,
437 size_t *number_aliases,ExceptionInfo *exception)
438 {
439 const MimeInfo
440 **aliases;
441
442 const MimeInfo
443 *p;
444
445 ssize_t
446 i;
447
448 /*
449 Allocate mime list.
450 */
451 assert(pattern != (char *) NULL);
452 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
453 assert(number_aliases != (size_t *) NULL);
454 *number_aliases=0;
455 p=GetMimeInfo((char *) NULL,(unsigned char *) "*",0,exception);
456 if (p == (const MimeInfo *) NULL)
457 return((const MimeInfo **) NULL);
458 aliases=(const MimeInfo **) AcquireQuantumMemory((size_t)
459 GetNumberOfElementsInLinkedList(mime_cache)+1UL,sizeof(*aliases));
460 if (aliases == (const MimeInfo **) NULL)
461 return((const MimeInfo **) NULL);
462 /*
463 Generate mime list.
464 */
465 LockSemaphoreInfo(mime_semaphore);
466 ResetLinkedListIterator(mime_cache);
467 p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
468 for (i=0; p != (const MimeInfo *) NULL; )
469 {
470 if ((p->stealth == MagickFalse) &&
471 (GlobExpression(p->type,pattern,MagickFalse) != MagickFalse))
472 aliases[i++]=p;
473 p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
474 }
475 UnlockSemaphoreInfo(mime_semaphore);
476 qsort((void *) aliases,(size_t) i,sizeof(*aliases),MimeInfoCompare);
477 aliases[i]=(MimeInfo *) NULL;
478 *number_aliases=(size_t) i;
479 return(aliases);
480 }
481
482 /*
483 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
484 % %
485 % %
486 % %
487 % G e t M i m e L i s t %
488 % %
489 % %
490 % %
491 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
492 %
493 % GetMimeList() returns any image format alias that matches the specified
494 % pattern.
495 %
496 % The format of the GetMimeList function is:
497 %
498 % char **GetMimeList(const char *pattern,size_t *number_aliases,
499 % ExceptionInfo *exception)
500 %
501 % A description of each parameter follows:
502 %
503 % o pattern: Specifies a pointer to a text string containing a pattern.
504 %
505 % o number_aliases: This integer returns the number of image format aliases
506 % in the list.
507 %
508 % o exception: return any errors or warnings in this structure.
509 %
510 */
511
512 #if defined(__cplusplus) || defined(c_plusplus)
513 extern "C" {
514 #endif
515
MimeCompare(const void * x,const void * y)516 static int MimeCompare(const void *x,const void *y)
517 {
518 char
519 *p,
520 *q;
521
522 p=(char *) x;
523 q=(char *) y;
524 return(strcasecmp(p,q));
525 }
526
527 #if defined(__cplusplus) || defined(c_plusplus)
528 }
529 #endif
530
GetMimeList(const char * pattern,size_t * number_aliases,ExceptionInfo * exception)531 MagickExport char **GetMimeList(const char *pattern,
532 size_t *number_aliases,ExceptionInfo *exception)
533 {
534 char
535 **aliases;
536
537 const MimeInfo
538 *p;
539
540 ssize_t
541 i;
542
543 /*
544 Allocate configure list.
545 */
546 assert(pattern != (char *) NULL);
547 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
548 assert(number_aliases != (size_t *) NULL);
549 *number_aliases=0;
550 p=GetMimeInfo((char *) NULL,(unsigned char *) "*",0,exception);
551 if (p == (const MimeInfo *) NULL)
552 return((char **) NULL);
553 aliases=(char **) AcquireQuantumMemory((size_t)
554 GetNumberOfElementsInLinkedList(mime_cache)+1UL,sizeof(*aliases));
555 if (aliases == (char **) NULL)
556 return((char **) NULL);
557 LockSemaphoreInfo(mime_semaphore);
558 ResetLinkedListIterator(mime_cache);
559 p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
560 for (i=0; p != (const MimeInfo *) NULL; )
561 {
562 if ((p->stealth == MagickFalse) &&
563 (GlobExpression(p->type,pattern,MagickFalse) != MagickFalse))
564 aliases[i++]=ConstantString(p->type);
565 p=(const MimeInfo *) GetNextValueInLinkedList(mime_cache);
566 }
567 UnlockSemaphoreInfo(mime_semaphore);
568 qsort((void *) aliases,(size_t) i,sizeof(*aliases),MimeCompare);
569 aliases[i]=(char *) NULL;
570 *number_aliases=(size_t) i;
571 return(aliases);
572 }
573
574 /*
575 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
576 % %
577 % %
578 % %
579 % G e t M i m e D e s c r i p t i o n %
580 % %
581 % %
582 % %
583 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
584 %
585 % GetMimeDescription() returns the mime type description.
586 %
587 % The format of the GetMimeDescription method is:
588 %
589 % const char *GetMimeDescription(const MimeInfo *mime_info)
590 %
591 % A description of each parameter follows:
592 %
593 % o mime_info: The magic info.
594 %
595 */
GetMimeDescription(const MimeInfo * mime_info)596 MagickExport const char *GetMimeDescription(const MimeInfo *mime_info)
597 {
598 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
599 assert(mime_info != (MimeInfo *) NULL);
600 assert(mime_info->signature == MagickCoreSignature);
601 return(mime_info->description);
602 }
603
604 /*
605 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
606 % %
607 % %
608 % %
609 % G e t M i m e T y p e %
610 % %
611 % %
612 % %
613 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
614 %
615 % GetMimeType() returns the mime type.
616 %
617 % The format of the GetMimeType method is:
618 %
619 % const char *GetMimeType(const MimeInfo *mime_info)
620 %
621 % A description of each parameter follows:
622 %
623 % o mime_info: The magic info.
624 %
625 */
GetMimeType(const MimeInfo * mime_info)626 MagickExport const char *GetMimeType(const MimeInfo *mime_info)
627 {
628 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
629 assert(mime_info != (MimeInfo *) NULL);
630 assert(mime_info->signature == MagickCoreSignature);
631 return(mime_info->type);
632 }
633
634 /*
635 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
636 % %
637 % %
638 % %
639 + I s M i m e C a c h e I n s t a n t i a t e d %
640 % %
641 % %
642 % %
643 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
644 %
645 % IsMimeCacheInstantiated() determines if the mime list is instantiated. If
646 % not, it instantiates the list and returns it.
647 %
648 % The format of the IsMimeInstantiated method is:
649 %
650 % MagickBooleanType IsMimeCacheInstantiated(ExceptionInfo *exception)
651 %
652 % A description of each parameter follows.
653 %
654 % o exception: return any errors or warnings in this structure.
655 %
656 */
IsMimeCacheInstantiated(ExceptionInfo * exception)657 static MagickBooleanType IsMimeCacheInstantiated(ExceptionInfo *exception)
658 {
659 if (mime_cache == (LinkedListInfo *) NULL)
660 {
661 if (mime_semaphore == (SemaphoreInfo *) NULL)
662 ActivateSemaphoreInfo(&mime_semaphore);
663 LockSemaphoreInfo(mime_semaphore);
664 if (mime_cache == (LinkedListInfo *) NULL)
665 mime_cache=AcquireMimeCache(MimeFilename,exception);
666 UnlockSemaphoreInfo(mime_semaphore);
667 }
668 return(mime_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
669 }
670
671 /*
672 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
673 % %
674 % %
675 % %
676 % L i s t M i m e I n f o %
677 % %
678 % %
679 % %
680 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
681 %
682 % ListMimeInfo() lists the magic info to a file.
683 %
684 % The format of the ListMimeInfo method is:
685 %
686 % MagickBooleanType ListMimeInfo(FILE *file,ExceptionInfo *exception)
687 %
688 % A description of each parameter follows.
689 %
690 % o file: An pointer to a FILE.
691 %
692 % o exception: return any errors or warnings in this structure.
693 %
694 */
ListMimeInfo(FILE * file,ExceptionInfo * exception)695 MagickExport MagickBooleanType ListMimeInfo(FILE *file,ExceptionInfo *exception)
696 {
697 const char
698 *path;
699
700 const MimeInfo
701 **mime_info;
702
703 ssize_t
704 i;
705
706 size_t
707 number_aliases;
708
709 ssize_t
710 j;
711
712 if (file == (const FILE *) NULL)
713 file=stdout;
714 mime_info=GetMimeInfoList("*",&number_aliases,exception);
715 if (mime_info == (const MimeInfo **) NULL)
716 return(MagickFalse);
717 j=0;
718 path=(const char *) NULL;
719 for (i=0; i < (ssize_t) number_aliases; i++)
720 {
721 if (mime_info[i]->stealth != MagickFalse)
722 continue;
723 if ((path == (const char *) NULL) ||
724 (strcasecmp(path,mime_info[i]->path) != 0))
725 {
726 if (mime_info[i]->path != (char *) NULL)
727 (void) FormatLocaleFile(file,"\nPath: %s\n\n",mime_info[i]->path);
728 (void) FormatLocaleFile(file,"Type Description\n");
729 (void) FormatLocaleFile(file,
730 "-------------------------------------------------"
731 "------------------------------\n");
732 }
733 path=mime_info[i]->path;
734 (void) FormatLocaleFile(file,"%s",mime_info[i]->type);
735 if (strlen(mime_info[i]->type) <= 25)
736 {
737 for (j=(ssize_t) strlen(mime_info[i]->type); j <= 27; j++)
738 (void) FormatLocaleFile(file," ");
739 }
740 else
741 {
742 (void) FormatLocaleFile(file,"\n");
743 for (j=0; j <= 27; j++)
744 (void) FormatLocaleFile(file," ");
745 }
746 if (mime_info[i]->description != (char *) NULL)
747 (void) FormatLocaleFile(file,"%s",mime_info[i]->description);
748 (void) FormatLocaleFile(file,"\n");
749 }
750 (void) fflush(file);
751 mime_info=(const MimeInfo **) RelinquishMagickMemory((void *) mime_info);
752 return(MagickTrue);
753 }
754
755 #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
756 /*
757 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
758 % %
759 % %
760 % %
761 + L o a d M i m e C a c h e %
762 % %
763 % %
764 % %
765 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
766 %
767 % LoadMimeCache() loads the mime configurations which provides a mapping
768 % between mime attributes and a mime name.
769 %
770 % The format of the LoadMimeCache method is:
771 %
772 % MagickBooleanType LoadMimeCache(LinkedListInfo *cache,const char *xml,
773 % const char *filename,const size_t depth,ExceptionInfo *exception)
774 %
775 % A description of each parameter follows:
776 %
777 % o xml: The mime list in XML format.
778 %
779 % o filename: The mime list filename.
780 %
781 % o depth: depth of <include /> statements.
782 %
783 % o exception: return any errors or warnings in this structure.
784 %
785 */
LoadMimeCache(LinkedListInfo * cache,const char * xml,const char * filename,const size_t depth,ExceptionInfo * exception)786 static MagickBooleanType LoadMimeCache(LinkedListInfo *cache,const char *xml,
787 const char *filename,const size_t depth,ExceptionInfo *exception)
788 {
789 const char
790 *attribute;
791
792 MimeInfo
793 *mime_info = (MimeInfo *) NULL;
794
795 MagickStatusType
796 status;
797
798 XMLTreeInfo
799 *mime,
800 *mime_map,
801 *include;
802
803 /*
804 Load the mime map file.
805 */
806 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
807 "Loading mime map \"%s\" ...",filename);
808 if (xml == (const char *) NULL)
809 return(MagickFalse);
810 mime_map=NewXMLTree(xml,exception);
811 if (mime_map == (XMLTreeInfo *) NULL)
812 return(MagickFalse);
813 status=MagickTrue;
814 include=GetXMLTreeChild(mime_map,"include");
815 while (include != (XMLTreeInfo *) NULL)
816 {
817 /*
818 Process include element.
819 */
820 attribute=GetXMLTreeAttribute(include,"file");
821 if (attribute != (const char *) NULL)
822 {
823 if (depth > MagickMaxRecursionDepth)
824 (void) ThrowMagickException(exception,GetMagickModule(),
825 ConfigureError,"IncludeElementNestedTooDeeply","`%s'",filename);
826 else
827 {
828 char
829 path[MagickPathExtent],
830 *file_xml;
831
832 GetPathComponent(filename,HeadPath,path);
833 if (*path != '\0')
834 (void) ConcatenateMagickString(path,DirectorySeparator,
835 MagickPathExtent);
836 if (*attribute == *DirectorySeparator)
837 (void) CopyMagickString(path,attribute,MagickPathExtent);
838 else
839 (void) ConcatenateMagickString(path,attribute,MagickPathExtent);
840 file_xml=FileToXML(path,~0UL);
841 if (file_xml != (char *) NULL)
842 {
843 status&=LoadMimeCache(cache,file_xml,path,depth+1,exception);
844 file_xml=DestroyString(file_xml);
845 }
846 }
847 }
848 include=GetNextXMLTreeTag(include);
849 }
850 mime=GetXMLTreeChild(mime_map,"mime");
851 while (mime != (XMLTreeInfo *) NULL)
852 {
853 /*
854 Process mime element.
855 */
856 mime_info=(MimeInfo *) AcquireCriticalMemory(sizeof(*mime_info));
857 (void) memset(mime_info,0,sizeof(*mime_info));
858 mime_info->path=ConstantString(filename);
859 mime_info->signature=MagickCoreSignature;
860 attribute=GetXMLTreeAttribute(mime,"data-type");
861 if (attribute != (const char *) NULL)
862 mime_info->data_type=(DataType) ParseCommandOption(MagickDataTypeOptions,
863 MagickTrue,attribute);
864 attribute=GetXMLTreeAttribute(mime,"description");
865 if (attribute != (const char *) NULL)
866 mime_info->description=ConstantString(attribute);
867 attribute=GetXMLTreeAttribute(mime,"endian");
868 if (attribute != (const char *) NULL)
869 mime_info->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
870 MagickTrue,attribute);
871 attribute=GetXMLTreeAttribute(mime,"magic");
872 if (attribute != (const char *) NULL)
873 {
874 char
875 *token;
876
877 const char
878 *p;
879
880 unsigned char
881 *q;
882
883 token=AcquireString(attribute);
884 (void) SubstituteString((char **) &token,"<","<");
885 (void) SubstituteString((char **) &token,"&","&");
886 (void) SubstituteString((char **) &token,""","\"");
887 mime_info->magic=(unsigned char *) AcquireString(token);
888 q=mime_info->magic;
889 for (p=token; *p != '\0'; )
890 {
891 if (*p == '\\')
892 {
893 p++;
894 if (isdigit((int) ((unsigned char) *p)) != 0)
895 {
896 char
897 *end;
898
899 *q++=(unsigned char) strtol(p,&end,8);
900 p+=(end-p);
901 mime_info->length++;
902 continue;
903 }
904 switch (*p)
905 {
906 case 'b': *q='\b'; break;
907 case 'f': *q='\f'; break;
908 case 'n': *q='\n'; break;
909 case 'r': *q='\r'; break;
910 case 't': *q='\t'; break;
911 case 'v': *q='\v'; break;
912 case 'a': *q='a'; break;
913 case '?': *q='\?'; break;
914 default: *q=(unsigned char) (*p); break;
915 }
916 p++;
917 q++;
918 mime_info->length++;
919 continue;
920 }
921 *q++=(unsigned char) (*p++);
922 mime_info->length++;
923 }
924 token=DestroyString(token);
925 if (mime_info->data_type != StringData)
926 mime_info->value=(ssize_t) strtoul((char *) mime_info->magic,
927 (char **) NULL,0);
928 }
929 attribute=GetXMLTreeAttribute(mime,"mask");
930 if (attribute != (const char *) NULL)
931 mime_info->mask=(ssize_t) strtoul(attribute,(char **) NULL,0);
932 attribute=GetXMLTreeAttribute(mime,"offset");
933 if (attribute != (const char *) NULL)
934 {
935 char
936 *c;
937
938 mime_info->offset=(MagickOffsetType) strtol(attribute,&c,0);
939 if (*c == ':')
940 mime_info->extent=(size_t) strtol(c+1,(char **) NULL,0);
941 }
942 attribute=GetXMLTreeAttribute(mime,"pattern");
943 if (attribute != (const char *) NULL)
944 mime_info->pattern=ConstantString(attribute);
945 attribute=GetXMLTreeAttribute(mime,"priority");
946 if (attribute != (const char *) NULL)
947 mime_info->priority=(ssize_t) strtol(attribute,(char **) NULL,0);
948 attribute=GetXMLTreeAttribute(mime,"stealth");
949 if (attribute != (const char *) NULL)
950 mime_info->stealth=IsStringTrue(attribute);
951 attribute=GetXMLTreeAttribute(mime,"type");
952 if (attribute != (const char *) NULL)
953 mime_info->type=ConstantString(attribute);
954 status=AppendValueToLinkedList(cache,mime_info);
955 if (status == MagickFalse)
956 (void) ThrowMagickException(exception,GetMagickModule(),
957 ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
958 mime=GetNextXMLTreeTag(mime);
959 }
960 mime_map=DestroyXMLTree(mime_map);
961 return(status != 0 ? MagickTrue : MagickFalse);
962 }
963 #endif
964
965 /*
966 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
967 % %
968 % %
969 % %
970 + M a g i c k T o M i m e %
971 % %
972 % %
973 % %
974 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
975 %
976 % MagickToMime() returns the officially registered (or de facto) MIME
977 % media-type corresponding to a magick string. If there is no registered
978 % media-type, then the string "image/x-magick" (all lower case) is returned.
979 % The returned string must be deallocated by the user.
980 %
981 % The format of the MagickToMime method is:
982 %
983 % char *MagickToMime(const char *magick)
984 %
985 % A description of each parameter follows.
986 %
987 % o magick: ImageMagick format specification "magick" tag.
988 %
989 */
MagickToMime(const char * magick)990 MagickExport char *MagickToMime(const char *magick)
991 {
992 char
993 filename[MagickPathExtent],
994 media[MagickPathExtent];
995
996 const MimeInfo
997 *mime_info;
998
999 ExceptionInfo
1000 *exception;
1001
1002 (void) FormatLocaleString(filename,MagickPathExtent,"file.%s",magick);
1003 LocaleLower(filename);
1004 exception=AcquireExceptionInfo();
1005 mime_info=GetMimeInfo(filename,(unsigned char *) " ",1,exception);
1006 exception=DestroyExceptionInfo(exception);
1007 if (mime_info != (const MimeInfo *) NULL)
1008 return(ConstantString(GetMimeType(mime_info)));
1009 (void) FormatLocaleString(media,MagickPathExtent,"image/x-%s",magick);
1010 LocaleLower(media+8);
1011 return(ConstantString(media));
1012 }
1013
1014 /*
1015 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1016 % %
1017 % %
1018 % %
1019 + M i m e C o m p o n e n t G e n e s i s %
1020 % %
1021 % %
1022 % %
1023 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1024 %
1025 % MimeComponentGenesis() instantiates the mime component.
1026 %
1027 % The format of the MimeComponentGenesis method is:
1028 %
1029 % MagickBooleanType MimeComponentGenesis(void)
1030 %
1031 */
MimeComponentGenesis(void)1032 MagickPrivate MagickBooleanType MimeComponentGenesis(void)
1033 {
1034 if (mime_semaphore == (SemaphoreInfo *) NULL)
1035 mime_semaphore=AcquireSemaphoreInfo();
1036 return(MagickTrue);
1037 }
1038
1039 /*
1040 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1041 % %
1042 % %
1043 % %
1044 + M i m e C o m p o n e n t T e r m i n u s %
1045 % %
1046 % %
1047 % %
1048 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1049 %
1050 % MimeComponentTerminus() destroys the mime component.
1051 %
1052 % The format of the MimeComponentTerminus method is:
1053 %
1054 % MimeComponentTerminus(void)
1055 %
1056 */
1057
DestroyMimeElement(void * mime_info)1058 static void *DestroyMimeElement(void *mime_info)
1059 {
1060 MimeInfo
1061 *p;
1062
1063 p=(MimeInfo *) mime_info;
1064 if (p->magic != (unsigned char *) NULL)
1065 p->magic=(unsigned char *) RelinquishMagickMemory(p->magic);
1066 if (p->pattern != (char *) NULL)
1067 p->pattern=DestroyString(p->pattern);
1068 if (p->description != (char *) NULL)
1069 p->description=DestroyString(p->description);
1070 if (p->type != (char *) NULL)
1071 p->type=DestroyString(p->type);
1072 if (p->path != (char *) NULL)
1073 p->path=DestroyString(p->path);
1074 p=(MimeInfo *) RelinquishMagickMemory(p);
1075 return((void *) NULL);
1076 }
1077
MimeComponentTerminus(void)1078 MagickPrivate void MimeComponentTerminus(void)
1079 {
1080 if (mime_semaphore == (SemaphoreInfo *) NULL)
1081 ActivateSemaphoreInfo(&mime_semaphore);
1082 LockSemaphoreInfo(mime_semaphore);
1083 if (mime_cache != (LinkedListInfo *) NULL)
1084 mime_cache=DestroyLinkedList(mime_cache,DestroyMimeElement);
1085 UnlockSemaphoreInfo(mime_semaphore);
1086 RelinquishSemaphoreInfo(&mime_semaphore);
1087 }
1088