blob: 4fa6b47f190421918063c54f93947e3862c6ee3b [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
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% %
cristy7e41fe82010-12-04 23:12:08 +000018% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000019% 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% http://www.imagemagick.org/MagicksToolkit/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*/
cristy4c08aed2011-07-01 19:47:50 +000040#include "MagickCore/studio.h"
41#include "MagickCore/blob.h"
42#include "MagickCore/client.h"
43#include "MagickCore/configure.h"
44#include "MagickCore/exception.h"
45#include "MagickCore/exception-private.h"
46#include "MagickCore/hashmap.h"
47#include "MagickCore/memory_.h"
48#include "MagickCore/mime.h"
49#include "MagickCore/mime-private.h"
50#include "MagickCore/option.h"
51#include "MagickCore/semaphore.h"
52#include "MagickCore/string_.h"
53#include "MagickCore/token.h"
54#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000055#include "MagickCore/utility-private.h"
cristy4c08aed2011-07-01 19:47:50 +000056#include "MagickCore/xml-tree.h"
cristy3ed852e2009-09-05 21:47:34 +000057
58/*
59 Define declarations.
60*/
61#define MimeFilename "mime.xml"
62
63/*
64 Typedef declaration.
65*/
66struct _MimeInfo
67{
68 char
69 *path,
70 *type,
71 *description,
72 *pattern;
73
cristybb503372010-05-27 20:51:26 +000074 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000075 priority;
76
77 MagickOffsetType
78 offset;
79
80 size_t
81 extent;
82
83 DataType
84 data_type;
85
cristy7c569132010-05-31 00:11:49 +000086 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000087 mask,
88 value;
89
90 EndianType
91 endian;
92
93 size_t
94 length;
95
96 unsigned char
97 *magic;
98
99 MagickBooleanType
100 stealth;
101
cristybb503372010-05-27 20:51:26 +0000102 size_t
cristy3ed852e2009-09-05 21:47:34 +0000103 signature;
104};
105
106/*
107 Static declarations.
108*/
109static const char
110 *MimeMap = (char *)
111 "<?xml version=\"1.0\"?>"
112 "<mimemap>"
113 "</mimemap>";
114
115static LinkedListInfo
116 *mime_list = (LinkedListInfo *) NULL;
117
118static SemaphoreInfo
119 *mime_semaphore = (SemaphoreInfo *) NULL;
120
121static volatile MagickBooleanType
122 instantiate_mime = MagickFalse;
123
124/*
125 Forward declarations.
126*/
127static MagickBooleanType
128 InitializeMimeList(ExceptionInfo *);
129
130/*
131%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
132% %
133% %
134% %
cristy3ed852e2009-09-05 21:47:34 +0000135+ G e t M i m e I n f o %
136% %
137% %
138% %
139%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
140%
141% GetMimeInfo() attempts to classify the content to identify which mime type
142% is associated with the content, if any.
143%
144% The format of the GetMimeInfo method is:
145%
146% const MimeInfo *GetMimeInfo(const char *filename,
147% const unsigned char *magic,const size_t length,
148% ExceptionInfo *exception)
149%
150% A description of each parameter follows:
151%
152% o filename: If we cannot not classify the string, we attempt to classify
153% based on the filename (e.g. *.pdf returns application/pdf).
154%
155% o magic: A binary string generally representing the first few characters
156% of the image file or blob.
157%
158% o length: the length of the binary signature.
159%
160% o exception: return any errors or warnings in this structure.
161%
162*/
163MagickExport const MimeInfo *GetMimeInfo(const char *filename,
164 const unsigned char *magic,const size_t length,ExceptionInfo *exception)
165{
166 const MimeInfo
167 *mime_info;
168
169 EndianType
170 endian;
171
cristy3ed852e2009-09-05 21:47:34 +0000172 register const MimeInfo
173 *p;
174
175 register const unsigned char
176 *q;
177
cristybb503372010-05-27 20:51:26 +0000178 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000179 i;
180
cristybb503372010-05-27 20:51:26 +0000181 size_t
cristy3ed852e2009-09-05 21:47:34 +0000182 lsb_first;
183
cristy7c569132010-05-31 00:11:49 +0000184 ssize_t
cristyecd0ab52010-05-30 14:59:20 +0000185 value;
186
cristy3ed852e2009-09-05 21:47:34 +0000187 assert(exception != (ExceptionInfo *) NULL);
188 if ((mime_list == (LinkedListInfo *) NULL) ||
189 (instantiate_mime == MagickFalse))
190 if (InitializeMimeList(exception) == MagickFalse)
191 return((const MimeInfo *) NULL);
192 if ((mime_list == (LinkedListInfo *) NULL) ||
193 (IsLinkedListEmpty(mime_list) != MagickFalse))
194 return((const MimeInfo *) NULL);
195 if ((magic == (const unsigned char *) NULL) || (length == 0))
196 return((const MimeInfo *) GetValueFromLinkedList(mime_list,0));
197 if (length == 0)
198 return((const MimeInfo *) NULL);
199 /*
200 Search for mime tag.
201 */
202 mime_info=(const MimeInfo *) NULL;
203 lsb_first=1;
cristyf84a1932010-01-03 18:00:18 +0000204 LockSemaphoreInfo(mime_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000205 ResetLinkedListIterator(mime_list);
206 p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
207 while (p != (const MimeInfo *) NULL)
208 {
209 assert(p->offset >= 0);
210 if (mime_info != (const MimeInfo *) NULL)
211 if (p->priority > mime_info->priority)
212 {
213 p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
214 continue;
215 }
216 if ((p->pattern != (char *) NULL) && (filename != (char *) NULL))
217 {
218 if (GlobExpression(filename,p->pattern,MagickFalse) != MagickFalse)
219 mime_info=p;
220 p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
221 continue;
222 }
223 switch (p->data_type)
224 {
225 case ByteData:
226 {
227 if ((size_t) (p->offset+4) > length)
228 break;
229 q=magic+p->offset;
cristy55a91cd2010-12-01 00:57:40 +0000230 value=(ssize_t) (*q++);
cristy3ed852e2009-09-05 21:47:34 +0000231 if (p->mask == 0)
232 {
233 if (p->value == value)
234 mime_info=p;
235 }
236 else
237 {
238 if ((p->value & p->mask) == value)
239 mime_info=p;
240 }
241 break;
242 }
243 case ShortData:
244 {
245 if ((size_t) (p->offset+4) > length)
246 break;
247 q=magic+p->offset;
248 endian=p->endian;
249 if (p->endian == UndefinedEndian)
250 endian=(*(char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
251 if (endian == LSBEndian)
252 {
cristy55a91cd2010-12-01 00:57:40 +0000253 value=(ssize_t) (*q++);
cristy3ed852e2009-09-05 21:47:34 +0000254 value|=(*q++) << 8;
255 }
256 else
257 {
cristy55a91cd2010-12-01 00:57:40 +0000258 value=(ssize_t) (*q++) << 8;
cristy3ed852e2009-09-05 21:47:34 +0000259 value|=(*q++);
260 }
261 if (p->mask == 0)
262 {
263 if (p->value == value)
264 mime_info=p;
265 }
266 else
267 {
268 if ((p->value & p->mask) == value)
269 mime_info=p;
270 }
271 break;
272 }
273 case LongData:
274 {
275 if ((size_t) (p->offset+4) > length)
276 break;
277 q=magic+p->offset;
278 endian=p->endian;
279 if (p->endian == UndefinedEndian)
280 endian=(*(char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
281 if (endian == LSBEndian)
282 {
cristy55a91cd2010-12-01 00:57:40 +0000283 value=(ssize_t) (*q++);
cristy3ed852e2009-09-05 21:47:34 +0000284 value|=(*q++) << 8;
285 value|=(*q++) << 16;
286 value|=(*q++) << 24;
287 }
288 else
289 {
cristy55a91cd2010-12-01 00:57:40 +0000290 value=(ssize_t) (*q++) << 24;
cristy3ed852e2009-09-05 21:47:34 +0000291 value|=(*q++) << 16;
292 value|=(*q++) << 8;
293 value|=(*q++);
294 }
295 if (p->mask == 0)
296 {
297 if (p->value == value)
298 mime_info=p;
299 }
300 else
301 {
302 if ((p->value & p->mask) == value)
303 mime_info=p;
304 }
305 break;
306 }
307 case StringData:
308 default:
309 {
cristybb503372010-05-27 20:51:26 +0000310 for (i=0; i <= (ssize_t) p->extent; i++)
cristy3ed852e2009-09-05 21:47:34 +0000311 {
312 if ((size_t) (p->offset+i+p->length) > length)
313 break;
314 if (memcmp(magic+p->offset+i,p->magic,p->length) == 0)
315 {
316 mime_info=p;
317 break;
318 }
319 }
320 break;
321 }
322 }
323 p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
324 }
325 if (p != (const MimeInfo *) NULL)
326 (void) InsertValueInLinkedList(mime_list,0,
327 RemoveElementByValueFromLinkedList(mime_list,p));
cristyf84a1932010-01-03 18:00:18 +0000328 UnlockSemaphoreInfo(mime_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000329 return(mime_info);
330}
331
332/*
333%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
334% %
335% %
336% %
337% G e t M i m e I n f o L i s t %
338% %
339% %
340% %
341%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
342%
343% GetMimeInfoList() returns any image aliases that match the specified
344% pattern.
345%
346% The magic of the GetMimeInfoList function is:
347%
348% const MimeInfo **GetMimeInfoList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000349% size_t *number_aliases,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000350%
351% A description of each parameter follows:
352%
353% o pattern: Specifies a pointer to a text string containing a pattern.
354%
355% o number_aliases: This integer returns the number of magics in the
356% list.
357%
358% o exception: return any errors or warnings in this structure.
359%
360*/
361
362#if defined(__cplusplus) || defined(c_plusplus)
363extern "C" {
364#endif
365
366static int MimeInfoCompare(const void *x,const void *y)
367{
368 const MimeInfo
369 **p,
370 **q;
371
372 p=(const MimeInfo **) x,
373 q=(const MimeInfo **) y;
374 if (strcasecmp((*p)->path,(*q)->path) == 0)
375 return(strcasecmp((*p)->type,(*q)->type));
376 return(strcasecmp((*p)->path,(*q)->path));
377}
378
379#if defined(__cplusplus) || defined(c_plusplus)
380}
381#endif
382
383MagickExport const MimeInfo **GetMimeInfoList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000384 size_t *number_aliases,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000385{
386 const MimeInfo
387 **aliases;
388
389 register const MimeInfo
390 *p;
391
cristybb503372010-05-27 20:51:26 +0000392 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000393 i;
394
395 /*
396 Allocate mime list.
397 */
398 assert(pattern != (char *) NULL);
399 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
cristybb503372010-05-27 20:51:26 +0000400 assert(number_aliases != (size_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000401 *number_aliases=0;
402 p=GetMimeInfo((char *) NULL,(unsigned char *) "*",0,exception);
403 if (p == (const MimeInfo *) NULL)
404 return((const MimeInfo **) NULL);
405 aliases=(const MimeInfo **) AcquireQuantumMemory((size_t)
406 GetNumberOfElementsInLinkedList(mime_list)+1UL,sizeof(*aliases));
407 if (aliases == (const MimeInfo **) NULL)
408 return((const MimeInfo **) NULL);
409 /*
410 Generate mime list.
411 */
cristyf84a1932010-01-03 18:00:18 +0000412 LockSemaphoreInfo(mime_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000413 ResetLinkedListIterator(mime_list);
414 p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
415 for (i=0; p != (const MimeInfo *) NULL; )
416 {
417 if ((p->stealth == MagickFalse) &&
418 (GlobExpression(p->type,pattern,MagickFalse) != MagickFalse))
419 aliases[i++]=p;
420 p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
421 }
cristyf84a1932010-01-03 18:00:18 +0000422 UnlockSemaphoreInfo(mime_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000423 qsort((void *) aliases,(size_t) i,sizeof(*aliases),MimeInfoCompare);
424 aliases[i]=(MimeInfo *) NULL;
cristybb503372010-05-27 20:51:26 +0000425 *number_aliases=(size_t) i;
cristy3ed852e2009-09-05 21:47:34 +0000426 return(aliases);
427}
428
429/*
430%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
431% %
432% %
433% %
434% G e t M i m e L i s t %
435% %
436% %
437% %
438%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
439%
440% GetMimeList() returns any image format alias that matches the specified
441% pattern.
442%
443% The format of the GetMimeList function is:
444%
cristybb503372010-05-27 20:51:26 +0000445% char **GetMimeList(const char *pattern,size_t *number_aliases,
cristy3ed852e2009-09-05 21:47:34 +0000446% ExceptionInfo *exception)
447%
448% A description of each parameter follows:
449%
450% o pattern: Specifies a pointer to a text string containing a pattern.
451%
452% o number_aliases: This integer returns the number of image format aliases
453% in the list.
454%
455% o exception: return any errors or warnings in this structure.
456%
457*/
458
459#if defined(__cplusplus) || defined(c_plusplus)
460extern "C" {
461#endif
462
463static int MimeCompare(const void *x,const void *y)
464{
465 register char
466 *p,
467 *q;
468
469 p=(char *) x;
470 q=(char *) y;
471 return(strcasecmp(p,q));
472}
473
474#if defined(__cplusplus) || defined(c_plusplus)
475}
476#endif
477
478MagickExport char **GetMimeList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000479 size_t *number_aliases,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000480{
481 char
482 **aliases;
483
484 register const MimeInfo
485 *p;
486
cristybb503372010-05-27 20:51:26 +0000487 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000488 i;
489
490 /*
491 Allocate configure list.
492 */
493 assert(pattern != (char *) NULL);
494 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
cristybb503372010-05-27 20:51:26 +0000495 assert(number_aliases != (size_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000496 *number_aliases=0;
497 p=GetMimeInfo((char *) NULL,(unsigned char *) "*",0,exception);
498 if (p == (const MimeInfo *) NULL)
499 return((char **) NULL);
500 aliases=(char **) AcquireQuantumMemory((size_t)
501 GetNumberOfElementsInLinkedList(mime_list)+1UL,sizeof(*aliases));
502 if (aliases == (char **) NULL)
503 return((char **) NULL);
cristyf84a1932010-01-03 18:00:18 +0000504 LockSemaphoreInfo(mime_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000505 ResetLinkedListIterator(mime_list);
506 p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
507 for (i=0; p != (const MimeInfo *) NULL; )
508 {
509 if ((p->stealth == MagickFalse) &&
510 (GlobExpression(p->type,pattern,MagickFalse) != MagickFalse))
511 aliases[i++]=ConstantString(p->type);
512 p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
513 }
cristyf84a1932010-01-03 18:00:18 +0000514 UnlockSemaphoreInfo(mime_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000515 qsort((void *) aliases,(size_t) i,sizeof(*aliases),MimeCompare);
516 aliases[i]=(char *) NULL;
cristybb503372010-05-27 20:51:26 +0000517 *number_aliases=(size_t) i;
cristy3ed852e2009-09-05 21:47:34 +0000518 return(aliases);
519}
520
521/*
522%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
523% %
524% %
525% %
526% G e t M i m e D e s c r i p t i o n %
527% %
528% %
529% %
530%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
531%
532% GetMimeDescription() returns the mime type description.
533%
534% The format of the GetMimeDescription method is:
535%
536% const char *GetMimeDescription(const MimeInfo *mime_info)
537%
538% A description of each parameter follows:
539%
540% o mime_info: The magic info.
541%
542*/
543MagickExport const char *GetMimeDescription(const MimeInfo *mime_info)
544{
545 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
546 assert(mime_info != (MimeInfo *) NULL);
547 assert(mime_info->signature == MagickSignature);
548 return(mime_info->description);
549}
550
551/*
552%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
553% %
554% %
555% %
556% G e t M i m e T y p e %
557% %
558% %
559% %
560%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
561%
562% GetMimeType() returns the mime type.
563%
564% The format of the GetMimeType method is:
565%
566% const char *GetMimeType(const MimeInfo *mime_info)
567%
568% A description of each parameter follows:
569%
570% o mime_info: The magic info.
571%
572*/
573MagickExport const char *GetMimeType(const MimeInfo *mime_info)
574{
575 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
576 assert(mime_info != (MimeInfo *) NULL);
577 assert(mime_info->signature == MagickSignature);
578 return(mime_info->type);
579}
580
581/*
582%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
583% %
584% %
585% %
586+ I n i t i a l i z e M i m e L i s t %
587% %
588% %
589% %
590%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
591%
592% InitializeMimeList() initializes the mime list.
593%
594% The format of the InitializeMimeList method is:
595%
596% MagickBooleanType InitializeMimeList(ExceptionInfo *exception)
597%
598% A description of each parameter follows.
599%
600% o exception: return any errors or warnings in this structure.
601%
602*/
603static MagickBooleanType InitializeMimeList(ExceptionInfo *exception)
604{
605 if ((mime_list == (LinkedListInfo *) NULL) &&
606 (instantiate_mime == MagickFalse))
607 {
cristy4e1dff62009-10-25 20:36:03 +0000608 if (mime_semaphore == (SemaphoreInfo *) NULL)
609 AcquireSemaphoreInfo(&mime_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000610 LockSemaphoreInfo(mime_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000611 if ((mime_list == (LinkedListInfo *) NULL) &&
612 (instantiate_mime == MagickFalse))
613 {
614 (void) LoadMimeLists(MimeFilename,exception);
615 instantiate_mime=MagickTrue;
616 }
cristyf84a1932010-01-03 18:00:18 +0000617 UnlockSemaphoreInfo(mime_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000618 }
619 return(mime_list != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
620}
621
622/*
623%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
624% %
625% %
626% %
627% L i s t M i m e I n f o %
628% %
629% %
630% %
631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
632%
633% ListMimeInfo() lists the magic info to a file.
634%
635% The format of the ListMimeInfo method is:
636%
637% MagickBooleanType ListMimeInfo(FILE *file,ExceptionInfo *exception)
638%
639% A description of each parameter follows.
640%
641% o file: An pointer to a FILE.
642%
643% o exception: return any errors or warnings in this structure.
644%
645*/
646MagickExport MagickBooleanType ListMimeInfo(FILE *file,ExceptionInfo *exception)
647{
648 const char
649 *path;
650
651 const MimeInfo
652 **mime_info;
653
cristybb503372010-05-27 20:51:26 +0000654 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000655 i;
656
cristybb503372010-05-27 20:51:26 +0000657 size_t
cristy3ed852e2009-09-05 21:47:34 +0000658 number_aliases;
659
cristy9d314ff2011-03-09 01:30:28 +0000660 ssize_t
661 j;
662
cristy3ed852e2009-09-05 21:47:34 +0000663 if (file == (const FILE *) NULL)
664 file=stdout;
665 mime_info=GetMimeInfoList("*",&number_aliases,exception);
666 if (mime_info == (const MimeInfo **) NULL)
667 return(MagickFalse);
668 j=0;
669 path=(const char *) NULL;
cristybb503372010-05-27 20:51:26 +0000670 for (i=0; i < (ssize_t) number_aliases; i++)
cristy3ed852e2009-09-05 21:47:34 +0000671 {
672 if (mime_info[i]->stealth != MagickFalse)
673 continue;
674 if ((path == (const char *) NULL) ||
675 (strcasecmp(path,mime_info[i]->path) != 0))
676 {
677 if (mime_info[i]->path != (char *) NULL)
cristyb51dff52011-05-19 16:55:47 +0000678 (void) FormatLocaleFile(file,"\nPath: %s\n\n",mime_info[i]->path);
679 (void) FormatLocaleFile(file,"Type Description\n");
cristy1e604812011-05-19 18:07:50 +0000680 (void) FormatLocaleFile(file,
681 "-------------------------------------------------"
cristy3ed852e2009-09-05 21:47:34 +0000682 "------------------------------\n");
683 }
684 path=mime_info[i]->path;
cristyb51dff52011-05-19 16:55:47 +0000685 (void) FormatLocaleFile(file,"%s",mime_info[i]->type);
cristy3ed852e2009-09-05 21:47:34 +0000686 if (strlen(mime_info[i]->type) <= 25)
687 {
cristybb503372010-05-27 20:51:26 +0000688 for (j=(ssize_t) strlen(mime_info[i]->type); j <= 27; j++)
cristyb51dff52011-05-19 16:55:47 +0000689 (void) FormatLocaleFile(file," ");
cristy3ed852e2009-09-05 21:47:34 +0000690 }
691 else
692 {
cristyb51dff52011-05-19 16:55:47 +0000693 (void) FormatLocaleFile(file,"\n");
cristy3ed852e2009-09-05 21:47:34 +0000694 for (j=0; j <= 27; j++)
cristyb51dff52011-05-19 16:55:47 +0000695 (void) FormatLocaleFile(file," ");
cristy3ed852e2009-09-05 21:47:34 +0000696 }
697 if (mime_info[i]->description != (char *) NULL)
cristyb51dff52011-05-19 16:55:47 +0000698 (void) FormatLocaleFile(file,"%s",mime_info[i]->description);
699 (void) FormatLocaleFile(file,"\n");
cristy3ed852e2009-09-05 21:47:34 +0000700 }
701 (void) fflush(file);
702 mime_info=(const MimeInfo **) RelinquishMagickMemory((void *) mime_info);
703 return(MagickTrue);
704}
705
706/*
707%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
708% %
709% %
710% %
711+ L o a d M i m e L i s t %
712% %
713% %
714% %
715%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
716%
717% LoadMimeList() loads the magic configuration file which provides a mapping
718% between magic attributes and a magic name.
719%
720% The format of the LoadMimeList method is:
721%
722% MagickBooleanType LoadMimeList(const char *xml,const char *filename,
cristybb503372010-05-27 20:51:26 +0000723% const size_t depth,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000724%
725% A description of each parameter follows:
726%
727% o xml: The mime list in XML format.
728%
729% o filename: The mime list filename.
730%
731% o depth: depth of <include /> statements.
732%
733% o exception: return any errors or warnings in this structure.
734%
735*/
736static MagickBooleanType LoadMimeList(const char *xml,const char *filename,
cristybb503372010-05-27 20:51:26 +0000737 const size_t depth,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000738{
739 const char
740 *attribute;
741
742 MimeInfo
743 *mime_info = (MimeInfo *) NULL;
744
745 MagickBooleanType
746 status;
747
748 XMLTreeInfo
749 *mime,
750 *mime_map,
751 *include;
752
753 /*
754 Load the mime map file.
755 */
756 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
757 "Loading mime map \"%s\" ...",filename);
758 if (xml == (const char *) NULL)
759 return(MagickFalse);
760 if (mime_list == (LinkedListInfo *) NULL)
761 {
762 mime_list=NewLinkedList(0);
763 if (mime_list == (LinkedListInfo *) NULL)
764 {
765 ThrowFileException(exception,ResourceLimitError,
766 "MemoryAllocationFailed",filename);
767 return(MagickFalse);
768 }
769 }
770 mime_map=NewXMLTree(xml,exception);
771 if (mime_map == (XMLTreeInfo *) NULL)
772 return(MagickFalse);
773 status=MagickTrue;
774 include=GetXMLTreeChild(mime_map,"include");
775 while (include != (XMLTreeInfo *) NULL)
776 {
777 /*
778 Process include element.
779 */
780 attribute=GetXMLTreeAttribute(include,"file");
781 if (attribute != (const char *) NULL)
782 {
783 if (depth > 200)
784 (void) ThrowMagickException(exception,GetMagickModule(),
785 ConfigureError,"IncludeElementNestedTooDeeply","`%s'",filename);
786 else
787 {
788 char
789 path[MaxTextExtent],
790 *xml;
791
792 GetPathComponent(filename,HeadPath,path);
793 if (*path != '\0')
794 (void) ConcatenateMagickString(path,DirectorySeparator,
795 MaxTextExtent);
796 if (*attribute == *DirectorySeparator)
797 (void) CopyMagickString(path,attribute,MaxTextExtent);
798 else
799 (void) ConcatenateMagickString(path,attribute,MaxTextExtent);
800 xml=FileToString(path,~0,exception);
801 if (xml != (char *) NULL)
802 {
803 status=LoadMimeList(xml,path,depth+1,exception);
804 xml=DestroyString(xml);
805 }
806 }
807 }
808 include=GetNextXMLTreeTag(include);
809 }
810 mime=GetXMLTreeChild(mime_map,"mime");
811 while (mime != (XMLTreeInfo *) NULL)
812 {
813 const char
814 *attribute;
815
816 /*
817 Process mime element.
818 */
cristy73bd4a52010-10-05 11:24:23 +0000819 mime_info=(MimeInfo *) AcquireMagickMemory(sizeof(*mime_info));
cristy3ed852e2009-09-05 21:47:34 +0000820 if (mime_info == (MimeInfo *) NULL)
821 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
822 (void) ResetMagickMemory(mime_info,0,sizeof(*mime_info));
823 mime_info->path=ConstantString(filename);
824 mime_info->signature=MagickSignature;
825 attribute=GetXMLTreeAttribute(mime,"data-type");
826 if (attribute != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +0000827 mime_info->data_type=(DataType) ParseCommandOption(MagickDataTypeOptions,
cristy3ed852e2009-09-05 21:47:34 +0000828 MagickTrue,attribute);
829 attribute=GetXMLTreeAttribute(mime,"description");
830 if (attribute != (const char *) NULL)
831 mime_info->description=ConstantString(attribute);
832 attribute=GetXMLTreeAttribute(mime,"endian");
833 if (attribute != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +0000834 mime_info->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
cristy3ed852e2009-09-05 21:47:34 +0000835 MagickTrue,attribute);
836 attribute=GetXMLTreeAttribute(mime,"magic");
837 if (attribute != (const char *) NULL)
838 {
839 char
840 *token;
841
842 const char
843 *p;
844
845 register unsigned char
846 *q;
847
848 token=AcquireString(attribute);
849 (void) SubstituteString((char **) &token,"&lt;","<");
850 (void) SubstituteString((char **) &token,"&amp;","&");
851 (void) SubstituteString((char **) &token,"&quot;","\"");
852 mime_info->magic=(unsigned char *) AcquireString(token);
853 q=mime_info->magic;
854 for (p=token; *p != '\0'; )
855 {
856 if (*p == '\\')
857 {
858 p++;
859 if (isdigit((int) ((unsigned char) *p)) != 0)
860 {
861 char
862 *end;
863
864 *q++=(unsigned char) strtol(p,&end,8);
865 p+=(end-p);
866 mime_info->length++;
867 continue;
868 }
869 switch (*p)
870 {
871 case 'b': *q='\b'; break;
872 case 'f': *q='\f'; break;
873 case 'n': *q='\n'; break;
874 case 'r': *q='\r'; break;
875 case 't': *q='\t'; break;
876 case 'v': *q='\v'; break;
877 case 'a': *q='a'; break;
878 case '?': *q='\?'; break;
879 default: *q=(unsigned char) (*p); break;
880 }
881 p++;
882 q++;
883 mime_info->length++;
884 continue;
885 }
886 *q++=(unsigned char) (*p++);
887 mime_info->length++;
888 }
889 token=DestroyString(token);
890 if (mime_info->data_type != StringData)
cristy55a91cd2010-12-01 00:57:40 +0000891 mime_info->value=(ssize_t) strtoul((char *) mime_info->magic,
cristyecd0ab52010-05-30 14:59:20 +0000892 (char **) NULL,0);
cristy3ed852e2009-09-05 21:47:34 +0000893 }
894 attribute=GetXMLTreeAttribute(mime,"mask");
895 if (attribute != (const char *) NULL)
cristy55a91cd2010-12-01 00:57:40 +0000896 mime_info->mask=(ssize_t) strtoul(attribute,(char **) NULL,0);
cristy3ed852e2009-09-05 21:47:34 +0000897 attribute=GetXMLTreeAttribute(mime,"offset");
898 if (attribute != (const char *) NULL)
899 {
900 char
901 *c;
902
903 mime_info->offset=(MagickOffsetType) strtol(attribute,&c,0);
904 if (*c == ':')
905 mime_info->extent=(size_t) strtol(c+1,(char **) NULL,0);
906 }
907 attribute=GetXMLTreeAttribute(mime,"pattern");
908 if (attribute != (const char *) NULL)
909 mime_info->pattern=ConstantString(attribute);
910 attribute=GetXMLTreeAttribute(mime,"priority");
911 if (attribute != (const char *) NULL)
cristyecd0ab52010-05-30 14:59:20 +0000912 mime_info->priority=(ssize_t) strtol(attribute,(char **) NULL,0);
cristy3ed852e2009-09-05 21:47:34 +0000913 attribute=GetXMLTreeAttribute(mime,"stealth");
914 if (attribute != (const char *) NULL)
915 mime_info->stealth=IsMagickTrue(attribute);
916 attribute=GetXMLTreeAttribute(mime,"type");
917 if (attribute != (const char *) NULL)
918 mime_info->type=ConstantString(attribute);
919 status=AppendValueToLinkedList(mime_list,mime_info);
920 if (status == MagickFalse)
921 (void) ThrowMagickException(exception,GetMagickModule(),
922 ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
923 mime=GetNextXMLTreeTag(mime);
924 }
925 mime_map=DestroyXMLTree(mime_map);
926 return(status);
927}
928
929/*
930%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
931% %
932% %
933% %
934% L o a d M i m e L i s t s %
935% %
936% %
937% %
938%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
939%
940% LoadMimeList() loads one or more magic configuration file which provides a
941% mapping between magic attributes and a magic name.
942%
943% The format of the LoadMimeLists method is:
944%
945% MagickBooleanType LoadMimeLists(const char *filename,
946% ExceptionInfo *exception)
947%
948% A description of each parameter follows:
949%
950% o filename: the font file name.
951%
952% o exception: return any errors or warnings in this structure.
953%
954*/
955MagickExport MagickBooleanType LoadMimeLists(const char *filename,
956 ExceptionInfo *exception)
957{
958#if defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
959 return(LoadMimeList(MimeMap,"built-in",0,exception));
960#else
961 const StringInfo
962 *option;
963
964 LinkedListInfo
965 *options;
966
967 MagickStatusType
968 status;
969
970 status=MagickFalse;
971 options=GetConfigureOptions(filename,exception);
972 option=(const StringInfo *) GetNextValueInLinkedList(options);
973 while (option != (const StringInfo *) NULL)
974 {
975 status|=LoadMimeList((const char *) GetStringInfoDatum(option),
976 GetStringInfoPath(option),0,exception);
977 option=(const StringInfo *) GetNextValueInLinkedList(options);
978 }
979 options=DestroyConfigureOptions(options);
cristy82b15832009-10-06 19:17:37 +0000980 if ((mime_list == (LinkedListInfo *) NULL) ||
cristy3ed852e2009-09-05 21:47:34 +0000981 (IsLinkedListEmpty(mime_list) != MagickFalse))
982 status|=LoadMimeList(MimeMap,"built-in",0,exception);
983 else
984 ClearMagickException(exception);
985 return(status != 0 ? MagickTrue : MagickFalse);
986#endif
987}
988
989/*
990%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
991% %
992% %
993% %
994+ M a g i c k T o M i m e %
995% %
996% %
997% %
998%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
999%
1000% MagickToMime() returns the officially registered (or de facto) MIME
1001% media-type corresponding to a magick string. If there is no registered
1002% media-type, then the string "image/x-magick" (all lower case) is returned.
1003% The returned string must be deallocated by the user.
1004%
1005% The format of the MagickToMime method is:
1006%
1007% char *MagickToMime(const char *magick)
1008%
1009% A description of each parameter follows.
1010%
1011% o magick: ImageMagick format specification "magick" tag.
1012%
1013*/
1014MagickExport char *MagickToMime(const char *magick)
1015{
1016 char
1017 filename[MaxTextExtent],
1018 media[MaxTextExtent];
1019
1020 const MimeInfo
1021 *mime_info;
1022
1023 ExceptionInfo
1024 *exception;
1025
cristyb51dff52011-05-19 16:55:47 +00001026 (void) FormatLocaleString(filename,MaxTextExtent,"file.%s",magick);
cristy3ed852e2009-09-05 21:47:34 +00001027 LocaleLower(filename);
1028 exception=AcquireExceptionInfo();
1029 mime_info=GetMimeInfo(filename,(unsigned char *) " ",1,exception);
1030 exception=DestroyExceptionInfo(exception);
1031 if (mime_info != (const MimeInfo *) NULL)
1032 return(ConstantString(GetMimeType(mime_info)));
cristyb51dff52011-05-19 16:55:47 +00001033 (void) FormatLocaleString(media,MaxTextExtent,"image/x-%s",magick);
cristy3ed852e2009-09-05 21:47:34 +00001034 LocaleLower(media+8);
1035 return(ConstantString(media));
1036}
cristyf34a1452009-10-24 22:29:27 +00001037
1038/*
1039%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1040% %
1041% %
1042% %
1043+ M i m e C o m p o n e n t G e n e s i s %
1044% %
1045% %
1046% %
1047%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1048%
1049% MimeComponentGenesis() instantiates the mime component.
1050%
1051% The format of the MimeComponentGenesis method is:
1052%
1053% MagickBooleanType MimeComponentGenesis(void)
1054%
1055*/
cristy5ff4eaf2011-09-03 01:38:02 +00001056MagickPrivate MagickBooleanType MimeComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +00001057{
cristy165b6092009-10-26 13:52:10 +00001058 AcquireSemaphoreInfo(&mime_semaphore);
cristyf34a1452009-10-24 22:29:27 +00001059 return(MagickTrue);
1060}
1061
1062/*
1063%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1064% %
1065% %
1066% %
1067+ M i m e C o m p o n e n t T e r m i n u s %
1068% %
1069% %
1070% %
1071%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1072%
1073% MimeComponentTerminus() destroys the mime component.
1074%
1075% The format of the MimeComponentTerminus method is:
1076%
1077% MimeComponentTerminus(void)
1078%
1079*/
1080
1081static void *DestroyMimeElement(void *mime_info)
1082{
1083 register MimeInfo
1084 *p;
1085
1086 p=(MimeInfo *) mime_info;
1087 if (p->magic != (unsigned char *) NULL)
1088 p->magic=(unsigned char *) RelinquishMagickMemory(p->magic);
1089 if (p->pattern != (char *) NULL)
1090 p->pattern=DestroyString(p->pattern);
1091 if (p->description != (char *) NULL)
1092 p->description=DestroyString(p->description);
1093 if (p->type != (char *) NULL)
1094 p->type=DestroyString(p->type);
1095 if (p->path != (char *) NULL)
1096 p->path=DestroyString(p->path);
1097 p=(MimeInfo *) RelinquishMagickMemory(p);
1098 return((void *) NULL);
1099}
1100
cristy5ff4eaf2011-09-03 01:38:02 +00001101MagickPrivate void MimeComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +00001102{
cristy18b17442009-10-25 18:36:48 +00001103 if (mime_semaphore == (SemaphoreInfo *) NULL)
1104 AcquireSemaphoreInfo(&mime_semaphore);
cristyf84a1932010-01-03 18:00:18 +00001105 LockSemaphoreInfo(mime_semaphore);
cristyf34a1452009-10-24 22:29:27 +00001106 if (mime_list != (LinkedListInfo *) NULL)
1107 mime_list=DestroyLinkedList(mime_list,DestroyMimeElement);
1108 instantiate_mime=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +00001109 UnlockSemaphoreInfo(mime_semaphore);
cristyf34a1452009-10-24 22:29:27 +00001110 DestroySemaphoreInfo(&mime_semaphore);
1111}