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