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