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