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