MagickCore  6.9.13-21
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/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  (void) SubstituteString((char **) &token,"&apos;","'");
908  mime_info->magic=(unsigned char *) AcquireString(token);
909  q=mime_info->magic;
910  for (p=token; *p != '\0'; )
911  {
912  if (*p == '\\')
913  {
914  p++;
915  if (isdigit((int) ((unsigned char) *p)) != 0)
916  {
917  char
918  *end;
919 
920  *q++=(unsigned char) strtol(p,&end,8);
921  p+=(ptrdiff_t) (end-p);
922  mime_info->length++;
923  continue;
924  }
925  switch (*p)
926  {
927  case 'b': *q='\b'; break;
928  case 'f': *q='\f'; break;
929  case 'n': *q='\n'; break;
930  case 'r': *q='\r'; break;
931  case 't': *q='\t'; break;
932  case 'v': *q='\v'; break;
933  case 'a': *q='a'; break;
934  case '?': *q='\?'; break;
935  default: *q=(unsigned char) (*p); break;
936  }
937  p++;
938  q++;
939  mime_info->length++;
940  continue;
941  }
942  *q++=(unsigned char) (*p++);
943  mime_info->length++;
944  }
945  token=DestroyString(token);
946  if (mime_info->data_type != StringData)
947  mime_info->value=(ssize_t) strtoul((char *) mime_info->magic,
948  (char **) NULL,0);
949  }
950  attribute=GetXMLTreeAttribute(mime,"mask");
951  if (attribute != (const char *) NULL)
952  mime_info->mask=(ssize_t) strtoul(attribute,(char **) NULL,0);
953  attribute=GetXMLTreeAttribute(mime,"offset");
954  if (attribute != (const char *) NULL)
955  {
956  char
957  *c;
958 
959  mime_info->offset=(MagickOffsetType) strtol(attribute,&c,0);
960  if (*c == ':')
961  mime_info->extent=(size_t) strtol(c+1,(char **) NULL,0);
962  }
963  attribute=GetXMLTreeAttribute(mime,"pattern");
964  if (attribute != (const char *) NULL)
965  mime_info->pattern=ConstantString(attribute);
966  attribute=GetXMLTreeAttribute(mime,"priority");
967  if (attribute != (const char *) NULL)
968  mime_info->priority=(ssize_t) strtol(attribute,(char **) NULL,0);
969  attribute=GetXMLTreeAttribute(mime,"stealth");
970  if (attribute != (const char *) NULL)
971  mime_info->stealth=IsMagickTrue(attribute);
972  attribute=GetXMLTreeAttribute(mime,"type");
973  if (attribute != (const char *) NULL)
974  mime_info->type=ConstantString(attribute);
975  status=AppendValueToLinkedList(cache,mime_info);
976  if (status == MagickFalse)
977  (void) ThrowMagickException(exception,GetMagickModule(),
978  ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
979  mime=GetNextXMLTreeTag(mime);
980  }
981  mime_map=DestroyXMLTree(mime_map);
982  return(status != 0 ? MagickTrue : MagickFalse);
983 }
984 ␌
985 /*
986 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
987 % %
988 % %
989 % %
990 + M a g i c k T o M i m e %
991 % %
992 % %
993 % %
994 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
995 %
996 % MagickToMime() returns the officially registered (or de facto) MIME
997 % media-type corresponding to a magick string. If there is no registered
998 % media-type, then the string "image/x-magick" (all lower case) is returned.
999 % The returned string must be deallocated by the user.
1000 %
1001 % The format of the MagickToMime method is:
1002 %
1003 % char *MagickToMime(const char *magick)
1004 %
1005 % A description of each parameter follows.
1006 %
1007 % o magick: ImageMagick format specification "magick" tag.
1008 %
1009 */
1010 MagickExport char *MagickToMime(const char *magick)
1011 {
1012  char
1013  filename[MaxTextExtent],
1014  media[MaxTextExtent];
1015 
1016  const MimeInfo
1017  *mime_info;
1018 
1020  *exception;
1021 
1022  (void) FormatLocaleString(filename,MaxTextExtent,"file.%s",magick);
1023  LocaleLower(filename);
1024  exception=AcquireExceptionInfo();
1025  mime_info=GetMimeInfo(filename,(unsigned char *) " ",1,exception);
1026  exception=DestroyExceptionInfo(exception);
1027  if (mime_info != (const MimeInfo *) NULL)
1028  return(ConstantString(GetMimeType(mime_info)));
1029  (void) FormatLocaleString(media,MaxTextExtent,"image/x-%s",magick);
1030  LocaleLower(media+8);
1031  return(ConstantString(media));
1032 }
1033 ␌
1034 /*
1035 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1036 % %
1037 % %
1038 % %
1039 + M i m e C o m p o n e n t G e n e s i s %
1040 % %
1041 % %
1042 % %
1043 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1044 %
1045 % MimeComponentGenesis() instantiates the mime component.
1046 %
1047 % The format of the MimeComponentGenesis method is:
1048 %
1049 % MagickBooleanType MimeComponentGenesis(void)
1050 %
1051 */
1052 MagickExport MagickBooleanType MimeComponentGenesis(void)
1053 {
1054  if (mime_semaphore == (SemaphoreInfo *) NULL)
1055  mime_semaphore=AllocateSemaphoreInfo();
1056  return(MagickTrue);
1057 }
1058 ␌
1059 /*
1060 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1061 % %
1062 % %
1063 % %
1064 + M i m e C o m p o n e n t T e r m i n u s %
1065 % %
1066 % %
1067 % %
1068 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1069 %
1070 % MimeComponentTerminus() destroys the mime component.
1071 %
1072 % The format of the MimeComponentTerminus method is:
1073 %
1074 % MimeComponentTerminus(void)
1075 %
1076 */
1077 
1078 static void *DestroyMimeElement(void *mime_info)
1079 {
1080  MimeInfo
1081  *p;
1082 
1083  p=(MimeInfo *) mime_info;
1084  if (p->magic != (unsigned char *) NULL)
1085  p->magic=(unsigned char *) RelinquishMagickMemory(p->magic);
1086  if (p->pattern != (char *) NULL)
1087  p->pattern=DestroyString(p->pattern);
1088  if (p->description != (char *) NULL)
1089  p->description=DestroyString(p->description);
1090  if (p->type != (char *) NULL)
1091  p->type=DestroyString(p->type);
1092  if (p->path != (char *) NULL)
1093  p->path=DestroyString(p->path);
1094  p=(MimeInfo *) RelinquishMagickMemory(p);
1095  return((void *) NULL);
1096 }
1097 
1098 MagickExport void MimeComponentTerminus(void)
1099 {
1100  if (mime_semaphore == (SemaphoreInfo *) NULL)
1101  ActivateSemaphoreInfo(&mime_semaphore);
1102  LockSemaphoreInfo(mime_semaphore);
1103  if (mime_cache != (LinkedListInfo *) NULL)
1104  mime_cache=DestroyLinkedList(mime_cache,DestroyMimeElement);
1105  UnlockSemaphoreInfo(mime_semaphore);
1106  DestroySemaphoreInfo(&mime_semaphore);
1107 }
Definition: mime.c:69