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