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