blob: c9fb232491ec6634bf46dc504711e34420ce886f [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% %
cristy16af1cb2009-12-11 21:38:29 +000018% Copyright 1999-2010 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*/
40#include "magick/studio.h"
41#include "magick/blob.h"
42#include "magick/client.h"
43#include "magick/configure.h"
44#include "magick/exception.h"
45#include "magick/exception-private.h"
46#include "magick/hashmap.h"
47#include "magick/memory_.h"
48#include "magick/mime.h"
49#include "magick/mime-private.h"
50#include "magick/option.h"
51#include "magick/semaphore.h"
52#include "magick/string_.h"
53#include "magick/token.h"
54#include "magick/utility.h"
55#include "magick/xml-tree.h"
56
57/*
58 Define declarations.
59*/
60#define MimeFilename "mime.xml"
61
62/*
63 Typedef declaration.
64*/
65struct _MimeInfo
66{
67 char
68 *path,
69 *type,
70 *description,
71 *pattern;
72
cristybb503372010-05-27 20:51:26 +000073 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000074 priority;
75
76 MagickOffsetType
77 offset;
78
79 size_t
80 extent;
81
82 DataType
83 data_type;
84
cristybb503372010-05-27 20:51:26 +000085 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000086 mask,
87 value;
88
89 EndianType
90 endian;
91
92 size_t
93 length;
94
95 unsigned char
96 *magic;
97
98 MagickBooleanType
99 stealth;
100
cristybb503372010-05-27 20:51:26 +0000101 size_t
cristy3ed852e2009-09-05 21:47:34 +0000102 signature;
103};
104
105/*
106 Static declarations.
107*/
108static const char
109 *MimeMap = (char *)
110 "<?xml version=\"1.0\"?>"
111 "<mimemap>"
112 "</mimemap>";
113
114static LinkedListInfo
115 *mime_list = (LinkedListInfo *) NULL;
116
117static SemaphoreInfo
118 *mime_semaphore = (SemaphoreInfo *) NULL;
119
120static volatile MagickBooleanType
121 instantiate_mime = MagickFalse;
122
123/*
124 Forward declarations.
125*/
126static MagickBooleanType
127 InitializeMimeList(ExceptionInfo *);
128
129/*
130%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
131% %
132% %
133% %
cristy3ed852e2009-09-05 21:47:34 +0000134+ G e t M i m e I n f o %
135% %
136% %
137% %
138%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
139%
140% GetMimeInfo() attempts to classify the content to identify which mime type
141% is associated with the content, if any.
142%
143% The format of the GetMimeInfo method is:
144%
145% const MimeInfo *GetMimeInfo(const char *filename,
146% const unsigned char *magic,const size_t length,
147% ExceptionInfo *exception)
148%
149% A description of each parameter follows:
150%
151% o filename: If we cannot not classify the string, we attempt to classify
152% based on the filename (e.g. *.pdf returns application/pdf).
153%
154% o magic: A binary string generally representing the first few characters
155% of the image file or blob.
156%
157% o length: the length of the binary signature.
158%
159% o exception: return any errors or warnings in this structure.
160%
161*/
162MagickExport const MimeInfo *GetMimeInfo(const char *filename,
163 const unsigned char *magic,const size_t length,ExceptionInfo *exception)
164{
165 const MimeInfo
166 *mime_info;
167
168 EndianType
169 endian;
170
cristybb503372010-05-27 20:51:26 +0000171 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000172 value;
173
174 register const MimeInfo
175 *p;
176
177 register const unsigned char
178 *q;
179
cristybb503372010-05-27 20:51:26 +0000180 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000181 i;
182
cristybb503372010-05-27 20:51:26 +0000183 size_t
cristy3ed852e2009-09-05 21:47:34 +0000184 lsb_first;
185
186 assert(exception != (ExceptionInfo *) NULL);
187 if ((mime_list == (LinkedListInfo *) NULL) ||
188 (instantiate_mime == MagickFalse))
189 if (InitializeMimeList(exception) == MagickFalse)
190 return((const MimeInfo *) NULL);
191 if ((mime_list == (LinkedListInfo *) NULL) ||
192 (IsLinkedListEmpty(mime_list) != MagickFalse))
193 return((const MimeInfo *) NULL);
194 if ((magic == (const unsigned char *) NULL) || (length == 0))
195 return((const MimeInfo *) GetValueFromLinkedList(mime_list,0));
196 if (length == 0)
197 return((const MimeInfo *) NULL);
198 /*
199 Search for mime tag.
200 */
201 mime_info=(const MimeInfo *) NULL;
202 lsb_first=1;
cristyf84a1932010-01-03 18:00:18 +0000203 LockSemaphoreInfo(mime_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000204 ResetLinkedListIterator(mime_list);
205 p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
206 while (p != (const MimeInfo *) NULL)
207 {
208 assert(p->offset >= 0);
209 if (mime_info != (const MimeInfo *) NULL)
210 if (p->priority > mime_info->priority)
211 {
212 p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
213 continue;
214 }
215 if ((p->pattern != (char *) NULL) && (filename != (char *) NULL))
216 {
217 if (GlobExpression(filename,p->pattern,MagickFalse) != MagickFalse)
218 mime_info=p;
219 p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
220 continue;
221 }
222 switch (p->data_type)
223 {
224 case ByteData:
225 {
226 if ((size_t) (p->offset+4) > length)
227 break;
228 q=magic+p->offset;
229 value=(*q++);
230 if (p->mask == 0)
231 {
232 if (p->value == value)
233 mime_info=p;
234 }
235 else
236 {
237 if ((p->value & p->mask) == value)
238 mime_info=p;
239 }
240 break;
241 }
242 case ShortData:
243 {
244 if ((size_t) (p->offset+4) > length)
245 break;
246 q=magic+p->offset;
247 endian=p->endian;
248 if (p->endian == UndefinedEndian)
249 endian=(*(char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
250 if (endian == LSBEndian)
251 {
252 value=(*q++);
253 value|=(*q++) << 8;
254 }
255 else
256 {
257 value=(*q++) << 8;
258 value|=(*q++);
259 }
260 if (p->mask == 0)
261 {
262 if (p->value == value)
263 mime_info=p;
264 }
265 else
266 {
267 if ((p->value & p->mask) == value)
268 mime_info=p;
269 }
270 break;
271 }
272 case LongData:
273 {
274 if ((size_t) (p->offset+4) > length)
275 break;
276 q=magic+p->offset;
277 endian=p->endian;
278 if (p->endian == UndefinedEndian)
279 endian=(*(char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
280 if (endian == LSBEndian)
281 {
282 value=(*q++);
283 value|=(*q++) << 8;
284 value|=(*q++) << 16;
285 value|=(*q++) << 24;
286 }
287 else
288 {
289 value=(*q++) << 24;
290 value|=(*q++) << 16;
291 value|=(*q++) << 8;
292 value|=(*q++);
293 }
294 if (p->mask == 0)
295 {
296 if (p->value == value)
297 mime_info=p;
298 }
299 else
300 {
301 if ((p->value & p->mask) == value)
302 mime_info=p;
303 }
304 break;
305 }
306 case StringData:
307 default:
308 {
cristybb503372010-05-27 20:51:26 +0000309 for (i=0; i <= (ssize_t) p->extent; i++)
cristy3ed852e2009-09-05 21:47:34 +0000310 {
311 if ((size_t) (p->offset+i+p->length) > length)
312 break;
313 if (memcmp(magic+p->offset+i,p->magic,p->length) == 0)
314 {
315 mime_info=p;
316 break;
317 }
318 }
319 break;
320 }
321 }
322 p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
323 }
324 if (p != (const MimeInfo *) NULL)
325 (void) InsertValueInLinkedList(mime_list,0,
326 RemoveElementByValueFromLinkedList(mime_list,p));
cristyf84a1932010-01-03 18:00:18 +0000327 UnlockSemaphoreInfo(mime_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000328 return(mime_info);
329}
330
331/*
332%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
333% %
334% %
335% %
336% G e t M i m e I n f o L i s t %
337% %
338% %
339% %
340%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
341%
342% GetMimeInfoList() returns any image aliases that match the specified
343% pattern.
344%
345% The magic of the GetMimeInfoList function is:
346%
347% const MimeInfo **GetMimeInfoList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000348% size_t *number_aliases,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000349%
350% A description of each parameter follows:
351%
352% o pattern: Specifies a pointer to a text string containing a pattern.
353%
354% o number_aliases: This integer returns the number of magics in the
355% list.
356%
357% o exception: return any errors or warnings in this structure.
358%
359*/
360
361#if defined(__cplusplus) || defined(c_plusplus)
362extern "C" {
363#endif
364
365static int MimeInfoCompare(const void *x,const void *y)
366{
367 const MimeInfo
368 **p,
369 **q;
370
371 p=(const MimeInfo **) x,
372 q=(const MimeInfo **) y;
373 if (strcasecmp((*p)->path,(*q)->path) == 0)
374 return(strcasecmp((*p)->type,(*q)->type));
375 return(strcasecmp((*p)->path,(*q)->path));
376}
377
378#if defined(__cplusplus) || defined(c_plusplus)
379}
380#endif
381
382MagickExport const MimeInfo **GetMimeInfoList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000383 size_t *number_aliases,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000384{
385 const MimeInfo
386 **aliases;
387
388 register const MimeInfo
389 *p;
390
cristybb503372010-05-27 20:51:26 +0000391 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000392 i;
393
394 /*
395 Allocate mime list.
396 */
397 assert(pattern != (char *) NULL);
398 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
cristybb503372010-05-27 20:51:26 +0000399 assert(number_aliases != (size_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000400 *number_aliases=0;
401 p=GetMimeInfo((char *) NULL,(unsigned char *) "*",0,exception);
402 if (p == (const MimeInfo *) NULL)
403 return((const MimeInfo **) NULL);
404 aliases=(const MimeInfo **) AcquireQuantumMemory((size_t)
405 GetNumberOfElementsInLinkedList(mime_list)+1UL,sizeof(*aliases));
406 if (aliases == (const MimeInfo **) NULL)
407 return((const MimeInfo **) NULL);
408 /*
409 Generate mime list.
410 */
cristyf84a1932010-01-03 18:00:18 +0000411 LockSemaphoreInfo(mime_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000412 ResetLinkedListIterator(mime_list);
413 p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
414 for (i=0; p != (const MimeInfo *) NULL; )
415 {
416 if ((p->stealth == MagickFalse) &&
417 (GlobExpression(p->type,pattern,MagickFalse) != MagickFalse))
418 aliases[i++]=p;
419 p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
420 }
cristyf84a1932010-01-03 18:00:18 +0000421 UnlockSemaphoreInfo(mime_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000422 qsort((void *) aliases,(size_t) i,sizeof(*aliases),MimeInfoCompare);
423 aliases[i]=(MimeInfo *) NULL;
cristybb503372010-05-27 20:51:26 +0000424 *number_aliases=(size_t) i;
cristy3ed852e2009-09-05 21:47:34 +0000425 return(aliases);
426}
427
428/*
429%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
430% %
431% %
432% %
433% G e t M i m e L i s t %
434% %
435% %
436% %
437%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
438%
439% GetMimeList() returns any image format alias that matches the specified
440% pattern.
441%
442% The format of the GetMimeList function is:
443%
cristybb503372010-05-27 20:51:26 +0000444% char **GetMimeList(const char *pattern,size_t *number_aliases,
cristy3ed852e2009-09-05 21:47:34 +0000445% ExceptionInfo *exception)
446%
447% A description of each parameter follows:
448%
449% o pattern: Specifies a pointer to a text string containing a pattern.
450%
451% o number_aliases: This integer returns the number of image format aliases
452% in the list.
453%
454% o exception: return any errors or warnings in this structure.
455%
456*/
457
458#if defined(__cplusplus) || defined(c_plusplus)
459extern "C" {
460#endif
461
462static int MimeCompare(const void *x,const void *y)
463{
464 register char
465 *p,
466 *q;
467
468 p=(char *) x;
469 q=(char *) y;
470 return(strcasecmp(p,q));
471}
472
473#if defined(__cplusplus) || defined(c_plusplus)
474}
475#endif
476
477MagickExport char **GetMimeList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000478 size_t *number_aliases,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000479{
480 char
481 **aliases;
482
483 register const MimeInfo
484 *p;
485
cristybb503372010-05-27 20:51:26 +0000486 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000487 i;
488
489 /*
490 Allocate configure list.
491 */
492 assert(pattern != (char *) NULL);
493 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
cristybb503372010-05-27 20:51:26 +0000494 assert(number_aliases != (size_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000495 *number_aliases=0;
496 p=GetMimeInfo((char *) NULL,(unsigned char *) "*",0,exception);
497 if (p == (const MimeInfo *) NULL)
498 return((char **) NULL);
499 aliases=(char **) AcquireQuantumMemory((size_t)
500 GetNumberOfElementsInLinkedList(mime_list)+1UL,sizeof(*aliases));
501 if (aliases == (char **) NULL)
502 return((char **) NULL);
cristyf84a1932010-01-03 18:00:18 +0000503 LockSemaphoreInfo(mime_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000504 ResetLinkedListIterator(mime_list);
505 p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
506 for (i=0; p != (const MimeInfo *) NULL; )
507 {
508 if ((p->stealth == MagickFalse) &&
509 (GlobExpression(p->type,pattern,MagickFalse) != MagickFalse))
510 aliases[i++]=ConstantString(p->type);
511 p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
512 }
cristyf84a1932010-01-03 18:00:18 +0000513 UnlockSemaphoreInfo(mime_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000514 qsort((void *) aliases,(size_t) i,sizeof(*aliases),MimeCompare);
515 aliases[i]=(char *) NULL;
cristybb503372010-05-27 20:51:26 +0000516 *number_aliases=(size_t) i;
cristy3ed852e2009-09-05 21:47:34 +0000517 return(aliases);
518}
519
520/*
521%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
522% %
523% %
524% %
525% G e t M i m e D e s c r i p t i o n %
526% %
527% %
528% %
529%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
530%
531% GetMimeDescription() returns the mime type description.
532%
533% The format of the GetMimeDescription method is:
534%
535% const char *GetMimeDescription(const MimeInfo *mime_info)
536%
537% A description of each parameter follows:
538%
539% o mime_info: The magic info.
540%
541*/
542MagickExport const char *GetMimeDescription(const MimeInfo *mime_info)
543{
544 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
545 assert(mime_info != (MimeInfo *) NULL);
546 assert(mime_info->signature == MagickSignature);
547 return(mime_info->description);
548}
549
550/*
551%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
552% %
553% %
554% %
555% G e t M i m e T y p e %
556% %
557% %
558% %
559%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
560%
561% GetMimeType() returns the mime type.
562%
563% The format of the GetMimeType method is:
564%
565% const char *GetMimeType(const MimeInfo *mime_info)
566%
567% A description of each parameter follows:
568%
569% o mime_info: The magic info.
570%
571*/
572MagickExport const char *GetMimeType(const MimeInfo *mime_info)
573{
574 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
575 assert(mime_info != (MimeInfo *) NULL);
576 assert(mime_info->signature == MagickSignature);
577 return(mime_info->type);
578}
579
580/*
581%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
582% %
583% %
584% %
585+ I n i t i a l i z e M i m e L i s t %
586% %
587% %
588% %
589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
590%
591% InitializeMimeList() initializes the mime list.
592%
593% The format of the InitializeMimeList method is:
594%
595% MagickBooleanType InitializeMimeList(ExceptionInfo *exception)
596%
597% A description of each parameter follows.
598%
599% o exception: return any errors or warnings in this structure.
600%
601*/
602static MagickBooleanType InitializeMimeList(ExceptionInfo *exception)
603{
604 if ((mime_list == (LinkedListInfo *) NULL) &&
605 (instantiate_mime == MagickFalse))
606 {
cristy4e1dff62009-10-25 20:36:03 +0000607 if (mime_semaphore == (SemaphoreInfo *) NULL)
608 AcquireSemaphoreInfo(&mime_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000609 LockSemaphoreInfo(mime_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000610 if ((mime_list == (LinkedListInfo *) NULL) &&
611 (instantiate_mime == MagickFalse))
612 {
613 (void) LoadMimeLists(MimeFilename,exception);
614 instantiate_mime=MagickTrue;
615 }
cristyf84a1932010-01-03 18:00:18 +0000616 UnlockSemaphoreInfo(mime_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000617 }
618 return(mime_list != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
619}
620
621/*
622%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
623% %
624% %
625% %
626% L i s t M i m e I n f o %
627% %
628% %
629% %
630%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
631%
632% ListMimeInfo() lists the magic info to a file.
633%
634% The format of the ListMimeInfo method is:
635%
636% MagickBooleanType ListMimeInfo(FILE *file,ExceptionInfo *exception)
637%
638% A description of each parameter follows.
639%
640% o file: An pointer to a FILE.
641%
642% o exception: return any errors or warnings in this structure.
643%
644*/
645MagickExport MagickBooleanType ListMimeInfo(FILE *file,ExceptionInfo *exception)
646{
647 const char
648 *path;
649
650 const MimeInfo
651 **mime_info;
652
cristybb503372010-05-27 20:51:26 +0000653 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000654 j;
655
cristybb503372010-05-27 20:51:26 +0000656 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000657 i;
658
cristybb503372010-05-27 20:51:26 +0000659 size_t
cristy3ed852e2009-09-05 21:47:34 +0000660 number_aliases;
661
662 if (file == (const FILE *) NULL)
663 file=stdout;
664 mime_info=GetMimeInfoList("*",&number_aliases,exception);
665 if (mime_info == (const MimeInfo **) NULL)
666 return(MagickFalse);
667 j=0;
668 path=(const char *) NULL;
cristybb503372010-05-27 20:51:26 +0000669 for (i=0; i < (ssize_t) number_aliases; i++)
cristy3ed852e2009-09-05 21:47:34 +0000670 {
671 if (mime_info[i]->stealth != MagickFalse)
672 continue;
673 if ((path == (const char *) NULL) ||
674 (strcasecmp(path,mime_info[i]->path) != 0))
675 {
676 if (mime_info[i]->path != (char *) NULL)
677 (void) fprintf(file,"\nPath: %s\n\n",mime_info[i]->path);
678 (void) fprintf(file,"Type Description\n");
679 (void) fprintf(file,"-------------------------------------------------"
680 "------------------------------\n");
681 }
682 path=mime_info[i]->path;
683 (void) fprintf(file,"%s",mime_info[i]->type);
684 if (strlen(mime_info[i]->type) <= 25)
685 {
cristybb503372010-05-27 20:51:26 +0000686 for (j=(ssize_t) strlen(mime_info[i]->type); j <= 27; j++)
cristy3ed852e2009-09-05 21:47:34 +0000687 (void) fprintf(file," ");
688 }
689 else
690 {
691 (void) fprintf(file,"\n");
692 for (j=0; j <= 27; j++)
693 (void) fprintf(file," ");
694 }
695 if (mime_info[i]->description != (char *) NULL)
696 (void) fprintf(file,"%s",mime_info[i]->description);
697 (void) fprintf(file,"\n");
698 }
699 (void) fflush(file);
700 mime_info=(const MimeInfo **) RelinquishMagickMemory((void *) mime_info);
701 return(MagickTrue);
702}
703
704/*
705%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
706% %
707% %
708% %
709+ L o a d M i m e L i s t %
710% %
711% %
712% %
713%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
714%
715% LoadMimeList() loads the magic configuration file which provides a mapping
716% between magic attributes and a magic name.
717%
718% The format of the LoadMimeList method is:
719%
720% MagickBooleanType LoadMimeList(const char *xml,const char *filename,
cristybb503372010-05-27 20:51:26 +0000721% const size_t depth,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000722%
723% A description of each parameter follows:
724%
725% o xml: The mime list in XML format.
726%
727% o filename: The mime list filename.
728%
729% o depth: depth of <include /> statements.
730%
731% o exception: return any errors or warnings in this structure.
732%
733*/
734static MagickBooleanType LoadMimeList(const char *xml,const char *filename,
cristybb503372010-05-27 20:51:26 +0000735 const size_t depth,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000736{
737 const char
738 *attribute;
739
740 MimeInfo
741 *mime_info = (MimeInfo *) NULL;
742
743 MagickBooleanType
744 status;
745
746 XMLTreeInfo
747 *mime,
748 *mime_map,
749 *include;
750
751 /*
752 Load the mime map file.
753 */
754 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
755 "Loading mime map \"%s\" ...",filename);
756 if (xml == (const char *) NULL)
757 return(MagickFalse);
758 if (mime_list == (LinkedListInfo *) NULL)
759 {
760 mime_list=NewLinkedList(0);
761 if (mime_list == (LinkedListInfo *) NULL)
762 {
763 ThrowFileException(exception,ResourceLimitError,
764 "MemoryAllocationFailed",filename);
765 return(MagickFalse);
766 }
767 }
768 mime_map=NewXMLTree(xml,exception);
769 if (mime_map == (XMLTreeInfo *) NULL)
770 return(MagickFalse);
771 status=MagickTrue;
772 include=GetXMLTreeChild(mime_map,"include");
773 while (include != (XMLTreeInfo *) NULL)
774 {
775 /*
776 Process include element.
777 */
778 attribute=GetXMLTreeAttribute(include,"file");
779 if (attribute != (const char *) NULL)
780 {
781 if (depth > 200)
782 (void) ThrowMagickException(exception,GetMagickModule(),
783 ConfigureError,"IncludeElementNestedTooDeeply","`%s'",filename);
784 else
785 {
786 char
787 path[MaxTextExtent],
788 *xml;
789
790 GetPathComponent(filename,HeadPath,path);
791 if (*path != '\0')
792 (void) ConcatenateMagickString(path,DirectorySeparator,
793 MaxTextExtent);
794 if (*attribute == *DirectorySeparator)
795 (void) CopyMagickString(path,attribute,MaxTextExtent);
796 else
797 (void) ConcatenateMagickString(path,attribute,MaxTextExtent);
798 xml=FileToString(path,~0,exception);
799 if (xml != (char *) NULL)
800 {
801 status=LoadMimeList(xml,path,depth+1,exception);
802 xml=DestroyString(xml);
803 }
804 }
805 }
806 include=GetNextXMLTreeTag(include);
807 }
808 mime=GetXMLTreeChild(mime_map,"mime");
809 while (mime != (XMLTreeInfo *) NULL)
810 {
811 const char
812 *attribute;
813
814 /*
815 Process mime element.
816 */
cristy90823212009-12-12 20:48:33 +0000817 mime_info=(MimeInfo *) AcquireAlignedMemory(1,sizeof(*mime_info));
cristy3ed852e2009-09-05 21:47:34 +0000818 if (mime_info == (MimeInfo *) NULL)
819 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
820 (void) ResetMagickMemory(mime_info,0,sizeof(*mime_info));
821 mime_info->path=ConstantString(filename);
822 mime_info->signature=MagickSignature;
823 attribute=GetXMLTreeAttribute(mime,"data-type");
824 if (attribute != (const char *) NULL)
825 mime_info->data_type=(DataType) ParseMagickOption(MagickDataTypeOptions,
826 MagickTrue,attribute);
827 attribute=GetXMLTreeAttribute(mime,"description");
828 if (attribute != (const char *) NULL)
829 mime_info->description=ConstantString(attribute);
830 attribute=GetXMLTreeAttribute(mime,"endian");
831 if (attribute != (const char *) NULL)
832 mime_info->endian=(EndianType) ParseMagickOption(MagickEndianOptions,
833 MagickTrue,attribute);
834 attribute=GetXMLTreeAttribute(mime,"magic");
835 if (attribute != (const char *) NULL)
836 {
837 char
838 *token;
839
840 const char
841 *p;
842
843 register unsigned char
844 *q;
845
846 token=AcquireString(attribute);
847 (void) SubstituteString((char **) &token,"&lt;","<");
848 (void) SubstituteString((char **) &token,"&amp;","&");
849 (void) SubstituteString((char **) &token,"&quot;","\"");
850 mime_info->magic=(unsigned char *) AcquireString(token);
851 q=mime_info->magic;
852 for (p=token; *p != '\0'; )
853 {
854 if (*p == '\\')
855 {
856 p++;
857 if (isdigit((int) ((unsigned char) *p)) != 0)
858 {
859 char
860 *end;
861
862 *q++=(unsigned char) strtol(p,&end,8);
863 p+=(end-p);
864 mime_info->length++;
865 continue;
866 }
867 switch (*p)
868 {
869 case 'b': *q='\b'; break;
870 case 'f': *q='\f'; break;
871 case 'n': *q='\n'; break;
872 case 'r': *q='\r'; break;
873 case 't': *q='\t'; break;
874 case 'v': *q='\v'; break;
875 case 'a': *q='a'; break;
876 case '?': *q='\?'; break;
877 default: *q=(unsigned char) (*p); break;
878 }
879 p++;
880 q++;
881 mime_info->length++;
882 continue;
883 }
884 *q++=(unsigned char) (*p++);
885 mime_info->length++;
886 }
887 token=DestroyString(token);
888 if (mime_info->data_type != StringData)
889 mime_info->value=strtol((char *) mime_info->magic,(char **) NULL,0);
890 }
891 attribute=GetXMLTreeAttribute(mime,"mask");
892 if (attribute != (const char *) NULL)
893 mime_info->mask=strtol(attribute,(char **) NULL,0);
894 attribute=GetXMLTreeAttribute(mime,"offset");
895 if (attribute != (const char *) NULL)
896 {
897 char
898 *c;
899
900 mime_info->offset=(MagickOffsetType) strtol(attribute,&c,0);
901 if (*c == ':')
902 mime_info->extent=(size_t) strtol(c+1,(char **) NULL,0);
903 }
904 attribute=GetXMLTreeAttribute(mime,"pattern");
905 if (attribute != (const char *) NULL)
906 mime_info->pattern=ConstantString(attribute);
907 attribute=GetXMLTreeAttribute(mime,"priority");
908 if (attribute != (const char *) NULL)
909 mime_info->priority=strtol(attribute,(char **) NULL,0);
910 attribute=GetXMLTreeAttribute(mime,"stealth");
911 if (attribute != (const char *) NULL)
912 mime_info->stealth=IsMagickTrue(attribute);
913 attribute=GetXMLTreeAttribute(mime,"type");
914 if (attribute != (const char *) NULL)
915 mime_info->type=ConstantString(attribute);
916 status=AppendValueToLinkedList(mime_list,mime_info);
917 if (status == MagickFalse)
918 (void) ThrowMagickException(exception,GetMagickModule(),
919 ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
920 mime=GetNextXMLTreeTag(mime);
921 }
922 mime_map=DestroyXMLTree(mime_map);
923 return(status);
924}
925
926/*
927%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
928% %
929% %
930% %
931% L o a d M i m e L i s t s %
932% %
933% %
934% %
935%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
936%
937% LoadMimeList() loads one or more magic configuration file which provides a
938% mapping between magic attributes and a magic name.
939%
940% The format of the LoadMimeLists method is:
941%
942% MagickBooleanType LoadMimeLists(const char *filename,
943% ExceptionInfo *exception)
944%
945% A description of each parameter follows:
946%
947% o filename: the font file name.
948%
949% o exception: return any errors or warnings in this structure.
950%
951*/
952MagickExport MagickBooleanType LoadMimeLists(const char *filename,
953 ExceptionInfo *exception)
954{
955#if defined(MAGICKCORE_EMBEDDABLE_SUPPORT)
956 return(LoadMimeList(MimeMap,"built-in",0,exception));
957#else
958 const StringInfo
959 *option;
960
961 LinkedListInfo
962 *options;
963
964 MagickStatusType
965 status;
966
967 status=MagickFalse;
968 options=GetConfigureOptions(filename,exception);
969 option=(const StringInfo *) GetNextValueInLinkedList(options);
970 while (option != (const StringInfo *) NULL)
971 {
972 status|=LoadMimeList((const char *) GetStringInfoDatum(option),
973 GetStringInfoPath(option),0,exception);
974 option=(const StringInfo *) GetNextValueInLinkedList(options);
975 }
976 options=DestroyConfigureOptions(options);
cristy82b15832009-10-06 19:17:37 +0000977 if ((mime_list == (LinkedListInfo *) NULL) ||
cristy3ed852e2009-09-05 21:47:34 +0000978 (IsLinkedListEmpty(mime_list) != MagickFalse))
979 status|=LoadMimeList(MimeMap,"built-in",0,exception);
980 else
981 ClearMagickException(exception);
982 return(status != 0 ? MagickTrue : MagickFalse);
983#endif
984}
985
986/*
987%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
988% %
989% %
990% %
991+ M a g i c k T o M i m e %
992% %
993% %
994% %
995%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
996%
997% MagickToMime() returns the officially registered (or de facto) MIME
998% media-type corresponding to a magick string. If there is no registered
999% media-type, then the string "image/x-magick" (all lower case) is returned.
1000% The returned string must be deallocated by the user.
1001%
1002% The format of the MagickToMime method is:
1003%
1004% char *MagickToMime(const char *magick)
1005%
1006% A description of each parameter follows.
1007%
1008% o magick: ImageMagick format specification "magick" tag.
1009%
1010*/
1011MagickExport char *MagickToMime(const char *magick)
1012{
1013 char
1014 filename[MaxTextExtent],
1015 media[MaxTextExtent];
1016
1017 const MimeInfo
1018 *mime_info;
1019
1020 ExceptionInfo
1021 *exception;
1022
1023 (void) FormatMagickString(filename,MaxTextExtent,"file.%s",magick);
1024 LocaleLower(filename);
1025 exception=AcquireExceptionInfo();
1026 mime_info=GetMimeInfo(filename,(unsigned char *) " ",1,exception);
1027 exception=DestroyExceptionInfo(exception);
1028 if (mime_info != (const MimeInfo *) NULL)
1029 return(ConstantString(GetMimeType(mime_info)));
1030 (void) FormatMagickString(media,MaxTextExtent,"image/x-%s",magick);
1031 LocaleLower(media+8);
1032 return(ConstantString(media));
1033}
cristyf34a1452009-10-24 22:29:27 +00001034
1035/*
1036%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1037% %
1038% %
1039% %
1040+ M i m e C o m p o n e n t G e n e s i s %
1041% %
1042% %
1043% %
1044%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1045%
1046% MimeComponentGenesis() instantiates the mime component.
1047%
1048% The format of the MimeComponentGenesis method is:
1049%
1050% MagickBooleanType MimeComponentGenesis(void)
1051%
1052*/
1053MagickExport MagickBooleanType MimeComponentGenesis(void)
1054{
cristy165b6092009-10-26 13:52:10 +00001055 AcquireSemaphoreInfo(&mime_semaphore);
cristyf34a1452009-10-24 22:29:27 +00001056 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
1078static void *DestroyMimeElement(void *mime_info)
1079{
1080 register 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
1098MagickExport void MimeComponentTerminus(void)
1099{
cristy18b17442009-10-25 18:36:48 +00001100 if (mime_semaphore == (SemaphoreInfo *) NULL)
1101 AcquireSemaphoreInfo(&mime_semaphore);
cristyf84a1932010-01-03 18:00:18 +00001102 LockSemaphoreInfo(mime_semaphore);
cristyf34a1452009-10-24 22:29:27 +00001103 if (mime_list != (LinkedListInfo *) NULL)
1104 mime_list=DestroyLinkedList(mime_list,DestroyMimeElement);
1105 instantiate_mime=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +00001106 UnlockSemaphoreInfo(mime_semaphore);
cristyf34a1452009-10-24 22:29:27 +00001107 DestroySemaphoreInfo(&mime_semaphore);
1108}