MagickCore  7.1.2-29
Convert, Edit, Or Compose Bitmap Images
mime.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % M M IIIII M M EEEEE %
6 % MM MM I MM MM E %
7 % M M M I M M M EEE %
8 % M M I M M E %
9 % M M IIIII M M EEEEE %
10 % %
11 % %
12 % MagickCore Mime Methods %
13 % %
14 % Software Design %
15 % July 2000 %
16 % %
17 % %
18 % Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization %
19 % dedicated to making software imaging solutions freely available. %
20 % %
21 % You may not use this file except in compliance with the License. You may %
22 % obtain a copy of the License at %
23 % %
24 % https://imagemagick.org/license/ %
25 % %
26 % Unless required by applicable law or agreed to in writing, software %
27 % distributed under the License is distributed on an "AS IS" BASIS, %
28 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
29 % See the License for the specific language governing permissions and %
30 % limitations under the License. %
31 % %
32 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
33 %
34 %
35 */
36 ␌
37 /*
38  Include declarations.
39 */
40 #include "MagickCore/studio.h"
41 #include "MagickCore/blob.h"
42 #include "MagickCore/client.h"
43 #include "MagickCore/configure.h"
44 #include "MagickCore/configure-private.h"
45 #include "MagickCore/exception.h"
46 #include "MagickCore/exception-private.h"
47 #include "MagickCore/linked-list.h"
48 #include "MagickCore/linked-list-private.h"
49 #include "MagickCore/memory_.h"
50 #include "MagickCore/mime.h"
51 #include "MagickCore/mime-private.h"
52 #include "MagickCore/option.h"
53 #include "MagickCore/semaphore.h"
54 #include "MagickCore/string_.h"
55 #include "MagickCore/token.h"
56 #include "MagickCore/utility.h"
57 #include "MagickCore/utility-private.h"
58 #include "MagickCore/quantum-private.h"
59 #include "MagickCore/xml-tree.h"
60 #include "MagickCore/xml-tree-private.h"
61 ␌
62 /*
63  Define declarations.
64 */
65 #define MimeFilename "mime.xml"
66 
67 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
68 # if !defined(strcasecmp)
69 # define strcasecmp _stricmp
70 # endif
71 #endif
72 ␌
73 /*
74  Typedef declaration.
75 */
76 struct _MimeInfo
77 {
78  char
79  *path,
80  *type,
81  *description,
82  *pattern;
83 
84  ssize_t
85  priority;
86 
87  MagickOffsetType
88  offset;
89 
90  size_t
91  extent;
92 
93  DataType
94  data_type;
95 
96  ssize_t
97  mask,
98  value;
99 
100  EndianType
101  endian;
102 
103  size_t
104  length;
105 
106  unsigned char
107  *magic;
108 
109  MagickBooleanType
110  stealth;
111 
112  size_t
113  signature;
114 };
115 ␌
116 /*
117  Static declarations.
118 */
119 static LinkedListInfo
120  *mime_cache = (LinkedListInfo *) NULL;
121 
122 static SemaphoreInfo
123  *mime_semaphore = (SemaphoreInfo *) NULL;
124 ␌
125 /*
126  Forward declarations.
127 */
128 static MagickBooleanType
129  IsMimeCacheInstantiated(ExceptionInfo *);
130 
131 #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
132 static MagickBooleanType
133  LoadMimeCache(LinkedListInfo *,const char *,const char *,const size_t,
134  ExceptionInfo *);
135 #endif
136 ␌
137 /*
138 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
139 % %
140 % %
141 % %
142 % A c q u i r e M i m e C a c h e %
143 % %
144 % %
145 % %
146 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
147 %
148 % AcquireMimeCache() caches one or more magic configurations which provides
149 % a mapping between magic attributes and a magic name.
150 %
151 % The format of the AcquireMimeCache method is:
152 %
153 % LinkedListInfo *AcquireMimeCache(const char *filename,
154 % ExceptionInfo *exception)
155 %
156 % A description of each parameter follows:
157 %
158 % o filename: the font file name.
159 %
160 % o exception: return any errors or warnings in this structure.
161 %
162 */
163 MagickExport LinkedListInfo *AcquireMimeCache(const char *filename,
164  ExceptionInfo *exception)
165 {
167  *cache;
168 
169  cache=NewLinkedList(0);
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  (void) LoadMimeCache(cache,(const char *)
183  GetStringInfoDatum(option),GetStringInfoPath(option),0,exception);
184  option=(const StringInfo *) GetNextValueInLinkedList(options);
185  }
186  options=DestroyConfigureOptions(options);
187  }
188 #else
189  magick_unreferenced(filename);
190  magick_unreferenced(exception);
191 #endif
192  return(cache);
193 }
194 ␌
195 /*
196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
197 % %
198 % %
199 % %
200 + G e t M i m e I n f o %
201 % %
202 % %
203 % %
204 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
205 %
206 % GetMimeInfo() attempts to classify the content to identify which mime type
207 % is associated with the content, if any.
208 %
209 % The format of the GetMimeInfo method is:
210 %
211 % const MimeInfo *GetMimeInfo(const char *filename,
212 % const unsigned char *magic,const size_t length,
213 % ExceptionInfo *exception)
214 %
215 % A description of each parameter follows:
216 %
217 % o filename: If we cannot not classify the string, we attempt to classify
218 % based on the filename (e.g. *.pdf returns application/pdf).
219 %
220 % o magic: A binary string generally representing the first few characters
221 % of the image file or blob.
222 %
223 % o length: the length of the binary signature.
224 %
225 % o exception: return any errors or warnings in this structure.
226 %
227 */
228 MagickExport const MimeInfo *GetMimeInfo(const char *filename,
229  const unsigned char *magic,const size_t length,ExceptionInfo *exception)
230 {
232  *element_info,
233  *p;
234 
235  EndianType
236  endian;
237 
238  const unsigned char
239  *r;
240 
241  ssize_t
242  i;
243 
244  ssize_t
245  value;
246 
247  assert(exception != (ExceptionInfo *) NULL);
248  if (IsMimeCacheInstantiated(exception) == MagickFalse)
249  return((const MimeInfo *) NULL);
250  /*
251  Search for mime tag.
252  */
253  LockSemaphoreInfo(mime_semaphore);
254  p=GetHeadElementInLinkedList(mime_cache);
255  if ((magic == (const unsigned char *) NULL) || (length == 0))
256  {
257  UnlockSemaphoreInfo(mime_semaphore);
258  if (p != (ElementInfo *) NULL)
259  return((const MimeInfo *) p->value);
260  return((const MimeInfo *) NULL);
261  }
262  element_info=(ElementInfo *) NULL;
263  while (p != (ElementInfo *) NULL)
264  {
265  const MimeInfo
266  *q;
267 
268  q=(const MimeInfo *) p->value;
269  assert(q->offset >= 0);
270  if (element_info != (const ElementInfo *) NULL)
271  if (q->priority > ((const MimeInfo *) element_info->value)->priority)
272  {
273  p=p->next;
274  continue;
275  }
276  if ((q->pattern != (char *) NULL) && (filename != (char *) NULL))
277  {
278  if (GlobExpression(filename,q->pattern,MagickFalse) != MagickFalse)
279  element_info=p;
280  p=p->next;
281  continue;
282  }
283  switch (q->data_type)
284  {
285  case ByteData:
286  {
287  if ((size_t) (q->offset+4) > length)
288  break;
289  r=magic+q->offset;
290  value=(ssize_t) (*r++);
291  if (q->mask == 0)
292  {
293  if (q->value == value)
294  element_info=p;
295  }
296  else
297  {
298  if ((q->value & q->mask) == value)
299  element_info=p;
300  }
301  break;
302  }
303  case ShortData:
304  {
305  if ((size_t) (q->offset+4) > length)
306  break;
307  r=magic+q->offset;
308  endian=q->endian;
309  if (q->endian == UndefinedEndian)
310  endian=GetHostEndian();
311  if (endian == LSBEndian)
312  {
313  value=(ssize_t) (*r++);
314  value|=(*r++) << 8;
315  }
316  else
317  {
318  value=(ssize_t) (*r++) << 8;
319  value|=(*r++);
320  }
321  if (q->mask == 0)
322  {
323  if (q->value == value)
324  element_info=p;
325  }
326  else
327  {
328  if ((q->value & q->mask) == value)
329  element_info=p;
330  }
331  break;
332  }
333  case LongData:
334  {
335  if ((size_t) (q->offset+4) > length)
336  break;
337  r=magic+q->offset;
338  endian=q->endian;
339  if (q->endian == UndefinedEndian)
340  endian=GetHostEndian();
341  if (endian == LSBEndian)
342  {
343  value=(ssize_t) (*r++);
344  value|=((ssize_t) *r++) << 8;
345  value|=((ssize_t) *r++) << 16;
346  value|=((ssize_t) *r++) << 24;
347  }
348  else
349  {
350  value=(ssize_t) (*r++) << 24;
351  value|=((ssize_t) *r++) << 16;
352  value|=((ssize_t) *r++) << 8;
353  value|=((ssize_t) *r++);
354  }
355  if (q->mask == 0)
356  {
357  if (q->value == value)
358  element_info=p;
359  }
360  else
361  {
362  if ((q->value & q->mask) == value)
363  element_info=p;
364  }
365  break;
366  }
367  case StringData:
368  default:
369  {
370  for (i=0; i <= (ssize_t) q->extent; i++)
371  {
372  if ((size_t) (q->offset+i+(ssize_t) q->length) > length)
373  break;
374  if (memcmp(magic+q->offset+i,q->magic,q->length) == 0)
375  {
376  element_info=p;
377  break;
378  }
379  }
380  break;
381  }
382  }
383  p=p->next;
384  }
385  if (element_info != (ElementInfo *) NULL)
386  SetHeadElementInLinkedList(mime_cache,element_info);
387  UnlockSemaphoreInfo(mime_semaphore);
388  if (element_info == (ElementInfo *) NULL)
389  return((const MimeInfo *) NULL);
390  return((const MimeInfo *) element_info->value);
391 }
392 ␌
393 /*
394 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
395 % %
396 % %
397 % %
398 % G e t M i m e I n f o L i s t %
399 % %
400 % %
401 % %
402 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
403 %
404 % GetMimeInfoList() returns any image aliases that match the specified
405 % pattern.
406 %
407 % The magic of the GetMimeInfoList function is:
408 %
409 % const MimeInfo **GetMimeInfoList(const char *pattern,
410 % size_t *number_aliases,ExceptionInfo *exception)
411 %
412 % A description of each parameter follows:
413 %
414 % o pattern: Specifies a pointer to a text string containing a pattern.
415 %
416 % o number_aliases: This integer returns the number of magics in the
417 % list.
418 %
419 % o exception: return any errors or warnings in this structure.
420 %
421 */
422 
423 #if defined(__cplusplus) || defined(c_plusplus)
424 extern "C" {
425 #endif
426 
427 static int MimeInfoCompare(const void *x,const void *y)
428 {
429  const MimeInfo
430  **p,
431  **q;
432 
433  p=(const MimeInfo **) x,
434  q=(const MimeInfo **) y;
435  if (strcasecmp((*p)->path,(*q)->path) == 0)
436  return(strcasecmp((*p)->type,(*q)->type));
437  return(strcasecmp((*p)->path,(*q)->path));
438 }
439 
440 #if defined(__cplusplus) || defined(c_plusplus)
441 }
442 #endif
443 
444 MagickExport const MimeInfo **GetMimeInfoList(const char *pattern,
445  size_t *number_aliases,ExceptionInfo *exception)
446 {
447  const MimeInfo
448  **aliases;
449 
451  *p;
452 
453  ssize_t
454  i;
455 
456  assert(pattern != (char *) NULL);
457  assert(number_aliases != (size_t *) NULL);
458  if (IsEventLogging() != MagickFalse)
459  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
460  *number_aliases=0;
461  if (IsMimeCacheInstantiated(exception) == MagickFalse)
462  return((const MimeInfo **) NULL);
463  aliases=(const MimeInfo **) AcquireQuantumMemory((size_t)
464  GetNumberOfElementsInLinkedList(mime_cache)+1UL,sizeof(*aliases));
465  if (aliases == (const MimeInfo **) NULL)
466  return((const MimeInfo **) NULL);
467  LockSemaphoreInfo(mime_semaphore);
468  p=GetHeadElementInLinkedList(mime_cache);
469  for (i=0; p != (ElementInfo *) NULL; )
470  {
471  MimeInfo
472  *mime_info;
473 
474  mime_info=(MimeInfo *) p->value;
475  if ((mime_info->stealth == MagickFalse) &&
476  (GlobExpression(mime_info->type,pattern,MagickFalse) != MagickFalse))
477  aliases[i++]=mime_info;
478  p=p->next;
479  }
480  UnlockSemaphoreInfo(mime_semaphore);
481  if (i == 0)
482  aliases=(const MimeInfo **) RelinquishMagickMemory((void *) aliases);
483  else
484  {
485  qsort((void *) aliases,(size_t) i,sizeof(*aliases),MimeInfoCompare);
486  aliases[i]=(MimeInfo *) NULL;
487  }
488  *number_aliases=(size_t) i;
489  return(aliases);
490 }
491 ␌
492 /*
493 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
494 % %
495 % %
496 % %
497 % G e t M i m e L i s t %
498 % %
499 % %
500 % %
501 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
502 %
503 % GetMimeList() returns any image format alias that matches the specified
504 % pattern.
505 %
506 % The format of the GetMimeList function is:
507 %
508 % char **GetMimeList(const char *pattern,size_t *number_aliases,
509 % ExceptionInfo *exception)
510 %
511 % A description of each parameter follows:
512 %
513 % o pattern: Specifies a pointer to a text string containing a pattern.
514 %
515 % o number_aliases: This integer returns the number of image format aliases
516 % in the list.
517 %
518 % o exception: return any errors or warnings in this structure.
519 %
520 */
521 
522 #if defined(__cplusplus) || defined(c_plusplus)
523 extern "C" {
524 #endif
525 
526 static int MimeCompare(const void *x,const void *y)
527 {
528  char
529  *p,
530  *q;
531 
532  p=(char *) x;
533  q=(char *) y;
534  return(strcasecmp(p,q));
535 }
536 
537 #if defined(__cplusplus) || defined(c_plusplus)
538 }
539 #endif
540 
541 MagickExport char **GetMimeList(const char *pattern,
542  size_t *number_aliases,ExceptionInfo *exception)
543 {
544  char
545  **aliases;
546 
548  *p;
549 
550  ssize_t
551  i;
552 
553  assert(pattern != (char *) NULL);
554  assert(number_aliases != (size_t *) NULL);
555  if (IsEventLogging() != MagickFalse)
556  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
557  *number_aliases=0;
558  if (IsMimeCacheInstantiated(exception) == MagickFalse)
559  return((char **) NULL);
560  aliases=(char **) AcquireQuantumMemory((size_t)
561  GetNumberOfElementsInLinkedList(mime_cache)+1UL,sizeof(*aliases));
562  if (aliases == (char **) NULL)
563  return((char **) NULL);
564  LockSemaphoreInfo(mime_semaphore);
565  p=GetHeadElementInLinkedList(mime_cache);
566  for (i=0; p != (ElementInfo *) NULL; )
567  {
568  const MimeInfo
569  *mime_info;
570 
571  mime_info=(const MimeInfo *) p->value;
572  if ((mime_info->stealth == MagickFalse) &&
573  (GlobExpression(mime_info->type,pattern,MagickFalse) != MagickFalse))
574  aliases[i++]=ConstantString(mime_info->type);
575  p=p->next;
576  }
577  UnlockSemaphoreInfo(mime_semaphore);
578  if (i == 0)
579  aliases=(char **) RelinquishMagickMemory(aliases);
580  else
581  {
582  qsort((void *) aliases,(size_t) i,sizeof(*aliases),MimeCompare);
583  aliases[i]=(char *) NULL;
584  }
585  *number_aliases=(size_t) i;
586  return(aliases);
587 }
588 ␌
589 /*
590 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
591 % %
592 % %
593 % %
594 % G e t M i m e D e s c r i p t i o n %
595 % %
596 % %
597 % %
598 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
599 %
600 % GetMimeDescription() returns the mime type description.
601 %
602 % The format of the GetMimeDescription method is:
603 %
604 % const char *GetMimeDescription(const MimeInfo *mime_info)
605 %
606 % A description of each parameter follows:
607 %
608 % o mime_info: The magic info.
609 %
610 */
611 MagickExport const char *GetMimeDescription(const MimeInfo *mime_info)
612 {
613  assert(mime_info != (MimeInfo *) NULL);
614  assert(mime_info->signature == MagickCoreSignature);
615  if (IsEventLogging() != MagickFalse)
616  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
617  return(mime_info->description);
618 }
619 ␌
620 /*
621 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
622 % %
623 % %
624 % %
625 % G e t M i m e T y p e %
626 % %
627 % %
628 % %
629 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
630 %
631 % GetMimeType() returns the mime type.
632 %
633 % The format of the GetMimeType method is:
634 %
635 % const char *GetMimeType(const MimeInfo *mime_info)
636 %
637 % A description of each parameter follows:
638 %
639 % o mime_info: The magic info.
640 %
641 */
642 MagickExport const char *GetMimeType(const MimeInfo *mime_info)
643 {
644  assert(mime_info != (MimeInfo *) NULL);
645  assert(mime_info->signature == MagickCoreSignature);
646  if (IsEventLogging() != MagickFalse)
647  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
648  return(mime_info->type);
649 }
650 ␌
651 /*
652 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
653 % %
654 % %
655 % %
656 + I s M i m e C a c h e I n s t a n t i a t e d %
657 % %
658 % %
659 % %
660 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
661 %
662 % IsMimeCacheInstantiated() determines if the mime list is instantiated. If
663 % not, it instantiates the list and returns it.
664 %
665 % The format of the IsMimeInstantiated method is:
666 %
667 % MagickBooleanType IsMimeCacheInstantiated(ExceptionInfo *exception)
668 %
669 % A description of each parameter follows.
670 %
671 % o exception: return any errors or warnings in this structure.
672 %
673 */
674 static MagickBooleanType IsMimeCacheInstantiated(ExceptionInfo *exception)
675 {
676  if (mime_cache == (LinkedListInfo *) NULL)
677  {
678  if (mime_semaphore == (SemaphoreInfo *) NULL)
679  ActivateSemaphoreInfo(&mime_semaphore);
680  LockSemaphoreInfo(mime_semaphore);
681  if (mime_cache == (LinkedListInfo *) NULL)
682  mime_cache=AcquireMimeCache(MimeFilename,exception);
683  UnlockSemaphoreInfo(mime_semaphore);
684  }
685  return(mime_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
686 }
687 ␌
688 /*
689 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
690 % %
691 % %
692 % %
693 % L i s t M i m e I n f o %
694 % %
695 % %
696 % %
697 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
698 %
699 % ListMimeInfo() lists the magic info to a file.
700 %
701 % The format of the ListMimeInfo method is:
702 %
703 % MagickBooleanType ListMimeInfo(FILE *file,ExceptionInfo *exception)
704 %
705 % A description of each parameter follows.
706 %
707 % o file: An pointer to a FILE.
708 %
709 % o exception: return any errors or warnings in this structure.
710 %
711 */
712 MagickExport MagickBooleanType ListMimeInfo(FILE *file,ExceptionInfo *exception)
713 {
714  const char
715  *path;
716 
717  const MimeInfo
718  **mime_info;
719 
720  ssize_t
721  i;
722 
723  size_t
724  number_aliases;
725 
726  ssize_t
727  j;
728 
729  if (file == (const FILE *) NULL)
730  file=stdout;
731  mime_info=GetMimeInfoList("*",&number_aliases,exception);
732  if (mime_info == (const MimeInfo **) NULL)
733  return(MagickFalse);
734  j=0;
735  path=(const char *) NULL;
736  for (i=0; i < (ssize_t) number_aliases; i++)
737  {
738  if (mime_info[i]->stealth != MagickFalse)
739  continue;
740  if ((path == (const char *) NULL) ||
741  (strcasecmp(path,mime_info[i]->path) != 0))
742  {
743  if (mime_info[i]->path != (char *) NULL)
744  (void) FormatLocaleFile(file,"\nPath: %s\n\n",mime_info[i]->path);
745  (void) FormatLocaleFile(file,"Type Description\n");
746  (void) FormatLocaleFile(file,
747  "-------------------------------------------------"
748  "------------------------------\n");
749  }
750  path=mime_info[i]->path;
751  (void) FormatLocaleFile(file,"%s",mime_info[i]->type);
752  if (strlen(mime_info[i]->type) <= 25)
753  {
754  for (j=(ssize_t) strlen(mime_info[i]->type); j <= 27; j++)
755  (void) FormatLocaleFile(file," ");
756  }
757  else
758  {
759  (void) FormatLocaleFile(file,"\n");
760  for (j=0; j <= 27; j++)
761  (void) FormatLocaleFile(file," ");
762  }
763  if (mime_info[i]->description != (char *) NULL)
764  (void) FormatLocaleFile(file,"%s",mime_info[i]->description);
765  (void) FormatLocaleFile(file,"\n");
766  }
767  (void) fflush(file);
768  mime_info=(const MimeInfo **) RelinquishMagickMemory((void *) mime_info);
769  return(MagickTrue);
770 }
771 ␌
772 #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
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[MagickPathExtent],
847  *file_xml;
848 
849  GetPathComponent(filename,HeadPath,path);
850  if (*path != '\0')
851  (void) ConcatenateMagickString(path,DirectorySeparator,
852  MagickPathExtent);
853  if (*attribute == *DirectorySeparator)
854  (void) CopyMagickString(path,attribute,MagickPathExtent);
855  else
856  (void) ConcatenateMagickString(path,attribute,MagickPathExtent);
857  file_xml=FileToXML(path,~0UL);
858  if (file_xml != (char *) NULL)
859  {
860  status&=(MagickStatusType) LoadMimeCache(cache,file_xml,path,
861  depth+1,exception);
862  file_xml=DestroyString(file_xml);
863  }
864  }
865  }
866  include=GetNextXMLTreeTag(include);
867  }
868  mime=GetXMLTreeChild(mime_map,"mime");
869  while (mime != (XMLTreeInfo *) NULL)
870  {
871  /*
872  Process mime element.
873  */
874  mime_info=(MimeInfo *) AcquireCriticalMemory(sizeof(*mime_info));
875  (void) memset(mime_info,0,sizeof(*mime_info));
876  mime_info->path=ConstantString(filename);
877  mime_info->signature=MagickCoreSignature;
878  attribute=GetXMLTreeAttribute(mime,"data-type");
879  if (attribute != (const char *) NULL)
880  mime_info->data_type=(DataType) ParseCommandOption(MagickDataTypeOptions,
881  MagickTrue,attribute);
882  attribute=GetXMLTreeAttribute(mime,"description");
883  if (attribute != (const char *) NULL)
884  mime_info->description=ConstantString(attribute);
885  attribute=GetXMLTreeAttribute(mime,"endian");
886  if (attribute != (const char *) NULL)
887  mime_info->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
888  MagickTrue,attribute);
889  attribute=GetXMLTreeAttribute(mime,"magic");
890  if (attribute != (const char *) NULL)
891  {
892  char
893  *token;
894 
895  const char
896  *p;
897 
898  unsigned char
899  *q;
900 
901  token=AcquireString(attribute);
902  (void) SubstituteString(&token,"&lt;","<");
903  (void) SubstituteString(&token,"&gt;",">");
904  (void) SubstituteString(&token,"&amp;","&");
905  (void) SubstituteString(&token,"&quot;","\"");
906  (void) SubstituteString(&token,"&apos;","'");
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+=(ptrdiff_t) (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=IsStringTrue(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 #endif
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[MagickPathExtent],
1014  media[MagickPathExtent];
1015 
1016  const MimeInfo
1017  *mime_info;
1018 
1020  *exception;
1021 
1022  (void) FormatLocaleString(filename,MagickPathExtent,"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,MagickPathExtent,"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 MagickPrivate MagickBooleanType MimeComponentGenesis(void)
1053 {
1054  if (mime_semaphore == (SemaphoreInfo *) NULL)
1055  mime_semaphore=AcquireSemaphoreInfo();
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 MagickPrivate 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  RelinquishSemaphoreInfo(&mime_semaphore);
1107 }
Definition: mime.c:77