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