blob: 8c273b1f0cd4c14007a44cce9435f5b1031d2adb [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% %
cristy1454be72011-12-19 01:52:48 +000018% Copyright 1999-2012 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"
cristy9639ba32011-09-05 15:09:42 +000044#include "MagickCore/configure-private.h"
cristy4c08aed2011-07-01 19:47:50 +000045#include "MagickCore/exception.h"
46#include "MagickCore/exception-private.h"
47#include "MagickCore/hashmap.h"
48#include "MagickCore/memory_.h"
49#include "MagickCore/mime.h"
50#include "MagickCore/mime-private.h"
51#include "MagickCore/option.h"
52#include "MagickCore/semaphore.h"
53#include "MagickCore/string_.h"
54#include "MagickCore/token.h"
55#include "MagickCore/utility.h"
cristyd1dd6e42011-09-04 01:46:08 +000056#include "MagickCore/utility-private.h"
cristy4c08aed2011-07-01 19:47:50 +000057#include "MagickCore/xml-tree.h"
cristy433d1182011-09-04 13:38:52 +000058#include "MagickCore/xml-tree-private.h"
cristy3ed852e2009-09-05 21:47:34 +000059
60/*
61 Define declarations.
62*/
63#define MimeFilename "mime.xml"
64
65/*
66 Typedef declaration.
67*/
68struct _MimeInfo
69{
70 char
71 *path,
72 *type,
73 *description,
74 *pattern;
75
cristybb503372010-05-27 20:51:26 +000076 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000077 priority;
78
79 MagickOffsetType
80 offset;
81
82 size_t
83 extent;
84
85 DataType
86 data_type;
87
cristy7c569132010-05-31 00:11:49 +000088 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000089 mask,
90 value;
91
92 EndianType
93 endian;
94
95 size_t
96 length;
97
98 unsigned char
99 *magic;
100
101 MagickBooleanType
102 stealth;
103
cristybb503372010-05-27 20:51:26 +0000104 size_t
cristy3ed852e2009-09-05 21:47:34 +0000105 signature;
106};
107
108/*
109 Static declarations.
110*/
111static const char
112 *MimeMap = (char *)
113 "<?xml version=\"1.0\"?>"
114 "<mimemap>"
115 "</mimemap>";
116
117static LinkedListInfo
118 *mime_list = (LinkedListInfo *) NULL;
119
120static SemaphoreInfo
121 *mime_semaphore = (SemaphoreInfo *) NULL;
122
123static volatile MagickBooleanType
124 instantiate_mime = MagickFalse;
125
126/*
127 Forward declarations.
128*/
129static MagickBooleanType
130 InitializeMimeList(ExceptionInfo *);
131
132/*
133%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
134% %
135% %
136% %
cristy3ed852e2009-09-05 21:47:34 +0000137+ G e t M i m e I n f o %
138% %
139% %
140% %
141%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
142%
143% GetMimeInfo() attempts to classify the content to identify which mime type
144% is associated with the content, if any.
145%
146% The format of the GetMimeInfo method is:
147%
148% const MimeInfo *GetMimeInfo(const char *filename,
149% const unsigned char *magic,const size_t length,
150% ExceptionInfo *exception)
151%
152% A description of each parameter follows:
153%
154% o filename: If we cannot not classify the string, we attempt to classify
155% based on the filename (e.g. *.pdf returns application/pdf).
156%
157% o magic: A binary string generally representing the first few characters
158% of the image file or blob.
159%
160% o length: the length of the binary signature.
161%
162% o exception: return any errors or warnings in this structure.
163%
164*/
165MagickExport const MimeInfo *GetMimeInfo(const char *filename,
166 const unsigned char *magic,const size_t length,ExceptionInfo *exception)
167{
168 const MimeInfo
169 *mime_info;
170
171 EndianType
172 endian;
173
cristy3ed852e2009-09-05 21:47:34 +0000174 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
cristy7c569132010-05-31 00:11:49 +0000186 ssize_t
cristyecd0ab52010-05-30 14:59:20 +0000187 value;
188
cristy3ed852e2009-09-05 21:47:34 +0000189 assert(exception != (ExceptionInfo *) NULL);
190 if ((mime_list == (LinkedListInfo *) NULL) ||
191 (instantiate_mime == MagickFalse))
192 if (InitializeMimeList(exception) == MagickFalse)
193 return((const MimeInfo *) NULL);
194 if ((mime_list == (LinkedListInfo *) NULL) ||
195 (IsLinkedListEmpty(mime_list) != MagickFalse))
196 return((const MimeInfo *) NULL);
197 if ((magic == (const unsigned char *) NULL) || (length == 0))
198 return((const MimeInfo *) GetValueFromLinkedList(mime_list,0));
199 if (length == 0)
200 return((const MimeInfo *) NULL);
201 /*
202 Search for mime tag.
203 */
204 mime_info=(const MimeInfo *) NULL;
205 lsb_first=1;
cristyf84a1932010-01-03 18:00:18 +0000206 LockSemaphoreInfo(mime_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000207 ResetLinkedListIterator(mime_list);
208 p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
209 while (p != (const MimeInfo *) NULL)
210 {
211 assert(p->offset >= 0);
212 if (mime_info != (const MimeInfo *) NULL)
213 if (p->priority > mime_info->priority)
214 {
215 p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
216 continue;
217 }
218 if ((p->pattern != (char *) NULL) && (filename != (char *) NULL))
219 {
220 if (GlobExpression(filename,p->pattern,MagickFalse) != MagickFalse)
221 mime_info=p;
222 p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
223 continue;
224 }
225 switch (p->data_type)
226 {
227 case ByteData:
228 {
229 if ((size_t) (p->offset+4) > length)
230 break;
231 q=magic+p->offset;
cristy55a91cd2010-12-01 00:57:40 +0000232 value=(ssize_t) (*q++);
cristy3ed852e2009-09-05 21:47:34 +0000233 if (p->mask == 0)
234 {
235 if (p->value == value)
236 mime_info=p;
237 }
238 else
239 {
240 if ((p->value & p->mask) == value)
241 mime_info=p;
242 }
243 break;
244 }
245 case ShortData:
246 {
247 if ((size_t) (p->offset+4) > length)
248 break;
249 q=magic+p->offset;
250 endian=p->endian;
251 if (p->endian == UndefinedEndian)
252 endian=(*(char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
253 if (endian == LSBEndian)
254 {
cristy55a91cd2010-12-01 00:57:40 +0000255 value=(ssize_t) (*q++);
cristy3ed852e2009-09-05 21:47:34 +0000256 value|=(*q++) << 8;
257 }
258 else
259 {
cristy55a91cd2010-12-01 00:57:40 +0000260 value=(ssize_t) (*q++) << 8;
cristy3ed852e2009-09-05 21:47:34 +0000261 value|=(*q++);
262 }
263 if (p->mask == 0)
264 {
265 if (p->value == value)
266 mime_info=p;
267 }
268 else
269 {
270 if ((p->value & p->mask) == value)
271 mime_info=p;
272 }
273 break;
274 }
275 case LongData:
276 {
277 if ((size_t) (p->offset+4) > length)
278 break;
279 q=magic+p->offset;
280 endian=p->endian;
281 if (p->endian == UndefinedEndian)
282 endian=(*(char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
283 if (endian == LSBEndian)
284 {
cristy55a91cd2010-12-01 00:57:40 +0000285 value=(ssize_t) (*q++);
cristy3ed852e2009-09-05 21:47:34 +0000286 value|=(*q++) << 8;
287 value|=(*q++) << 16;
288 value|=(*q++) << 24;
289 }
290 else
291 {
cristy55a91cd2010-12-01 00:57:40 +0000292 value=(ssize_t) (*q++) << 24;
cristy3ed852e2009-09-05 21:47:34 +0000293 value|=(*q++) << 16;
294 value|=(*q++) << 8;
295 value|=(*q++);
296 }
297 if (p->mask == 0)
298 {
299 if (p->value == value)
300 mime_info=p;
301 }
302 else
303 {
304 if ((p->value & p->mask) == value)
305 mime_info=p;
306 }
307 break;
308 }
309 case StringData:
310 default:
311 {
cristybb503372010-05-27 20:51:26 +0000312 for (i=0; i <= (ssize_t) p->extent; i++)
cristy3ed852e2009-09-05 21:47:34 +0000313 {
314 if ((size_t) (p->offset+i+p->length) > length)
315 break;
316 if (memcmp(magic+p->offset+i,p->magic,p->length) == 0)
317 {
318 mime_info=p;
319 break;
320 }
321 }
322 break;
323 }
324 }
325 p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
326 }
327 if (p != (const MimeInfo *) NULL)
328 (void) InsertValueInLinkedList(mime_list,0,
329 RemoveElementByValueFromLinkedList(mime_list,p));
cristyf84a1932010-01-03 18:00:18 +0000330 UnlockSemaphoreInfo(mime_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000331 return(mime_info);
332}
333
334/*
335%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
336% %
337% %
338% %
339% G e t M i m e I n f o L i s t %
340% %
341% %
342% %
343%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
344%
345% GetMimeInfoList() returns any image aliases that match the specified
346% pattern.
347%
348% The magic of the GetMimeInfoList function is:
349%
350% const MimeInfo **GetMimeInfoList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000351% size_t *number_aliases,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000352%
353% A description of each parameter follows:
354%
355% o pattern: Specifies a pointer to a text string containing a pattern.
356%
357% o number_aliases: This integer returns the number of magics in the
358% list.
359%
360% o exception: return any errors or warnings in this structure.
361%
362*/
363
364#if defined(__cplusplus) || defined(c_plusplus)
365extern "C" {
366#endif
367
368static int MimeInfoCompare(const void *x,const void *y)
369{
370 const MimeInfo
371 **p,
372 **q;
373
374 p=(const MimeInfo **) x,
375 q=(const MimeInfo **) y;
376 if (strcasecmp((*p)->path,(*q)->path) == 0)
377 return(strcasecmp((*p)->type,(*q)->type));
378 return(strcasecmp((*p)->path,(*q)->path));
379}
380
381#if defined(__cplusplus) || defined(c_plusplus)
382}
383#endif
384
385MagickExport const MimeInfo **GetMimeInfoList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000386 size_t *number_aliases,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000387{
388 const MimeInfo
389 **aliases;
390
391 register const MimeInfo
392 *p;
393
cristybb503372010-05-27 20:51:26 +0000394 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000395 i;
396
397 /*
398 Allocate mime list.
399 */
400 assert(pattern != (char *) NULL);
401 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
cristybb503372010-05-27 20:51:26 +0000402 assert(number_aliases != (size_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000403 *number_aliases=0;
404 p=GetMimeInfo((char *) NULL,(unsigned char *) "*",0,exception);
405 if (p == (const MimeInfo *) NULL)
406 return((const MimeInfo **) NULL);
407 aliases=(const MimeInfo **) AcquireQuantumMemory((size_t)
408 GetNumberOfElementsInLinkedList(mime_list)+1UL,sizeof(*aliases));
409 if (aliases == (const MimeInfo **) NULL)
410 return((const MimeInfo **) NULL);
411 /*
412 Generate mime list.
413 */
cristyf84a1932010-01-03 18:00:18 +0000414 LockSemaphoreInfo(mime_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000415 ResetLinkedListIterator(mime_list);
416 p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
417 for (i=0; p != (const MimeInfo *) NULL; )
418 {
419 if ((p->stealth == MagickFalse) &&
420 (GlobExpression(p->type,pattern,MagickFalse) != MagickFalse))
421 aliases[i++]=p;
422 p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
423 }
cristyf84a1932010-01-03 18:00:18 +0000424 UnlockSemaphoreInfo(mime_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000425 qsort((void *) aliases,(size_t) i,sizeof(*aliases),MimeInfoCompare);
426 aliases[i]=(MimeInfo *) NULL;
cristybb503372010-05-27 20:51:26 +0000427 *number_aliases=(size_t) i;
cristy3ed852e2009-09-05 21:47:34 +0000428 return(aliases);
429}
430
431/*
432%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
433% %
434% %
435% %
436% G e t M i m e L i s t %
437% %
438% %
439% %
440%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
441%
442% GetMimeList() returns any image format alias that matches the specified
443% pattern.
444%
445% The format of the GetMimeList function is:
446%
cristybb503372010-05-27 20:51:26 +0000447% char **GetMimeList(const char *pattern,size_t *number_aliases,
cristy3ed852e2009-09-05 21:47:34 +0000448% ExceptionInfo *exception)
449%
450% A description of each parameter follows:
451%
452% o pattern: Specifies a pointer to a text string containing a pattern.
453%
454% o number_aliases: This integer returns the number of image format aliases
455% in the list.
456%
457% o exception: return any errors or warnings in this structure.
458%
459*/
460
461#if defined(__cplusplus) || defined(c_plusplus)
462extern "C" {
463#endif
464
465static int MimeCompare(const void *x,const void *y)
466{
467 register char
468 *p,
469 *q;
470
471 p=(char *) x;
472 q=(char *) y;
473 return(strcasecmp(p,q));
474}
475
476#if defined(__cplusplus) || defined(c_plusplus)
477}
478#endif
479
480MagickExport char **GetMimeList(const char *pattern,
cristybb503372010-05-27 20:51:26 +0000481 size_t *number_aliases,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000482{
483 char
484 **aliases;
485
486 register const MimeInfo
487 *p;
488
cristybb503372010-05-27 20:51:26 +0000489 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000490 i;
491
492 /*
493 Allocate configure list.
494 */
495 assert(pattern != (char *) NULL);
496 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
cristybb503372010-05-27 20:51:26 +0000497 assert(number_aliases != (size_t *) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000498 *number_aliases=0;
499 p=GetMimeInfo((char *) NULL,(unsigned char *) "*",0,exception);
500 if (p == (const MimeInfo *) NULL)
501 return((char **) NULL);
502 aliases=(char **) AcquireQuantumMemory((size_t)
503 GetNumberOfElementsInLinkedList(mime_list)+1UL,sizeof(*aliases));
504 if (aliases == (char **) NULL)
505 return((char **) NULL);
cristyf84a1932010-01-03 18:00:18 +0000506 LockSemaphoreInfo(mime_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000507 ResetLinkedListIterator(mime_list);
508 p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
509 for (i=0; p != (const MimeInfo *) NULL; )
510 {
511 if ((p->stealth == MagickFalse) &&
512 (GlobExpression(p->type,pattern,MagickFalse) != MagickFalse))
513 aliases[i++]=ConstantString(p->type);
514 p=(const MimeInfo *) GetNextValueInLinkedList(mime_list);
515 }
cristyf84a1932010-01-03 18:00:18 +0000516 UnlockSemaphoreInfo(mime_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000517 qsort((void *) aliases,(size_t) i,sizeof(*aliases),MimeCompare);
518 aliases[i]=(char *) NULL;
cristybb503372010-05-27 20:51:26 +0000519 *number_aliases=(size_t) i;
cristy3ed852e2009-09-05 21:47:34 +0000520 return(aliases);
521}
522
523/*
524%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
525% %
526% %
527% %
528% G e t M i m e D e s c r i p t i o n %
529% %
530% %
531% %
532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
533%
534% GetMimeDescription() returns the mime type description.
535%
536% The format of the GetMimeDescription method is:
537%
538% const char *GetMimeDescription(const MimeInfo *mime_info)
539%
540% A description of each parameter follows:
541%
542% o mime_info: The magic info.
543%
544*/
545MagickExport const char *GetMimeDescription(const MimeInfo *mime_info)
546{
547 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
548 assert(mime_info != (MimeInfo *) NULL);
549 assert(mime_info->signature == MagickSignature);
550 return(mime_info->description);
551}
552
553/*
554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
555% %
556% %
557% %
558% G e t M i m e T y p e %
559% %
560% %
561% %
562%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
563%
564% GetMimeType() returns the mime type.
565%
566% The format of the GetMimeType method is:
567%
568% const char *GetMimeType(const MimeInfo *mime_info)
569%
570% A description of each parameter follows:
571%
572% o mime_info: The magic info.
573%
574*/
575MagickExport const char *GetMimeType(const MimeInfo *mime_info)
576{
577 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
578 assert(mime_info != (MimeInfo *) NULL);
579 assert(mime_info->signature == MagickSignature);
580 return(mime_info->type);
581}
582
583/*
584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
585% %
586% %
587% %
588+ I n i t i a l i z e M i m e L i s t %
589% %
590% %
591% %
592%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
593%
594% InitializeMimeList() initializes the mime list.
595%
596% The format of the InitializeMimeList method is:
597%
598% MagickBooleanType InitializeMimeList(ExceptionInfo *exception)
599%
600% A description of each parameter follows.
601%
602% o exception: return any errors or warnings in this structure.
603%
604*/
605static MagickBooleanType InitializeMimeList(ExceptionInfo *exception)
606{
607 if ((mime_list == (LinkedListInfo *) NULL) &&
608 (instantiate_mime == MagickFalse))
609 {
cristy4e1dff62009-10-25 20:36:03 +0000610 if (mime_semaphore == (SemaphoreInfo *) NULL)
611 AcquireSemaphoreInfo(&mime_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000612 LockSemaphoreInfo(mime_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000613 if ((mime_list == (LinkedListInfo *) NULL) &&
614 (instantiate_mime == MagickFalse))
615 {
616 (void) LoadMimeLists(MimeFilename,exception);
617 instantiate_mime=MagickTrue;
618 }
cristyf84a1932010-01-03 18:00:18 +0000619 UnlockSemaphoreInfo(mime_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000620 }
621 return(mime_list != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
622}
623
624/*
625%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
626% %
627% %
628% %
629% L i s t M i m e I n f o %
630% %
631% %
632% %
633%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
634%
635% ListMimeInfo() lists the magic info to a file.
636%
637% The format of the ListMimeInfo method is:
638%
639% MagickBooleanType ListMimeInfo(FILE *file,ExceptionInfo *exception)
640%
641% A description of each parameter follows.
642%
643% o file: An pointer to a FILE.
644%
645% o exception: return any errors or warnings in this structure.
646%
647*/
648MagickExport MagickBooleanType ListMimeInfo(FILE *file,ExceptionInfo *exception)
649{
650 const char
651 *path;
652
653 const MimeInfo
654 **mime_info;
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
cristy9d314ff2011-03-09 01:30:28 +0000662 ssize_t
663 j;
664
cristy3ed852e2009-09-05 21:47:34 +0000665 if (file == (const FILE *) NULL)
666 file=stdout;
667 mime_info=GetMimeInfoList("*",&number_aliases,exception);
668 if (mime_info == (const MimeInfo **) NULL)
669 return(MagickFalse);
670 j=0;
671 path=(const char *) NULL;
cristybb503372010-05-27 20:51:26 +0000672 for (i=0; i < (ssize_t) number_aliases; i++)
cristy3ed852e2009-09-05 21:47:34 +0000673 {
674 if (mime_info[i]->stealth != MagickFalse)
675 continue;
676 if ((path == (const char *) NULL) ||
677 (strcasecmp(path,mime_info[i]->path) != 0))
678 {
679 if (mime_info[i]->path != (char *) NULL)
cristyb51dff52011-05-19 16:55:47 +0000680 (void) FormatLocaleFile(file,"\nPath: %s\n\n",mime_info[i]->path);
681 (void) FormatLocaleFile(file,"Type Description\n");
cristy1e604812011-05-19 18:07:50 +0000682 (void) FormatLocaleFile(file,
683 "-------------------------------------------------"
cristy3ed852e2009-09-05 21:47:34 +0000684 "------------------------------\n");
685 }
686 path=mime_info[i]->path;
cristyb51dff52011-05-19 16:55:47 +0000687 (void) FormatLocaleFile(file,"%s",mime_info[i]->type);
cristy3ed852e2009-09-05 21:47:34 +0000688 if (strlen(mime_info[i]->type) <= 25)
689 {
cristybb503372010-05-27 20:51:26 +0000690 for (j=(ssize_t) strlen(mime_info[i]->type); j <= 27; j++)
cristyb51dff52011-05-19 16:55:47 +0000691 (void) FormatLocaleFile(file," ");
cristy3ed852e2009-09-05 21:47:34 +0000692 }
693 else
694 {
cristyb51dff52011-05-19 16:55:47 +0000695 (void) FormatLocaleFile(file,"\n");
cristy3ed852e2009-09-05 21:47:34 +0000696 for (j=0; j <= 27; j++)
cristyb51dff52011-05-19 16:55:47 +0000697 (void) FormatLocaleFile(file," ");
cristy3ed852e2009-09-05 21:47:34 +0000698 }
699 if (mime_info[i]->description != (char *) NULL)
cristyb51dff52011-05-19 16:55:47 +0000700 (void) FormatLocaleFile(file,"%s",mime_info[i]->description);
701 (void) FormatLocaleFile(file,"\n");
cristy3ed852e2009-09-05 21:47:34 +0000702 }
703 (void) fflush(file);
704 mime_info=(const MimeInfo **) RelinquishMagickMemory((void *) mime_info);
705 return(MagickTrue);
706}
707
708/*
709%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
710% %
711% %
712% %
713+ L o a d M i m e L i s t %
714% %
715% %
716% %
717%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
718%
719% LoadMimeList() loads the magic configuration file which provides a mapping
720% between magic attributes and a magic name.
721%
722% The format of the LoadMimeList method is:
723%
724% MagickBooleanType LoadMimeList(const char *xml,const char *filename,
cristybb503372010-05-27 20:51:26 +0000725% const size_t depth,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000726%
727% A description of each parameter follows:
728%
729% o xml: The mime list in XML format.
730%
731% o filename: The mime list filename.
732%
733% o depth: depth of <include /> statements.
734%
735% o exception: return any errors or warnings in this structure.
736%
737*/
738static MagickBooleanType LoadMimeList(const char *xml,const char *filename,
cristybb503372010-05-27 20:51:26 +0000739 const size_t depth,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000740{
741 const char
742 *attribute;
743
744 MimeInfo
745 *mime_info = (MimeInfo *) NULL;
746
747 MagickBooleanType
748 status;
749
750 XMLTreeInfo
751 *mime,
752 *mime_map,
753 *include;
754
755 /*
756 Load the mime map file.
757 */
758 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
759 "Loading mime map \"%s\" ...",filename);
760 if (xml == (const char *) NULL)
761 return(MagickFalse);
762 if (mime_list == (LinkedListInfo *) NULL)
763 {
764 mime_list=NewLinkedList(0);
765 if (mime_list == (LinkedListInfo *) NULL)
766 {
767 ThrowFileException(exception,ResourceLimitError,
768 "MemoryAllocationFailed",filename);
769 return(MagickFalse);
770 }
771 }
772 mime_map=NewXMLTree(xml,exception);
773 if (mime_map == (XMLTreeInfo *) NULL)
774 return(MagickFalse);
775 status=MagickTrue;
776 include=GetXMLTreeChild(mime_map,"include");
777 while (include != (XMLTreeInfo *) NULL)
778 {
779 /*
780 Process include element.
781 */
782 attribute=GetXMLTreeAttribute(include,"file");
783 if (attribute != (const char *) NULL)
784 {
785 if (depth > 200)
786 (void) ThrowMagickException(exception,GetMagickModule(),
787 ConfigureError,"IncludeElementNestedTooDeeply","`%s'",filename);
788 else
789 {
790 char
791 path[MaxTextExtent],
792 *xml;
793
794 GetPathComponent(filename,HeadPath,path);
795 if (*path != '\0')
796 (void) ConcatenateMagickString(path,DirectorySeparator,
797 MaxTextExtent);
798 if (*attribute == *DirectorySeparator)
799 (void) CopyMagickString(path,attribute,MaxTextExtent);
800 else
801 (void) ConcatenateMagickString(path,attribute,MaxTextExtent);
802 xml=FileToString(path,~0,exception);
803 if (xml != (char *) NULL)
804 {
805 status=LoadMimeList(xml,path,depth+1,exception);
806 xml=DestroyString(xml);
807 }
808 }
809 }
810 include=GetNextXMLTreeTag(include);
811 }
812 mime=GetXMLTreeChild(mime_map,"mime");
813 while (mime != (XMLTreeInfo *) NULL)
814 {
815 const char
816 *attribute;
817
818 /*
819 Process mime element.
820 */
cristy73bd4a52010-10-05 11:24:23 +0000821 mime_info=(MimeInfo *) AcquireMagickMemory(sizeof(*mime_info));
cristy3ed852e2009-09-05 21:47:34 +0000822 if (mime_info == (MimeInfo *) NULL)
823 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
824 (void) ResetMagickMemory(mime_info,0,sizeof(*mime_info));
825 mime_info->path=ConstantString(filename);
826 mime_info->signature=MagickSignature;
827 attribute=GetXMLTreeAttribute(mime,"data-type");
828 if (attribute != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +0000829 mime_info->data_type=(DataType) ParseCommandOption(MagickDataTypeOptions,
cristy3ed852e2009-09-05 21:47:34 +0000830 MagickTrue,attribute);
831 attribute=GetXMLTreeAttribute(mime,"description");
832 if (attribute != (const char *) NULL)
833 mime_info->description=ConstantString(attribute);
834 attribute=GetXMLTreeAttribute(mime,"endian");
835 if (attribute != (const char *) NULL)
cristy042ee782011-04-22 18:48:30 +0000836 mime_info->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
cristy3ed852e2009-09-05 21:47:34 +0000837 MagickTrue,attribute);
838 attribute=GetXMLTreeAttribute(mime,"magic");
839 if (attribute != (const char *) NULL)
840 {
841 char
842 *token;
843
844 const char
845 *p;
846
847 register unsigned char
848 *q;
849
850 token=AcquireString(attribute);
851 (void) SubstituteString((char **) &token,"&lt;","<");
852 (void) SubstituteString((char **) &token,"&amp;","&");
853 (void) SubstituteString((char **) &token,"&quot;","\"");
854 mime_info->magic=(unsigned char *) AcquireString(token);
855 q=mime_info->magic;
856 for (p=token; *p != '\0'; )
857 {
858 if (*p == '\\')
859 {
860 p++;
861 if (isdigit((int) ((unsigned char) *p)) != 0)
862 {
863 char
864 *end;
865
866 *q++=(unsigned char) strtol(p,&end,8);
867 p+=(end-p);
868 mime_info->length++;
869 continue;
870 }
871 switch (*p)
872 {
873 case 'b': *q='\b'; break;
874 case 'f': *q='\f'; break;
875 case 'n': *q='\n'; break;
876 case 'r': *q='\r'; break;
877 case 't': *q='\t'; break;
878 case 'v': *q='\v'; break;
879 case 'a': *q='a'; break;
880 case '?': *q='\?'; break;
881 default: *q=(unsigned char) (*p); break;
882 }
883 p++;
884 q++;
885 mime_info->length++;
886 continue;
887 }
888 *q++=(unsigned char) (*p++);
889 mime_info->length++;
890 }
891 token=DestroyString(token);
892 if (mime_info->data_type != StringData)
cristy55a91cd2010-12-01 00:57:40 +0000893 mime_info->value=(ssize_t) strtoul((char *) mime_info->magic,
cristyecd0ab52010-05-30 14:59:20 +0000894 (char **) NULL,0);
cristy3ed852e2009-09-05 21:47:34 +0000895 }
896 attribute=GetXMLTreeAttribute(mime,"mask");
897 if (attribute != (const char *) NULL)
cristy55a91cd2010-12-01 00:57:40 +0000898 mime_info->mask=(ssize_t) strtoul(attribute,(char **) NULL,0);
cristy3ed852e2009-09-05 21:47:34 +0000899 attribute=GetXMLTreeAttribute(mime,"offset");
900 if (attribute != (const char *) NULL)
901 {
902 char
903 *c;
904
905 mime_info->offset=(MagickOffsetType) strtol(attribute,&c,0);
906 if (*c == ':')
907 mime_info->extent=(size_t) strtol(c+1,(char **) NULL,0);
908 }
909 attribute=GetXMLTreeAttribute(mime,"pattern");
910 if (attribute != (const char *) NULL)
911 mime_info->pattern=ConstantString(attribute);
912 attribute=GetXMLTreeAttribute(mime,"priority");
913 if (attribute != (const char *) NULL)
cristyecd0ab52010-05-30 14:59:20 +0000914 mime_info->priority=(ssize_t) strtol(attribute,(char **) NULL,0);
cristy3ed852e2009-09-05 21:47:34 +0000915 attribute=GetXMLTreeAttribute(mime,"stealth");
916 if (attribute != (const char *) NULL)
917 mime_info->stealth=IsMagickTrue(attribute);
918 attribute=GetXMLTreeAttribute(mime,"type");
919 if (attribute != (const char *) NULL)
920 mime_info->type=ConstantString(attribute);
921 status=AppendValueToLinkedList(mime_list,mime_info);
922 if (status == MagickFalse)
923 (void) ThrowMagickException(exception,GetMagickModule(),
924 ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
925 mime=GetNextXMLTreeTag(mime);
926 }
927 mime_map=DestroyXMLTree(mime_map);
928 return(status);
929}
930
931/*
932%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
933% %
934% %
935% %
936% L o a d M i m e L i s t s %
937% %
938% %
939% %
940%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
941%
942% LoadMimeList() loads one or more magic configuration file which provides a
943% mapping between magic attributes and a magic name.
944%
945% The format of the LoadMimeLists method is:
946%
947% MagickBooleanType LoadMimeLists(const char *filename,
948% ExceptionInfo *exception)
949%
950% A description of each parameter follows:
951%
952% o filename: the font file name.
953%
954% o exception: return any errors or warnings in this structure.
955%
956*/
957MagickExport MagickBooleanType LoadMimeLists(const char *filename,
958 ExceptionInfo *exception)
959{
cristy6e3607c2011-09-13 13:59:17 +0000960#if defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT)
cristy3ed852e2009-09-05 21:47:34 +0000961 return(LoadMimeList(MimeMap,"built-in",0,exception));
962#else
963 const StringInfo
964 *option;
965
966 LinkedListInfo
967 *options;
968
969 MagickStatusType
970 status;
971
972 status=MagickFalse;
973 options=GetConfigureOptions(filename,exception);
974 option=(const StringInfo *) GetNextValueInLinkedList(options);
975 while (option != (const StringInfo *) NULL)
976 {
977 status|=LoadMimeList((const char *) GetStringInfoDatum(option),
978 GetStringInfoPath(option),0,exception);
979 option=(const StringInfo *) GetNextValueInLinkedList(options);
980 }
981 options=DestroyConfigureOptions(options);
cristy82b15832009-10-06 19:17:37 +0000982 if ((mime_list == (LinkedListInfo *) NULL) ||
cristy3ed852e2009-09-05 21:47:34 +0000983 (IsLinkedListEmpty(mime_list) != MagickFalse))
984 status|=LoadMimeList(MimeMap,"built-in",0,exception);
985 else
986 ClearMagickException(exception);
987 return(status != 0 ? MagickTrue : MagickFalse);
988#endif
989}
990
991/*
992%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
993% %
994% %
995% %
996+ M a g i c k T o M i m e %
997% %
998% %
999% %
1000%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1001%
1002% MagickToMime() returns the officially registered (or de facto) MIME
1003% media-type corresponding to a magick string. If there is no registered
1004% media-type, then the string "image/x-magick" (all lower case) is returned.
1005% The returned string must be deallocated by the user.
1006%
1007% The format of the MagickToMime method is:
1008%
1009% char *MagickToMime(const char *magick)
1010%
1011% A description of each parameter follows.
1012%
1013% o magick: ImageMagick format specification "magick" tag.
1014%
1015*/
1016MagickExport char *MagickToMime(const char *magick)
1017{
1018 char
1019 filename[MaxTextExtent],
1020 media[MaxTextExtent];
1021
1022 const MimeInfo
1023 *mime_info;
1024
1025 ExceptionInfo
1026 *exception;
1027
cristyb51dff52011-05-19 16:55:47 +00001028 (void) FormatLocaleString(filename,MaxTextExtent,"file.%s",magick);
cristy3ed852e2009-09-05 21:47:34 +00001029 LocaleLower(filename);
1030 exception=AcquireExceptionInfo();
1031 mime_info=GetMimeInfo(filename,(unsigned char *) " ",1,exception);
1032 exception=DestroyExceptionInfo(exception);
1033 if (mime_info != (const MimeInfo *) NULL)
1034 return(ConstantString(GetMimeType(mime_info)));
cristyb51dff52011-05-19 16:55:47 +00001035 (void) FormatLocaleString(media,MaxTextExtent,"image/x-%s",magick);
cristy3ed852e2009-09-05 21:47:34 +00001036 LocaleLower(media+8);
1037 return(ConstantString(media));
1038}
cristyf34a1452009-10-24 22:29:27 +00001039
1040/*
1041%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1042% %
1043% %
1044% %
1045+ M i m e C o m p o n e n t G e n e s i s %
1046% %
1047% %
1048% %
1049%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1050%
1051% MimeComponentGenesis() instantiates the mime component.
1052%
1053% The format of the MimeComponentGenesis method is:
1054%
1055% MagickBooleanType MimeComponentGenesis(void)
1056%
1057*/
cristy5ff4eaf2011-09-03 01:38:02 +00001058MagickPrivate MagickBooleanType MimeComponentGenesis(void)
cristyf34a1452009-10-24 22:29:27 +00001059{
cristy165b6092009-10-26 13:52:10 +00001060 AcquireSemaphoreInfo(&mime_semaphore);
cristyf34a1452009-10-24 22:29:27 +00001061 return(MagickTrue);
1062}
1063
1064/*
1065%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1066% %
1067% %
1068% %
1069+ M i m e C o m p o n e n t T e r m i n u s %
1070% %
1071% %
1072% %
1073%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1074%
1075% MimeComponentTerminus() destroys the mime component.
1076%
1077% The format of the MimeComponentTerminus method is:
1078%
1079% MimeComponentTerminus(void)
1080%
1081*/
1082
1083static void *DestroyMimeElement(void *mime_info)
1084{
1085 register MimeInfo
1086 *p;
1087
1088 p=(MimeInfo *) mime_info;
1089 if (p->magic != (unsigned char *) NULL)
1090 p->magic=(unsigned char *) RelinquishMagickMemory(p->magic);
1091 if (p->pattern != (char *) NULL)
1092 p->pattern=DestroyString(p->pattern);
1093 if (p->description != (char *) NULL)
1094 p->description=DestroyString(p->description);
1095 if (p->type != (char *) NULL)
1096 p->type=DestroyString(p->type);
1097 if (p->path != (char *) NULL)
1098 p->path=DestroyString(p->path);
1099 p=(MimeInfo *) RelinquishMagickMemory(p);
1100 return((void *) NULL);
1101}
1102
cristy5ff4eaf2011-09-03 01:38:02 +00001103MagickPrivate void MimeComponentTerminus(void)
cristyf34a1452009-10-24 22:29:27 +00001104{
cristy18b17442009-10-25 18:36:48 +00001105 if (mime_semaphore == (SemaphoreInfo *) NULL)
1106 AcquireSemaphoreInfo(&mime_semaphore);
cristyf84a1932010-01-03 18:00:18 +00001107 LockSemaphoreInfo(mime_semaphore);
cristyf34a1452009-10-24 22:29:27 +00001108 if (mime_list != (LinkedListInfo *) NULL)
1109 mime_list=DestroyLinkedList(mime_list,DestroyMimeElement);
1110 instantiate_mime=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +00001111 UnlockSemaphoreInfo(mime_semaphore);
cristyf34a1452009-10-24 22:29:27 +00001112 DestroySemaphoreInfo(&mime_semaphore);
1113}