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