1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % M M EEEEE TTTTT AAA %
7 % MM MM E T A A %
8 % M M M EEE T AAAAA %
9 % M M E T A A %
10 % M M EEEEE T A A %
11 % %
12 % %
13 % Read/Write Embedded Image Profiles. %
14 % %
15 % Software Design %
16 % William Radcliffe %
17 % July 2001 %
18 % %
19 % %
20 % Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % https://imagemagick.org/script/license.php %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38
39 /*
40 Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/blob.h"
44 #include "MagickCore/blob-private.h"
45 #include "MagickCore/channel.h"
46 #include "MagickCore/exception.h"
47 #include "MagickCore/exception-private.h"
48 #include "MagickCore/image.h"
49 #include "MagickCore/image-private.h"
50 #include "MagickCore/list.h"
51 #include "MagickCore/magick.h"
52 #include "MagickCore/memory_.h"
53 #include "MagickCore/module.h"
54 #include "MagickCore/profile.h"
55 #include "MagickCore/splay-tree.h"
56 #include "MagickCore/quantum-private.h"
57 #include "MagickCore/static.h"
58 #include "MagickCore/string_.h"
59 #include "MagickCore/string-private.h"
60 #include "MagickCore/token.h"
61 #include "MagickCore/utility.h"
62
63 /*
64 Forward declarations.
65 */
66 static MagickBooleanType
67 WriteMETAImage(const ImageInfo *,Image *,ExceptionInfo *);
68
69 /*
70 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
71 % %
72 % %
73 % %
74 % I s M E T A %
75 % %
76 % %
77 % %
78 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
79 %
80 % IsMETA() returns MagickTrue if the image format type, identified by the
81 % magick string, is META.
82 %
83 % The format of the IsMETA method is:
84 %
85 % MagickBooleanType IsMETA(const unsigned char *magick,const size_t length)
86 %
87 % A description of each parameter follows:
88 %
89 % o magick: compare image format pattern against these bytes.
90 %
91 % o length: Specifies the length of the magick string.
92 %
93 %
94 */
95 #ifdef IMPLEMENT_IS_FUNCTION
IsMETA(const unsigned char * magick,const size_t length)96 static MagickBooleanType IsMETA(const unsigned char *magick,const size_t length)
97 {
98 if (length < 4)
99 return(MagickFalse);
100 if (LocaleNCompare((char *) magick,"8BIM",4) == 0)
101 return(MagickTrue);
102 if (LocaleNCompare((char *) magick,"APP1",4) == 0)
103 return(MagickTrue);
104 if (LocaleNCompare((char *) magick,"\034\002",2) == 0)
105 return(MagickTrue);
106 return(MagickFalse);
107 }
108 #endif
109
110 /*
111 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
112 % %
113 % %
114 % %
115 % R e a d M E T A I m a g e %
116 % %
117 % %
118 % %
119 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
120 %
121 % ReadMETAImage() reads a META image file and returns it. It
122 % allocates the memory necessary for the new Image structure and returns a
123 % pointer to the new image.
124 %
125 % The format of the ReadMETAImage method is:
126 %
127 % Image *ReadMETAImage(const ImageInfo *image_info,
128 % ExceptionInfo *exception)
129 %
130 % Decompression code contributed by Kyle Shorter.
131 %
132 % A description of each parameter follows:
133 %
134 % o image: Method ReadMETAImage returns a pointer to the image after
135 % reading. A null image is returned if there is a memory shortage or
136 % if the image cannot be read.
137 %
138 % o image_info: Specifies a pointer to an ImageInfo structure.
139 %
140 % o exception: return any errors or warnings in this structure.
141 %
142 */
143
144 typedef struct _html_code
145 {
146 const short int
147 len;
148
149 const char
150 *code,
151 val;
152 } html_code;
153
154 static const html_code html_codes[] = {
155 #ifdef HANDLE_GT_LT
156 { 4,"<",'<' },
157 { 4,">",'>' },
158 #endif
159 { 5,"&",'&' },
160 { 6,""",'"' },
161 { 6,"'",'\''}
162 };
163
stringnicmp(const char * p,const char * q,size_t n)164 static int stringnicmp(const char *p,const char *q,size_t n)
165 {
166 register ssize_t
167 i,
168 j;
169
170 if (p == q)
171 return(0);
172 if (p == (char *) NULL)
173 return(-1);
174 if (q == (char *) NULL)
175 return(1);
176 while ((*p != '\0') && (*q != '\0'))
177 {
178 if ((*p == '\0') || (*q == '\0'))
179 break;
180 i=(*p);
181 if (islower(i))
182 i=LocaleUppercase(i);
183 j=(*q);
184 if (islower(j))
185 j=LocaleUppercase(j);
186 if (i != j)
187 break;
188 n--;
189 if (n == 0)
190 break;
191 p++;
192 q++;
193 }
194 return(LocaleUppercase((int) *p)-LocaleUppercase((int) *q));
195 }
196
convertHTMLcodes(char * s)197 static size_t convertHTMLcodes(char *s)
198 {
199 int
200 value;
201
202 register size_t
203 i;
204
205 size_t
206 length;
207
208 length=0;
209 for (i=0; (i < 7U) && (s[i] != '\0'); i++)
210 if (s[i] == ';')
211 {
212 length=i+1;
213 break;
214 }
215 if ((length == 0) || (s == (char *) NULL) || (*s == '\0'))
216 return(0);
217 if ((length > 3) && (s[1] == '#') && (sscanf(s,"&#%d;",&value) == 1))
218 {
219 size_t
220 o;
221
222 o=3;
223 while (s[o] != ';')
224 {
225 o++;
226 if (o > 5)
227 break;
228 }
229 if (o < 6)
230 (void) memmove(s+1,s+1+o,strlen(s+1+o)+1);
231 *s=value;
232 return(o);
233 }
234 for (i=0; i < (ssize_t) (sizeof(html_codes)/sizeof(html_code)); i++)
235 {
236 if (html_codes[i].len <= (ssize_t) length)
237 if (stringnicmp(s,html_codes[i].code,(size_t) (html_codes[i].len)) == 0)
238 {
239 (void) memmove(s+1,s+html_codes[i].len,strlen(s+html_codes[i].len)+1);
240 *s=html_codes[i].val;
241 return(html_codes[i].len-1);
242 }
243 }
244 return(0);
245 }
246
super_fgets(char ** b,int * blen,Image * file)247 static char *super_fgets(char **b, int *blen, Image *file)
248 {
249 int
250 c,
251 len;
252
253 unsigned char
254 *p,
255 *q;
256
257 len=*blen;
258 p=(unsigned char *) (*b);
259 for (q=p; ; q++)
260 {
261 c=ReadBlobByte(file);
262 if (c == EOF || c == '\n')
263 break;
264 if ((q-p+1) >= (int) len)
265 {
266 int
267 tlen;
268
269 tlen=q-p;
270 len<<=1;
271 p=(unsigned char *) ResizeQuantumMemory(p,(size_t) len+2UL,sizeof(*p));
272 *b=(char *) p;
273 if (p == (unsigned char *) NULL)
274 break;
275 q=p+tlen;
276 }
277 *q=(unsigned char) c;
278 }
279 *blen=0;
280 if (p != (unsigned char *) NULL)
281 {
282 int
283 tlen;
284
285 tlen=q-p;
286 if (tlen == 0)
287 return (char *) NULL;
288 p[tlen] = '\0';
289 *blen=++tlen;
290 }
291 return((char *) p);
292 }
293
294 #define IPTC_ID 1028
295 #define THUMBNAIL_ID 1033
296
parse8BIM(Image * ifile,Image * ofile)297 static ssize_t parse8BIM(Image *ifile, Image *ofile)
298 {
299 char
300 brkused,
301 quoted,
302 *line,
303 *token,
304 *newstr,
305 *name;
306
307 int
308 state,
309 next;
310
311 unsigned char
312 dataset;
313
314 unsigned int
315 recnum;
316
317 int
318 inputlen = MagickPathExtent;
319
320 MagickOffsetType
321 savedpos,
322 currentpos;
323
324 ssize_t
325 savedolen = 0L,
326 outputlen = 0L;
327
328 TokenInfo
329 *token_info;
330
331 dataset = 0;
332 recnum = 0;
333 line = (char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*line));
334 if (line == (char *) NULL)
335 return(-1);
336 newstr = name = token = (char *) NULL;
337 savedpos = 0;
338 token_info=AcquireTokenInfo();
339 while (super_fgets(&line,&inputlen,ifile)!=NULL)
340 {
341 state=0;
342 next=0;
343
344 token=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*token));
345 if (token == (char *) NULL)
346 break;
347 newstr=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*newstr));
348 if (newstr == (char *) NULL)
349 break;
350 while (Tokenizer(token_info,0,token,(size_t) inputlen,line,"","=","\"",0,
351 &brkused,&next,"ed)==0)
352 {
353 if (state == 0)
354 {
355 int
356 state,
357 next;
358
359 char
360 brkused,
361 quoted;
362
363 state=0;
364 next=0;
365 while (Tokenizer(token_info,0,newstr,(size_t) inputlen,token,"","#",
366 "", 0,&brkused,&next,"ed)==0)
367 {
368 switch (state)
369 {
370 case 0:
371 if (strcmp(newstr,"8BIM")==0)
372 dataset = 255;
373 else
374 dataset = (unsigned char) StringToLong(newstr);
375 break;
376 case 1:
377 recnum = (unsigned int) StringToUnsignedLong(newstr);
378 break;
379 case 2:
380 name=(char *) AcquireQuantumMemory(strlen(newstr)+MagickPathExtent,
381 sizeof(*name));
382 if (name)
383 (void) strcpy(name,newstr);
384 break;
385 }
386 state++;
387 }
388 }
389 else
390 if (state == 1)
391 {
392 int
393 next;
394
395 ssize_t
396 len;
397
398 char
399 brkused,
400 quoted;
401
402 next=0;
403 len = (ssize_t) strlen(token);
404 while (Tokenizer(token_info,0,newstr,(size_t) inputlen,token,"","&",
405 "",0,&brkused,&next,"ed)==0)
406 {
407 if (brkused && next > 0)
408 {
409 size_t
410 codes_length;
411
412 char
413 *s = &token[next-1];
414
415 codes_length=convertHTMLcodes(s);
416 if ((ssize_t) codes_length > len)
417 len=0;
418 else
419 len-=codes_length;
420 }
421 }
422
423 if (dataset == 255)
424 {
425 unsigned char
426 nlen = 0;
427
428 int
429 i;
430
431 if (savedolen > 0)
432 {
433 MagickOffsetType
434 offset;
435
436 ssize_t diff = outputlen - savedolen;
437 currentpos = TellBlob(ofile);
438 if (currentpos < 0)
439 {
440 line=DestroyString(line);
441 return(-1);
442 }
443 offset=SeekBlob(ofile,savedpos,SEEK_SET);
444 if (offset < 0)
445 {
446 line=DestroyString(line);
447 return(-1);
448 }
449 (void) WriteBlobMSBLong(ofile,(unsigned int) diff);
450 offset=SeekBlob(ofile,currentpos,SEEK_SET);
451 if (offset < 0)
452 {
453 line=DestroyString(line);
454 return(-1);
455 }
456 savedolen = 0L;
457 }
458 if (outputlen & 1)
459 {
460 (void) WriteBlobByte(ofile,0x00);
461 outputlen++;
462 }
463 (void) WriteBlobString(ofile,"8BIM");
464 (void) WriteBlobMSBShort(ofile,(unsigned short) recnum);
465 outputlen += 6;
466 if (name)
467 nlen = (unsigned char) strlen(name);
468 (void) WriteBlobByte(ofile,nlen);
469 outputlen++;
470 for (i=0; i<nlen; i++)
471 (void) WriteBlobByte(ofile,(unsigned char) name[i]);
472 outputlen += nlen;
473 if ((nlen & 0x01) == 0)
474 {
475 (void) WriteBlobByte(ofile,0x00);
476 outputlen++;
477 }
478 if (recnum != IPTC_ID)
479 {
480 (void) WriteBlobMSBLong(ofile, (unsigned int) len);
481 outputlen += 4;
482
483 next=0;
484 outputlen += len;
485 while (len-- > 0)
486 (void) WriteBlobByte(ofile,(unsigned char) token[next++]);
487
488 if (outputlen & 1)
489 {
490 (void) WriteBlobByte(ofile,0x00);
491 outputlen++;
492 }
493 }
494 else
495 {
496 /* patch in a fake length for now and fix it later */
497 savedpos = TellBlob(ofile);
498 if (savedpos < 0)
499 return(-1);
500 (void) WriteBlobMSBLong(ofile,0xFFFFFFFFU);
501 outputlen += 4;
502 savedolen = outputlen;
503 }
504 }
505 else
506 {
507 if (len <= 0x7FFF)
508 {
509 (void) WriteBlobByte(ofile,0x1c);
510 (void) WriteBlobByte(ofile,(unsigned char) dataset);
511 (void) WriteBlobByte(ofile,(unsigned char) (recnum & 0xff));
512 (void) WriteBlobMSBShort(ofile,(unsigned short) len);
513 outputlen += 5;
514 next=0;
515 outputlen += len;
516 while (len-- > 0)
517 (void) WriteBlobByte(ofile,(unsigned char) token[next++]);
518 }
519 }
520 }
521 state++;
522 }
523 if (token != (char *) NULL)
524 token=DestroyString(token);
525 if (newstr != (char *) NULL)
526 newstr=DestroyString(newstr);
527 if (name != (char *) NULL)
528 name=DestroyString(name);
529 }
530 token_info=DestroyTokenInfo(token_info);
531 if (token != (char *) NULL)
532 token=DestroyString(token);
533 if (newstr != (char *) NULL)
534 newstr=DestroyString(newstr);
535 if (name != (char *) NULL)
536 name=DestroyString(name);
537 line=DestroyString(line);
538 if (savedolen > 0)
539 {
540 MagickOffsetType
541 offset;
542
543 ssize_t diff = outputlen - savedolen;
544
545 currentpos = TellBlob(ofile);
546 if (currentpos < 0)
547 return(-1);
548 offset=SeekBlob(ofile,savedpos,SEEK_SET);
549 if (offset < 0)
550 return(-1);
551 (void) WriteBlobMSBLong(ofile,(unsigned int) diff);
552 offset=SeekBlob(ofile,currentpos,SEEK_SET);
553 if (offset < 0)
554 return(-1);
555 savedolen = 0L;
556 }
557 return outputlen;
558 }
559
super_fgets_w(char ** b,int * blen,Image * file)560 static char *super_fgets_w(char **b, int *blen, Image *file)
561 {
562 int
563 c,
564 len;
565
566 unsigned char
567 *p,
568 *q;
569
570 len=*blen;
571 p=(unsigned char *) (*b);
572 for (q=p; ; q++)
573 {
574 c=ReadBlobLSBSignedShort(file);
575 if ((c == -1) || (c == '\n'))
576 break;
577 if (EOFBlob(file))
578 break;
579 if ((q-p+1) >= (int) len)
580 {
581 int
582 tlen;
583
584 tlen=q-p;
585 len<<=1;
586 p=(unsigned char *) ResizeQuantumMemory(p,(size_t) (len+2),sizeof(*p));
587 *b=(char *) p;
588 if (p == (unsigned char *) NULL)
589 break;
590 q=p+tlen;
591 }
592 *q=(unsigned char) c;
593 }
594 *blen=0;
595 if ((*b) != (char *) NULL)
596 {
597 int
598 tlen;
599
600 tlen=q-p;
601 if (tlen == 0)
602 return (char *) NULL;
603 p[tlen] = '\0';
604 *blen=++tlen;
605 }
606 return((char *) p);
607 }
608
parse8BIMW(Image * ifile,Image * ofile)609 static ssize_t parse8BIMW(Image *ifile, Image *ofile)
610 {
611 char
612 brkused,
613 quoted,
614 *line,
615 *token,
616 *newstr,
617 *name;
618
619 int
620 state,
621 next;
622
623 unsigned char
624 dataset;
625
626 unsigned int
627 recnum;
628
629 int
630 inputlen = MagickPathExtent;
631
632 ssize_t
633 savedolen = 0L,
634 outputlen = 0L;
635
636 MagickOffsetType
637 savedpos,
638 currentpos;
639
640 TokenInfo
641 *token_info;
642
643 dataset = 0;
644 recnum = 0;
645 line=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*line));
646 if (line == (char *) NULL)
647 return(-1);
648 newstr = name = token = (char *) NULL;
649 savedpos = 0;
650 token_info=AcquireTokenInfo();
651 while (super_fgets_w(&line,&inputlen,ifile) != NULL)
652 {
653 state=0;
654 next=0;
655
656 token=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*token));
657 if (token == (char *) NULL)
658 break;
659 newstr=(char *) AcquireQuantumMemory((size_t) inputlen,sizeof(*newstr));
660 if (newstr == (char *) NULL)
661 break;
662 while (Tokenizer(token_info,0,token,(size_t) inputlen,line,"","=","\"",0,
663 &brkused,&next,"ed)==0)
664 {
665 if (state == 0)
666 {
667 int
668 state,
669 next;
670
671 char
672 brkused,
673 quoted;
674
675 state=0;
676 next=0;
677 while (Tokenizer(token_info,0,newstr,(size_t) inputlen,token,"","#",
678 "",0,&brkused,&next,"ed)==0)
679 {
680 switch (state)
681 {
682 case 0:
683 if (strcmp(newstr,"8BIM")==0)
684 dataset = 255;
685 else
686 dataset = (unsigned char) StringToLong(newstr);
687 break;
688 case 1:
689 recnum=(unsigned int) StringToUnsignedLong(newstr);
690 break;
691 case 2:
692 name=(char *) AcquireQuantumMemory(strlen(newstr)+MagickPathExtent,
693 sizeof(*name));
694 if (name)
695 (void) CopyMagickString(name,newstr,strlen(newstr)+MagickPathExtent);
696 break;
697 }
698 state++;
699 }
700 }
701 else
702 if (state == 1)
703 {
704 int
705 next;
706
707 ssize_t
708 len;
709
710 char
711 brkused,
712 quoted;
713
714 next=0;
715 len = (ssize_t) strlen(token);
716 while (Tokenizer(token_info,0,newstr,(size_t) inputlen,token,"","&",
717 "",0,&brkused,&next,"ed)==0)
718 {
719 if (brkused && next > 0)
720 {
721 size_t
722 codes_length;
723
724 char
725 *s = &token[next-1];
726
727 codes_length=convertHTMLcodes(s);
728 if ((ssize_t) codes_length > len)
729 len=0;
730 else
731 len-=codes_length;
732 }
733 }
734
735 if (dataset == 255)
736 {
737 unsigned char
738 nlen = 0;
739
740 int
741 i;
742
743 if (savedolen > 0)
744 {
745 MagickOffsetType
746 offset;
747
748 ssize_t diff = outputlen - savedolen;
749 currentpos = TellBlob(ofile);
750 if (currentpos < 0)
751 return(-1);
752 offset=SeekBlob(ofile,savedpos,SEEK_SET);
753 if (offset < 0)
754 return(-1);
755 (void) WriteBlobMSBLong(ofile,(unsigned int) diff);
756 offset=SeekBlob(ofile,currentpos,SEEK_SET);
757 if (offset < 0)
758 return(-1);
759 savedolen = 0L;
760 }
761 if (outputlen & 1)
762 {
763 (void) WriteBlobByte(ofile,0x00);
764 outputlen++;
765 }
766 (void) WriteBlobString(ofile,"8BIM");
767 (void) WriteBlobMSBShort(ofile,(unsigned short) recnum);
768 outputlen += 6;
769 if (name)
770 nlen = (unsigned char) strlen(name);
771 (void) WriteBlobByte(ofile,(unsigned char) nlen);
772 outputlen++;
773 for (i=0; i<nlen; i++)
774 (void) WriteBlobByte(ofile,(unsigned char) name[i]);
775 outputlen += nlen;
776 if ((nlen & 0x01) == 0)
777 {
778 (void) WriteBlobByte(ofile,0x00);
779 outputlen++;
780 }
781 if (recnum != IPTC_ID)
782 {
783 (void) WriteBlobMSBLong(ofile,(unsigned int) len);
784 outputlen += 4;
785
786 next=0;
787 outputlen += len;
788 while (len--)
789 (void) WriteBlobByte(ofile,(unsigned char) token[next++]);
790
791 if (outputlen & 1)
792 {
793 (void) WriteBlobByte(ofile,0x00);
794 outputlen++;
795 }
796 }
797 else
798 {
799 /* patch in a fake length for now and fix it later */
800 savedpos = TellBlob(ofile);
801 if (savedpos < 0)
802 return(-1);
803 (void) WriteBlobMSBLong(ofile,0xFFFFFFFFU);
804 outputlen += 4;
805 savedolen = outputlen;
806 }
807 }
808 else
809 {
810 if (len <= 0x7FFF)
811 {
812 (void) WriteBlobByte(ofile,0x1c);
813 (void) WriteBlobByte(ofile,dataset);
814 (void) WriteBlobByte(ofile,(unsigned char) (recnum & 0xff));
815 (void) WriteBlobMSBShort(ofile,(unsigned short) len);
816 outputlen += 5;
817 next=0;
818 outputlen += len;
819 while (len--)
820 (void) WriteBlobByte(ofile,(unsigned char) token[next++]);
821 }
822 }
823 }
824 state++;
825 }
826 if (token != (char *) NULL)
827 token=DestroyString(token);
828 if (newstr != (char *) NULL)
829 newstr=DestroyString(newstr);
830 if (name != (char *) NULL)
831 name=DestroyString(name);
832 }
833 token_info=DestroyTokenInfo(token_info);
834 if (token != (char *) NULL)
835 token=DestroyString(token);
836 if (newstr != (char *) NULL)
837 newstr=DestroyString(newstr);
838 if (name != (char *) NULL)
839 name=DestroyString(name);
840 line=DestroyString(line);
841 if (savedolen > 0)
842 {
843 MagickOffsetType
844 offset;
845
846 ssize_t diff = outputlen - savedolen;
847
848 currentpos = TellBlob(ofile);
849 if (currentpos < 0)
850 return(-1);
851 offset=SeekBlob(ofile,savedpos,SEEK_SET);
852 if (offset < 0)
853 return(-1);
854 (void) WriteBlobMSBLong(ofile,(unsigned int) diff);
855 offset=SeekBlob(ofile,currentpos,SEEK_SET);
856 if (offset < 0)
857 return(-1);
858 savedolen = 0L;
859 }
860 return(outputlen);
861 }
862
863 /* some defines for the different JPEG block types */
864 #define M_SOF0 0xC0 /* Start Of Frame N */
865 #define M_SOF1 0xC1 /* N indicates which compression process */
866 #define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */
867 #define M_SOF3 0xC3
868 #define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */
869 #define M_SOF6 0xC6
870 #define M_SOF7 0xC7
871 #define M_SOF9 0xC9
872 #define M_SOF10 0xCA
873 #define M_SOF11 0xCB
874 #define M_SOF13 0xCD
875 #define M_SOF14 0xCE
876 #define M_SOF15 0xCF
877 #define M_SOI 0xD8
878 #define M_EOI 0xD9 /* End Of Image (end of datastream) */
879 #define M_SOS 0xDA /* Start Of Scan (begins compressed data) */
880 #define M_APP0 0xe0
881 #define M_APP1 0xe1
882 #define M_APP2 0xe2
883 #define M_APP3 0xe3
884 #define M_APP4 0xe4
885 #define M_APP5 0xe5
886 #define M_APP6 0xe6
887 #define M_APP7 0xe7
888 #define M_APP8 0xe8
889 #define M_APP9 0xe9
890 #define M_APP10 0xea
891 #define M_APP11 0xeb
892 #define M_APP12 0xec
893 #define M_APP13 0xed
894 #define M_APP14 0xee
895 #define M_APP15 0xef
896
jpeg_transfer_1(Image * ifile,Image * ofile)897 static int jpeg_transfer_1(Image *ifile, Image *ofile)
898 {
899 int c;
900
901 c = ReadBlobByte(ifile);
902 if (c == EOF)
903 return EOF;
904 (void) WriteBlobByte(ofile,(unsigned char) c);
905 return c;
906 }
907
908 #if defined(future)
jpeg_skip_1(Image * ifile)909 static int jpeg_skip_1(Image *ifile)
910 {
911 int c;
912
913 c = ReadBlobByte(ifile);
914 if (c == EOF)
915 return EOF;
916 return c;
917 }
918 #endif
919
jpeg_read_remaining(Image * ifile,Image * ofile)920 static int jpeg_read_remaining(Image *ifile, Image *ofile)
921 {
922 int c;
923
924 while ((c = jpeg_transfer_1(ifile, ofile)) != EOF)
925 continue;
926 return M_EOI;
927 }
928
jpeg_skip_variable(Image * ifile,Image * ofile)929 static int jpeg_skip_variable(Image *ifile, Image *ofile)
930 {
931 unsigned int length;
932 int c1,c2;
933
934 if ((c1 = jpeg_transfer_1(ifile, ofile)) == EOF)
935 return M_EOI;
936 if ((c2 = jpeg_transfer_1(ifile, ofile)) == EOF)
937 return M_EOI;
938
939 length = (((unsigned int) c1) << 8) + ((unsigned int) c2);
940 length -= 2;
941
942 while (length--)
943 if (jpeg_transfer_1(ifile, ofile) == EOF)
944 return M_EOI;
945
946 return 0;
947 }
948
jpeg_skip_variable2(Image * ifile,Image * ofile)949 static int jpeg_skip_variable2(Image *ifile, Image *ofile)
950 {
951 unsigned int length;
952 int c1,c2;
953
954 (void) ofile;
955 if ((c1 = ReadBlobByte(ifile)) == EOF) return M_EOI;
956 if ((c2 = ReadBlobByte(ifile)) == EOF) return M_EOI;
957
958 length = (((unsigned int) c1) << 8) + ((unsigned int) c2);
959 length -= 2;
960
961 while (length--)
962 if (ReadBlobByte(ifile) == EOF)
963 return M_EOI;
964
965 return 0;
966 }
967
jpeg_nextmarker(Image * ifile,Image * ofile)968 static int jpeg_nextmarker(Image *ifile, Image *ofile)
969 {
970 int c;
971
972 /* transfer anything until we hit 0xff */
973 do
974 {
975 c = ReadBlobByte(ifile);
976 if (c == EOF)
977 return M_EOI; /* we hit EOF */
978 else
979 if (c != 0xff)
980 (void) WriteBlobByte(ofile,(unsigned char) c);
981 } while (c != 0xff);
982
983 /* get marker byte, swallowing possible padding */
984 do
985 {
986 c = ReadBlobByte(ifile);
987 if (c == EOF)
988 return M_EOI; /* we hit EOF */
989 } while (c == 0xff);
990
991 return c;
992 }
993
994 #if defined(future)
jpeg_skip_till_marker(Image * ifile,int marker)995 static int jpeg_skip_till_marker(Image *ifile, int marker)
996 {
997 int c, i;
998
999 do
1000 {
1001 /* skip anything until we hit 0xff */
1002 i = 0;
1003 do
1004 {
1005 c = ReadBlobByte(ifile);
1006 i++;
1007 if (c == EOF)
1008 return M_EOI; /* we hit EOF */
1009 } while (c != 0xff);
1010
1011 /* get marker byte, swallowing possible padding */
1012 do
1013 {
1014 c = ReadBlobByte(ifile);
1015 if (c == EOF)
1016 return M_EOI; /* we hit EOF */
1017 } while (c == 0xff);
1018 } while (c != marker);
1019 return c;
1020 }
1021 #endif
1022
1023 /* Embed binary IPTC data into a JPEG image. */
jpeg_embed(Image * ifile,Image * ofile,Image * iptc)1024 static int jpeg_embed(Image *ifile, Image *ofile, Image *iptc)
1025 {
1026 unsigned int marker;
1027 unsigned int done = 0;
1028 unsigned int len;
1029 int inx;
1030
1031 if (jpeg_transfer_1(ifile, ofile) != 0xFF)
1032 return 0;
1033 if (jpeg_transfer_1(ifile, ofile) != M_SOI)
1034 return 0;
1035
1036 while (done == MagickFalse)
1037 {
1038 marker=(unsigned int) jpeg_nextmarker(ifile, ofile);
1039 if (marker == M_EOI)
1040 { /* EOF */
1041 break;
1042 }
1043 else
1044 {
1045 if (marker != M_APP13)
1046 {
1047 (void) WriteBlobByte(ofile,0xff);
1048 (void) WriteBlobByte(ofile,(unsigned char) marker);
1049 }
1050 }
1051
1052 switch (marker)
1053 {
1054 case M_APP13:
1055 /* we are going to write a new APP13 marker, so don't output the old one */
1056 jpeg_skip_variable2(ifile, ofile);
1057 break;
1058
1059 case M_APP0:
1060 /* APP0 is in each and every JPEG, so when we hit APP0 we insert our new APP13! */
1061 jpeg_skip_variable(ifile, ofile);
1062
1063 if (iptc != (Image *) NULL)
1064 {
1065 char
1066 psheader[] = "\xFF\xED\0\0Photoshop 3.0\0" "8BIM\x04\x04\0\0\0\0";
1067
1068 len=(unsigned int) GetBlobSize(iptc);
1069 if (len & 1)
1070 len++; /* make the length even */
1071 psheader[2]=(char) ((len+16)>>8);
1072 psheader[3]=(char) ((len+16)&0xff);
1073 for (inx = 0; inx < 18; inx++)
1074 (void) WriteBlobByte(ofile,(unsigned char) psheader[inx]);
1075 jpeg_read_remaining(iptc, ofile);
1076 len=(unsigned int) GetBlobSize(iptc);
1077 if (len & 1)
1078 (void) WriteBlobByte(ofile,0);
1079 }
1080 break;
1081
1082 case M_SOS:
1083 /* we hit data, no more marker-inserting can be done! */
1084 jpeg_read_remaining(ifile, ofile);
1085 done = 1;
1086 break;
1087
1088 default:
1089 jpeg_skip_variable(ifile, ofile);
1090 break;
1091 }
1092 }
1093 return 1;
1094 }
1095
1096 /* handle stripping the APP13 data out of a JPEG */
1097 #if defined(future)
jpeg_strip(Image * ifile,Image * ofile)1098 static void jpeg_strip(Image *ifile, Image *ofile)
1099 {
1100 unsigned int marker;
1101
1102 marker = jpeg_skip_till_marker(ifile, M_SOI);
1103 if (marker == M_SOI)
1104 {
1105 (void) WriteBlobByte(ofile,0xff);
1106 (void) WriteBlobByte(ofile,M_SOI);
1107 jpeg_read_remaining(ifile, ofile);
1108 }
1109 }
1110
1111 /* Extract any APP13 binary data into a file. */
jpeg_extract(Image * ifile,Image * ofile)1112 static int jpeg_extract(Image *ifile, Image *ofile)
1113 {
1114 unsigned int marker;
1115 unsigned int done = 0;
1116
1117 if (jpeg_skip_1(ifile) != 0xff)
1118 return 0;
1119 if (jpeg_skip_1(ifile) != M_SOI)
1120 return 0;
1121
1122 while (done == MagickFalse)
1123 {
1124 marker = jpeg_skip_till_marker(ifile, M_APP13);
1125 if (marker == M_APP13)
1126 {
1127 marker = jpeg_nextmarker(ifile, ofile);
1128 break;
1129 }
1130 }
1131 return 1;
1132 }
1133 #endif
1134
CopyBlob(Image * source,Image * destination)1135 static inline void CopyBlob(Image *source,Image *destination)
1136 {
1137 ssize_t
1138 i;
1139
1140 unsigned char
1141 *buffer;
1142
1143 ssize_t
1144 count,
1145 length;
1146
1147 buffer=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
1148 sizeof(*buffer));
1149 if (buffer != (unsigned char *) NULL)
1150 {
1151 i=0;
1152 while ((length=ReadBlob(source,MagickMaxBufferExtent,buffer)) != 0)
1153 {
1154 count=0;
1155 for (i=0; i < (ssize_t) length; i+=count)
1156 {
1157 count=WriteBlob(destination,(size_t) (length-i),buffer+i);
1158 if (count <= 0)
1159 break;
1160 }
1161 if (i < (ssize_t) length)
1162 break;
1163 }
1164 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
1165 }
1166 }
1167
ReadMETAImage(const ImageInfo * image_info,ExceptionInfo * exception)1168 static Image *ReadMETAImage(const ImageInfo *image_info,
1169 ExceptionInfo *exception)
1170 {
1171 Image
1172 *buff,
1173 *image;
1174
1175 MagickBooleanType
1176 status;
1177
1178 StringInfo
1179 *profile;
1180
1181 size_t
1182 length;
1183
1184 void
1185 *blob;
1186
1187 /*
1188 Open file containing binary metadata
1189 */
1190 assert(image_info != (const ImageInfo *) NULL);
1191 assert(image_info->signature == MagickCoreSignature);
1192 if (image_info->debug != MagickFalse)
1193 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1194 image_info->filename);
1195 assert(exception != (ExceptionInfo *) NULL);
1196 assert(exception->signature == MagickCoreSignature);
1197 image=AcquireImage(image_info,exception);
1198 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1199 if (status == MagickFalse)
1200 {
1201 image=DestroyImageList(image);
1202 return((Image *) NULL);
1203 }
1204 image->columns=1;
1205 image->rows=1;
1206 if (SetImageBackgroundColor(image,exception) == MagickFalse)
1207 {
1208 image=DestroyImageList(image);
1209 return((Image *) NULL);
1210 }
1211 length=1;
1212 if (LocaleNCompare(image_info->magick,"8BIM",4) == 0)
1213 {
1214 /*
1215 Read 8BIM binary metadata.
1216 */
1217 buff=AcquireImage((ImageInfo *) NULL,exception);
1218 if (buff == (Image *) NULL)
1219 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1220 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1221 if (blob == (unsigned char *) NULL)
1222 {
1223 buff=DestroyImage(buff);
1224 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1225 }
1226 (void) memset(blob,0,length);
1227 AttachBlob(buff->blob,blob,length);
1228 if (LocaleCompare(image_info->magick,"8BIMTEXT") == 0)
1229 {
1230 length=(size_t) parse8BIM(image, buff);
1231 if (length == 0)
1232 {
1233 blob=DetachBlob(buff->blob);
1234 blob=(unsigned char *) RelinquishMagickMemory(blob);
1235 buff=DestroyImage(buff);
1236 ThrowReaderException(CorruptImageError,"CorruptImage");
1237 }
1238 if (length & 1)
1239 (void) WriteBlobByte(buff,0x0);
1240 }
1241 else if (LocaleCompare(image_info->magick,"8BIMWTEXT") == 0)
1242 {
1243 length=(size_t) parse8BIMW(image, buff);
1244 if (length == 0)
1245 {
1246 blob=DetachBlob(buff->blob);
1247 blob=(unsigned char *) RelinquishMagickMemory(blob);
1248 buff=DestroyImage(buff);
1249 ThrowReaderException(CorruptImageError,"CorruptImage");
1250 }
1251 if (length & 1)
1252 (void) WriteBlobByte(buff,0x0);
1253 }
1254 else
1255 CopyBlob(image,buff);
1256 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
1257 GetBlobSize(buff));
1258 if (profile == (StringInfo *) NULL)
1259 {
1260 blob=DetachBlob(buff->blob);
1261 blob=(unsigned char *) RelinquishMagickMemory(blob);
1262 buff=DestroyImage(buff);
1263 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1264 }
1265 status=SetImageProfile(image,"8bim",profile,exception);
1266 profile=DestroyStringInfo(profile);
1267 blob=DetachBlob(buff->blob);
1268 blob=(unsigned char *) RelinquishMagickMemory(blob);
1269 buff=DestroyImage(buff);
1270 if (status == MagickFalse)
1271 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1272 }
1273 if (LocaleNCompare(image_info->magick,"APP1",4) == 0)
1274 {
1275 char
1276 name[MagickPathExtent];
1277
1278 (void) FormatLocaleString(name,MagickPathExtent,"APP%d",1);
1279 buff=AcquireImage((ImageInfo *) NULL,exception);
1280 if (buff == (Image *) NULL)
1281 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1282 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1283 if (blob == (unsigned char *) NULL)
1284 {
1285 buff=DestroyImage(buff);
1286 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1287 }
1288 AttachBlob(buff->blob,blob,length);
1289 if (LocaleCompare(image_info->magick,"APP1JPEG") == 0)
1290 {
1291 Image
1292 *iptc;
1293
1294 int
1295 result;
1296
1297 if (image_info->profile == (void *) NULL)
1298 {
1299 blob=DetachBlob(buff->blob);
1300 blob=(unsigned char *) RelinquishMagickMemory(blob);
1301 buff=DestroyImage(buff);
1302 ThrowReaderException(CoderError,"NoIPTCProfileAvailable");
1303 }
1304 profile=CloneStringInfo((StringInfo *) image_info->profile);
1305 iptc=AcquireImage((ImageInfo *) NULL,exception);
1306 if (iptc == (Image *) NULL)
1307 {
1308 blob=DetachBlob(buff->blob);
1309 blob=(unsigned char *) RelinquishMagickMemory(blob);
1310 buff=DestroyImage(buff);
1311 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1312 }
1313 AttachBlob(iptc->blob,GetStringInfoDatum(profile),
1314 GetStringInfoLength(profile));
1315 result=jpeg_embed(image,buff,iptc);
1316 blob=DetachBlob(iptc->blob);
1317 blob=(unsigned char *) RelinquishMagickMemory(blob);
1318 iptc=DestroyImage(iptc);
1319 if (result == 0)
1320 {
1321 buff=DestroyImage(buff);
1322 ThrowReaderException(CoderError,"JPEGEmbeddingFailed");
1323 }
1324 }
1325 else
1326 CopyBlob(image,buff);
1327 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
1328 GetBlobSize(buff));
1329 if (profile == (StringInfo *) NULL)
1330 {
1331 blob=DetachBlob(buff->blob);
1332 blob=(unsigned char *) RelinquishMagickMemory(blob);
1333 buff=DestroyImage(buff);
1334 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1335 }
1336 status=SetImageProfile(image,name,profile,exception);
1337 profile=DestroyStringInfo(profile);
1338 blob=DetachBlob(buff->blob);
1339 blob=(unsigned char *) RelinquishMagickMemory(blob);
1340 buff=DestroyImage(buff);
1341 if (status == MagickFalse)
1342 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1343 }
1344 if ((LocaleCompare(image_info->magick,"ICC") == 0) ||
1345 (LocaleCompare(image_info->magick,"ICM") == 0))
1346 {
1347 buff=AcquireImage((ImageInfo *) NULL,exception);
1348 if (buff == (Image *) NULL)
1349 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1350 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1351 if (blob == (unsigned char *) NULL)
1352 {
1353 buff=DestroyImage(buff);
1354 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1355 }
1356 AttachBlob(buff->blob,blob,length);
1357 CopyBlob(image,buff);
1358 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
1359 GetBlobSize(buff));
1360 if (profile == (StringInfo *) NULL)
1361 {
1362 blob=DetachBlob(buff->blob);
1363 blob=(unsigned char *) RelinquishMagickMemory(blob);
1364 buff=DestroyImage(buff);
1365 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1366 }
1367 (void) SetImageProfile(image,"icc",profile,exception);
1368 profile=DestroyStringInfo(profile);
1369 blob=DetachBlob(buff->blob);
1370 blob=(unsigned char *) RelinquishMagickMemory(blob);
1371 buff=DestroyImage(buff);
1372 }
1373 if (LocaleCompare(image_info->magick,"IPTC") == 0)
1374 {
1375 buff=AcquireImage((ImageInfo *) NULL,exception);
1376 if (buff == (Image *) NULL)
1377 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1378 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1379 if (blob == (unsigned char *) NULL)
1380 {
1381 buff=DestroyImage(buff);
1382 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1383 }
1384 AttachBlob(buff->blob,blob,length);
1385 CopyBlob(image,buff);
1386 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
1387 GetBlobSize(buff));
1388 if (profile == (StringInfo *) NULL)
1389 {
1390 blob=DetachBlob(buff->blob);
1391 blob=(unsigned char *) RelinquishMagickMemory(blob);
1392 buff=DestroyImage(buff);
1393 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1394 }
1395 (void) SetImageProfile(image,"8bim",profile,exception);
1396 profile=DestroyStringInfo(profile);
1397 blob=DetachBlob(buff->blob);
1398 blob=(unsigned char *) RelinquishMagickMemory(blob);
1399 buff=DestroyImage(buff);
1400 }
1401 if (LocaleCompare(image_info->magick,"XMP") == 0)
1402 {
1403 buff=AcquireImage((ImageInfo *) NULL,exception);
1404 if (buff == (Image *) NULL)
1405 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1406 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(unsigned char));
1407 if (blob == (unsigned char *) NULL)
1408 {
1409 buff=DestroyImage(buff);
1410 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1411 }
1412 AttachBlob(buff->blob,blob,length);
1413 CopyBlob(image,buff);
1414 profile=BlobToStringInfo(GetBlobStreamData(buff),(size_t)
1415 GetBlobSize(buff));
1416 if (profile == (StringInfo *) NULL)
1417 {
1418 blob=DetachBlob(buff->blob);
1419 blob=(unsigned char *) RelinquishMagickMemory(blob);
1420 buff=DestroyImage(buff);
1421 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1422 }
1423 (void) SetImageProfile(image,"xmp",profile,exception);
1424 profile=DestroyStringInfo(profile);
1425 blob=DetachBlob(buff->blob);
1426 blob=(unsigned char *) RelinquishMagickMemory(blob);
1427 buff=DestroyImage(buff);
1428 }
1429 (void) CloseBlob(image);
1430 return(GetFirstImageInList(image));
1431 }
1432
1433 /*
1434 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1435 % %
1436 % %
1437 % %
1438 % R e g i s t e r M E T A I m a g e %
1439 % %
1440 % %
1441 % %
1442 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1443 %
1444 % RegisterMETAImage() adds attributes for the META image format to
1445 % the list of supported formats. The attributes include the image format
1446 % tag, a method to read and/or write the format, whether the format
1447 % supports the saving of more than one frame to the same file or blob,
1448 % whether the format supports native in-memory I/O, and a brief
1449 % description of the format.
1450 %
1451 % The format of the RegisterMETAImage method is:
1452 %
1453 % size_t RegisterMETAImage(void)
1454 %
1455 */
RegisterMETAImage(void)1456 ModuleExport size_t RegisterMETAImage(void)
1457 {
1458 MagickInfo
1459 *entry;
1460
1461 entry=AcquireMagickInfo("META","8BIM","Photoshop resource format");
1462 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1463 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1464 entry->flags^=CoderAdjoinFlag;
1465 entry->flags|=CoderStealthFlag;
1466 entry->flags|=CoderDecoderSeekableStreamFlag;
1467 (void) RegisterMagickInfo(entry);
1468 entry=AcquireMagickInfo("META","8BIMTEXT","Photoshop resource text format");
1469 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1470 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1471 entry->flags^=CoderAdjoinFlag;
1472 entry->flags|=CoderStealthFlag;
1473 entry->flags|=CoderDecoderSeekableStreamFlag;
1474 (void) RegisterMagickInfo(entry);
1475 entry=AcquireMagickInfo("META","8BIMWTEXT",
1476 "Photoshop resource wide text format");
1477 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1478 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1479 entry->flags^=CoderAdjoinFlag;
1480 entry->flags|=CoderStealthFlag;
1481 entry->flags|=CoderDecoderSeekableStreamFlag;
1482 (void) RegisterMagickInfo(entry);
1483 entry=AcquireMagickInfo("META","APP1","Raw application information");
1484 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1485 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1486 entry->flags^=CoderAdjoinFlag;
1487 entry->flags|=CoderStealthFlag;
1488 entry->flags|=CoderDecoderSeekableStreamFlag;
1489 (void) RegisterMagickInfo(entry);
1490 entry=AcquireMagickInfo("META","APP1JPEG","Raw JPEG binary data");
1491 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1492 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1493 entry->flags^=CoderAdjoinFlag;
1494 entry->flags|=CoderStealthFlag;
1495 entry->flags|=CoderDecoderSeekableStreamFlag;
1496 (void) RegisterMagickInfo(entry);
1497 entry=AcquireMagickInfo("META","EXIF","Exif digital camera binary data");
1498 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1499 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1500 entry->flags^=CoderAdjoinFlag;
1501 entry->flags|=CoderStealthFlag;
1502 entry->flags|=CoderDecoderSeekableStreamFlag;
1503 (void) RegisterMagickInfo(entry);
1504 entry=AcquireMagickInfo("META","XMP","Adobe XML metadata");
1505 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1506 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1507 entry->flags^=CoderAdjoinFlag;
1508 entry->flags|=CoderStealthFlag;
1509 entry->flags|=CoderDecoderSeekableStreamFlag;
1510 (void) RegisterMagickInfo(entry);
1511 entry=AcquireMagickInfo("META","ICM","ICC Color Profile");
1512 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1513 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1514 entry->flags^=CoderAdjoinFlag;
1515 entry->flags|=CoderStealthFlag;
1516 entry->flags|=CoderDecoderSeekableStreamFlag;
1517 (void) RegisterMagickInfo(entry);
1518 entry=AcquireMagickInfo("META","ICC","ICC Color Profile");
1519 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1520 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1521 entry->flags^=CoderAdjoinFlag;
1522 entry->flags|=CoderStealthFlag;
1523 entry->flags|=CoderDecoderSeekableStreamFlag;
1524 (void) RegisterMagickInfo(entry);
1525 entry=AcquireMagickInfo("META","IPTC","IPTC Newsphoto");
1526 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1527 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1528 entry->flags^=CoderAdjoinFlag;
1529 entry->flags|=CoderStealthFlag;
1530 entry->flags|=CoderDecoderSeekableStreamFlag;
1531 (void) RegisterMagickInfo(entry);
1532 entry=AcquireMagickInfo("META","IPTCTEXT","IPTC Newsphoto text format");
1533 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1534 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1535 entry->flags^=CoderAdjoinFlag;
1536 entry->flags|=CoderStealthFlag;
1537 entry->flags|=CoderDecoderSeekableStreamFlag;
1538 (void) RegisterMagickInfo(entry);
1539 entry=AcquireMagickInfo("META","IPTCWTEXT","IPTC Newsphoto text format");
1540 entry->decoder=(DecodeImageHandler *) ReadMETAImage;
1541 entry->encoder=(EncodeImageHandler *) WriteMETAImage;
1542 entry->flags^=CoderAdjoinFlag;
1543 entry->flags|=CoderStealthFlag;
1544 entry->flags|=CoderDecoderSeekableStreamFlag;
1545 (void) RegisterMagickInfo(entry);
1546 return(MagickImageCoderSignature);
1547 }
1548
1549 /*
1550 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1551 % %
1552 % %
1553 % %
1554 % U n r e g i s t e r M E T A I m a g e %
1555 % %
1556 % %
1557 % %
1558 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1559 %
1560 % UnregisterMETAImage() removes format registrations made by the
1561 % META module from the list of supported formats.
1562 %
1563 % The format of the UnregisterMETAImage method is:
1564 %
1565 % UnregisterMETAImage(void)
1566 %
1567 */
UnregisterMETAImage(void)1568 ModuleExport void UnregisterMETAImage(void)
1569 {
1570 (void) UnregisterMagickInfo("8BIM");
1571 (void) UnregisterMagickInfo("8BIMTEXT");
1572 (void) UnregisterMagickInfo("8BIMWTEXT");
1573 (void) UnregisterMagickInfo("EXIF");
1574 (void) UnregisterMagickInfo("APP1");
1575 (void) UnregisterMagickInfo("APP1JPEG");
1576 (void) UnregisterMagickInfo("ICCTEXT");
1577 (void) UnregisterMagickInfo("ICM");
1578 (void) UnregisterMagickInfo("ICC");
1579 (void) UnregisterMagickInfo("IPTC");
1580 (void) UnregisterMagickInfo("IPTCTEXT");
1581 (void) UnregisterMagickInfo("IPTCWTEXT");
1582 (void) UnregisterMagickInfo("XMP");
1583 }
1584
1585 /*
1586 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1587 % %
1588 % %
1589 % %
1590 % W r i t e M E T A I m a g e %
1591 % %
1592 % %
1593 % %
1594 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1595 %
1596 % WriteMETAImage() writes a META image to a file.
1597 %
1598 % The format of the WriteMETAImage method is:
1599 %
1600 % MagickBooleanType WriteMETAImage(const ImageInfo *image_info,
1601 % Image *image,ExceptionInfo *exception)
1602 %
1603 % Compression code contributed by Kyle Shorter.
1604 %
1605 % A description of each parameter follows:
1606 %
1607 % o image_info: Specifies a pointer to an ImageInfo structure.
1608 %
1609 % o image: A pointer to a Image structure.
1610 %
1611 % o exception: return any errors or warnings in this structure.
1612 %
1613 */
1614
GetIPTCStream(unsigned char ** info,size_t length)1615 static size_t GetIPTCStream(unsigned char **info,size_t length)
1616 {
1617 int
1618 c;
1619
1620 register ssize_t
1621 i;
1622
1623 register unsigned char
1624 *p;
1625
1626 size_t
1627 extent,
1628 info_length;
1629
1630 unsigned int
1631 marker;
1632
1633 size_t
1634 tag_length;
1635
1636 p=(*info);
1637 extent=length;
1638 if ((*p == 0x1c) && (*(p+1) == 0x02))
1639 return(length);
1640 /*
1641 Extract IPTC from 8BIM resource block.
1642 */
1643 while (extent >= 12)
1644 {
1645 if (strncmp((const char *) p,"8BIM",4))
1646 break;
1647 p+=4;
1648 extent-=4;
1649 marker=(unsigned int) (*p) << 8 | *(p+1);
1650 p+=2;
1651 extent-=2;
1652 c=*p++;
1653 extent--;
1654 c|=0x01;
1655 if ((size_t) c >= extent)
1656 break;
1657 p+=c;
1658 extent-=c;
1659 if (extent < 4)
1660 break;
1661 tag_length=(((size_t) *p) << 24) | (((size_t) *(p+1)) << 16) |
1662 (((size_t) *(p+2)) << 8) | ((size_t) *(p+3));
1663 p+=4;
1664 extent-=4;
1665 if (tag_length > extent)
1666 break;
1667 if (marker == IPTC_ID)
1668 {
1669 *info=p;
1670 return(tag_length);
1671 }
1672 if ((tag_length & 0x01) != 0)
1673 tag_length++;
1674 p+=tag_length;
1675 extent-=tag_length;
1676 }
1677 /*
1678 Find the beginning of the IPTC info.
1679 */
1680 p=(*info);
1681 tag_length=0;
1682 iptc_find:
1683 info_length=0;
1684 marker=MagickFalse;
1685 while (length != 0)
1686 {
1687 c=(*p++);
1688 length--;
1689 if (length == 0)
1690 break;
1691 if (c == 0x1c)
1692 {
1693 p--;
1694 *info=p; /* let the caller know were it is */
1695 break;
1696 }
1697 }
1698 /*
1699 Determine the length of the IPTC info.
1700 */
1701 while (length != 0)
1702 {
1703 c=(*p++);
1704 length--;
1705 if (length == 0)
1706 break;
1707 if (c == 0x1c)
1708 marker=MagickTrue;
1709 else
1710 if (marker)
1711 break;
1712 else
1713 continue;
1714 info_length++;
1715 /*
1716 Found the 0x1c tag; skip the dataset and record number tags.
1717 */
1718 c=(*p++); /* should be 2 */
1719 length--;
1720 if (length == 0)
1721 break;
1722 if ((info_length == 1) && (c != 2))
1723 goto iptc_find;
1724 info_length++;
1725 c=(*p++); /* should be 0 */
1726 length--;
1727 if (length == 0)
1728 break;
1729 if ((info_length == 2) && (c != 0))
1730 goto iptc_find;
1731 info_length++;
1732 /*
1733 Decode the length of the block that follows - ssize_t or short format.
1734 */
1735 c=(*p++);
1736 length--;
1737 if (length == 0)
1738 break;
1739 info_length++;
1740 if ((c & 0x80) != 0)
1741 {
1742 /*
1743 Long format.
1744 */
1745 tag_length=0;
1746 for (i=0; i < 4; i++)
1747 {
1748 tag_length<<=8;
1749 tag_length|=(*p++);
1750 length--;
1751 if (length == 0)
1752 break;
1753 info_length++;
1754 }
1755 }
1756 else
1757 {
1758 /*
1759 Short format.
1760 */
1761 tag_length=((long) c) << 8;
1762 c=(*p++);
1763 length--;
1764 if (length == 0)
1765 break;
1766 info_length++;
1767 tag_length|=(long) c;
1768 }
1769 if (tag_length > (length+1))
1770 break;
1771 p+=tag_length;
1772 length-=tag_length;
1773 if (length == 0)
1774 break;
1775 info_length+=tag_length;
1776 }
1777 return(info_length);
1778 }
1779
formatString(Image * ofile,const char * s,int len)1780 static void formatString(Image *ofile, const char *s, int len)
1781 {
1782 char
1783 temp[MagickPathExtent];
1784
1785 (void) WriteBlobByte(ofile,'"');
1786 for (; len > 0; len--, s++) {
1787 int c = (*s) & 255;
1788 switch (c) {
1789 case '&':
1790 (void) WriteBlobString(ofile,"&");
1791 break;
1792 #ifdef HANDLE_GT_LT
1793 case '<':
1794 (void) WriteBlobString(ofile,"<");
1795 break;
1796 case '>':
1797 (void) WriteBlobString(ofile,">");
1798 break;
1799 #endif
1800 case '"':
1801 (void) WriteBlobString(ofile,""");
1802 break;
1803 default:
1804 if (isprint(c))
1805 (void) WriteBlobByte(ofile,(unsigned char) *s);
1806 else
1807 {
1808 (void) FormatLocaleString(temp,MagickPathExtent,"&#%d;", c & 255);
1809 (void) WriteBlobString(ofile,temp);
1810 }
1811 break;
1812 }
1813 }
1814 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1815 (void) WriteBlobString(ofile,"\"\r\n");
1816 #else
1817 #if defined(macintosh)
1818 (void) WriteBlobString(ofile,"\"\r");
1819 #else
1820 (void) WriteBlobString(ofile,"\"\n");
1821 #endif
1822 #endif
1823 }
1824
1825 typedef struct _tag_spec
1826 {
1827 const short
1828 id;
1829
1830 const char
1831 *name;
1832 } tag_spec;
1833
1834 static const tag_spec tags[] = {
1835 { 5, "Image Name" },
1836 { 7, "Edit Status" },
1837 { 10, "Priority" },
1838 { 15, "Category" },
1839 { 20, "Supplemental Category" },
1840 { 22, "Fixture Identifier" },
1841 { 25, "Keyword" },
1842 { 30, "Release Date" },
1843 { 35, "Release Time" },
1844 { 40, "Special Instructions" },
1845 { 45, "Reference Service" },
1846 { 47, "Reference Date" },
1847 { 50, "Reference Number" },
1848 { 55, "Created Date" },
1849 { 60, "Created Time" },
1850 { 65, "Originating Program" },
1851 { 70, "Program Version" },
1852 { 75, "Object Cycle" },
1853 { 80, "Byline" },
1854 { 85, "Byline Title" },
1855 { 90, "City" },
1856 { 92, "Sub-Location" },
1857 { 95, "Province State" },
1858 { 100, "Country Code" },
1859 { 101, "Country" },
1860 { 103, "Original Transmission Reference" },
1861 { 105, "Headline" },
1862 { 110, "Credit" },
1863 { 115, "Source" },
1864 { 116, "Copyright String" },
1865 { 120, "Caption" },
1866 { 121, "Image Orientation" },
1867 { 122, "Caption Writer" },
1868 { 131, "Local Caption" },
1869 { 200, "Custom Field 1" },
1870 { 201, "Custom Field 2" },
1871 { 202, "Custom Field 3" },
1872 { 203, "Custom Field 4" },
1873 { 204, "Custom Field 5" },
1874 { 205, "Custom Field 6" },
1875 { 206, "Custom Field 7" },
1876 { 207, "Custom Field 8" },
1877 { 208, "Custom Field 9" },
1878 { 209, "Custom Field 10" },
1879 { 210, "Custom Field 11" },
1880 { 211, "Custom Field 12" },
1881 { 212, "Custom Field 13" },
1882 { 213, "Custom Field 14" },
1883 { 214, "Custom Field 15" },
1884 { 215, "Custom Field 16" },
1885 { 216, "Custom Field 17" },
1886 { 217, "Custom Field 18" },
1887 { 218, "Custom Field 19" },
1888 { 219, "Custom Field 20" }
1889 };
1890
formatIPTC(Image * ifile,Image * ofile)1891 static int formatIPTC(Image *ifile, Image *ofile)
1892 {
1893 char
1894 temp[MagickPathExtent];
1895
1896 unsigned int
1897 foundiptc,
1898 tagsfound;
1899
1900 unsigned char
1901 recnum,
1902 dataset;
1903
1904 unsigned char
1905 *readable,
1906 *str;
1907
1908 ssize_t
1909 tagindx,
1910 taglen;
1911
1912 int
1913 i,
1914 tagcount = (int) (sizeof(tags) / sizeof(tag_spec));
1915
1916 int
1917 c;
1918
1919 foundiptc = 0; /* found the IPTC-Header */
1920 tagsfound = 0; /* number of tags found */
1921
1922 c = ReadBlobByte(ifile);
1923 while (c != EOF)
1924 {
1925 if (c == 0x1c)
1926 foundiptc = 1;
1927 else
1928 {
1929 if (foundiptc)
1930 return(-1);
1931 else
1932 {
1933 c=0;
1934 continue;
1935 }
1936 }
1937
1938 /* we found the 0x1c tag and now grab the dataset and record number tags */
1939 c = ReadBlobByte(ifile);
1940 if (c == EOF)
1941 return(-1);
1942 dataset = (unsigned char) c;
1943 c = ReadBlobByte(ifile);
1944 if (c == EOF)
1945 return(-1);
1946 recnum = (unsigned char) c;
1947 /* try to match this record to one of the ones in our named table */
1948 for (i=0; i< tagcount; i++)
1949 {
1950 if (tags[i].id == (short) recnum)
1951 break;
1952 }
1953 if (i < tagcount)
1954 readable = (unsigned char *) tags[i].name;
1955 else
1956 readable = (unsigned char *) "";
1957 /*
1958 We decode the length of the block that follows - ssize_t or short fmt.
1959 */
1960 c=ReadBlobByte(ifile);
1961 if (c == EOF)
1962 return(-1);
1963 if (c & (unsigned char) 0x80)
1964 return(0);
1965 else
1966 {
1967 int
1968 c0;
1969
1970 c0=ReadBlobByte(ifile);
1971 if (c0 == EOF)
1972 return(-1);
1973 taglen = (c << 8) | c0;
1974 }
1975 if (taglen < 0)
1976 return(-1);
1977 /* make a buffer to hold the tag datand snag it from the input stream */
1978 str=(unsigned char *) AcquireQuantumMemory((size_t) (taglen+
1979 MagickPathExtent),sizeof(*str));
1980 if (str == (unsigned char *) NULL)
1981 return(0);
1982 for (tagindx=0; tagindx<taglen; tagindx++)
1983 {
1984 c=ReadBlobByte(ifile);
1985 if (c == EOF)
1986 {
1987 str=(unsigned char *) RelinquishMagickMemory(str);
1988 return(-1);
1989 }
1990 str[tagindx] = (unsigned char) c;
1991 }
1992 str[taglen] = 0;
1993
1994 /* now finish up by formatting this binary data into ASCII equivalent */
1995 if (strlen((char *)readable) > 0)
1996 (void) FormatLocaleString(temp,MagickPathExtent,"%d#%d#%s=",
1997 (unsigned int) dataset, (unsigned int) recnum, readable);
1998 else
1999 (void) FormatLocaleString(temp,MagickPathExtent,"%d#%d=",
2000 (unsigned int) dataset,(unsigned int) recnum);
2001 (void) WriteBlobString(ofile,temp);
2002 formatString( ofile, (char *)str, taglen );
2003 str=(unsigned char *) RelinquishMagickMemory(str);
2004
2005 tagsfound++;
2006
2007 c=ReadBlobByte(ifile);
2008 }
2009 return((int) tagsfound);
2010 }
2011
readWordFromBuffer(char ** s,ssize_t * len)2012 static int readWordFromBuffer(char **s, ssize_t *len)
2013 {
2014 unsigned char
2015 buffer[2];
2016
2017 int
2018 i,
2019 c;
2020
2021 for (i=0; i<2; i++)
2022 {
2023 c = *(*s)++; (*len)--;
2024 if (*len < 0) return -1;
2025 buffer[i] = (unsigned char) c;
2026 }
2027 return (((int) buffer[ 0 ]) << 8) |
2028 (((int) buffer[ 1 ]));
2029 }
2030
formatIPTCfromBuffer(Image * ofile,char * s,ssize_t len)2031 static int formatIPTCfromBuffer(Image *ofile, char *s, ssize_t len)
2032 {
2033 char
2034 temp[MagickPathExtent];
2035
2036 unsigned int
2037 foundiptc,
2038 tagsfound;
2039
2040 unsigned char
2041 recnum,
2042 dataset;
2043
2044 unsigned char
2045 *readable,
2046 *str;
2047
2048 ssize_t
2049 tagindx,
2050 taglen;
2051
2052 int
2053 i,
2054 tagcount = (int) (sizeof(tags) / sizeof(tag_spec));
2055
2056 int
2057 c;
2058
2059 foundiptc = 0; /* found the IPTC-Header */
2060 tagsfound = 0; /* number of tags found */
2061
2062 while (len > 0)
2063 {
2064 c = *s++; len--;
2065 if (c == 0x1c)
2066 foundiptc = 1;
2067 else
2068 {
2069 if (foundiptc)
2070 return -1;
2071 else
2072 continue;
2073 }
2074 /*
2075 We found the 0x1c tag and now grab the dataset and record number tags.
2076 */
2077 c = *s++; len--;
2078 if (len < 0) return -1;
2079 dataset = (unsigned char) c;
2080 c = *s++; len--;
2081 if (len < 0) return -1;
2082 recnum = (unsigned char) c;
2083 /* try to match this record to one of the ones in our named table */
2084 for (i=0; i< tagcount; i++)
2085 if (tags[i].id == (short) recnum)
2086 break;
2087 if (i < tagcount)
2088 readable=(unsigned char *) tags[i].name;
2089 else
2090 readable=(unsigned char *) "";
2091 /*
2092 We decode the length of the block that follows - ssize_t or short fmt.
2093 */
2094 c=(*s++);
2095 len--;
2096 if (len < 0)
2097 return(-1);
2098 if (c & (unsigned char) 0x80)
2099 return(0);
2100 else
2101 {
2102 s--;
2103 len++;
2104 taglen=readWordFromBuffer(&s, &len);
2105 }
2106 if (taglen < 0)
2107 return(-1);
2108 if (taglen > 65535)
2109 return(-1);
2110 /* make a buffer to hold the tag datand snag it from the input stream */
2111 str=(unsigned char *) AcquireQuantumMemory((size_t) (taglen+
2112 MagickPathExtent),sizeof(*str));
2113 if (str == (unsigned char *) NULL)
2114 {
2115 (void) printf("MemoryAllocationFailed");
2116 return 0;
2117 }
2118 for (tagindx=0; tagindx<taglen; tagindx++)
2119 {
2120 c = *s++; len--;
2121 if (len < 0)
2122 {
2123 str=(unsigned char *) RelinquishMagickMemory(str);
2124 return(-1);
2125 }
2126 str[tagindx]=(unsigned char) c;
2127 }
2128 str[taglen]=0;
2129
2130 /* now finish up by formatting this binary data into ASCII equivalent */
2131 if (strlen((char *)readable) > 0)
2132 (void) FormatLocaleString(temp,MagickPathExtent,"%d#%d#%s=",
2133 (unsigned int) dataset,(unsigned int) recnum, readable);
2134 else
2135 (void) FormatLocaleString(temp,MagickPathExtent,"%d#%d=",
2136 (unsigned int) dataset,(unsigned int) recnum);
2137 (void) WriteBlobString(ofile,temp);
2138 formatString( ofile, (char *)str, taglen );
2139 str=(unsigned char *) RelinquishMagickMemory(str);
2140
2141 tagsfound++;
2142 }
2143 return ((int) tagsfound);
2144 }
2145
format8BIM(Image * ifile,Image * ofile)2146 static int format8BIM(Image *ifile, Image *ofile)
2147 {
2148 char
2149 temp[MagickPathExtent];
2150
2151 unsigned int
2152 foundOSType;
2153
2154 int
2155 ID,
2156 resCount,
2157 i,
2158 c;
2159
2160 ssize_t
2161 count;
2162
2163 unsigned char
2164 *PString,
2165 *str;
2166
2167 resCount=0;
2168 foundOSType=0; /* found the OSType */
2169 (void) foundOSType;
2170 c=ReadBlobByte(ifile);
2171 while (c != EOF)
2172 {
2173 if (c == '8')
2174 {
2175 unsigned char
2176 buffer[5];
2177
2178 buffer[0]=(unsigned char) c;
2179 for (i=1; i<4; i++)
2180 {
2181 c=ReadBlobByte(ifile);
2182 if (c == EOF)
2183 return(-1);
2184 buffer[i] = (unsigned char) c;
2185 }
2186 buffer[4]=0;
2187 if (strcmp((const char *)buffer, "8BIM") == 0)
2188 foundOSType=1;
2189 else
2190 continue;
2191 }
2192 else
2193 {
2194 c=ReadBlobByte(ifile);
2195 continue;
2196 }
2197 /*
2198 We found the OSType (8BIM) and now grab the ID, PString, and Size fields.
2199 */
2200 ID=ReadBlobMSBSignedShort(ifile);
2201 if (ID < 0)
2202 return(-1);
2203 {
2204 unsigned char
2205 plen;
2206
2207 c=ReadBlobByte(ifile);
2208 if (c == EOF)
2209 return(-1);
2210 plen = (unsigned char) c;
2211 PString=(unsigned char *) AcquireQuantumMemory((size_t) (plen+
2212 MagickPathExtent),sizeof(*PString));
2213 if (PString == (unsigned char *) NULL)
2214 return 0;
2215 for (i=0; i<plen; i++)
2216 {
2217 c=ReadBlobByte(ifile);
2218 if (c == EOF)
2219 {
2220 PString=(unsigned char *) RelinquishMagickMemory(PString);
2221 return -1;
2222 }
2223 PString[i] = (unsigned char) c;
2224 }
2225 PString[ plen ] = 0;
2226 if ((plen & 0x01) == 0)
2227 {
2228 c=ReadBlobByte(ifile);
2229 if (c == EOF)
2230 {
2231 PString=(unsigned char *) RelinquishMagickMemory(PString);
2232 return -1;
2233 }
2234 }
2235 }
2236 count=(ssize_t) ReadBlobMSBSignedLong(ifile);
2237 if ((count < 0) || (count > (ssize_t) GetBlobSize(ifile)))
2238 {
2239 PString=(unsigned char *) RelinquishMagickMemory(PString);
2240 return -1;
2241 }
2242 /* make a buffer to hold the data and snag it from the input stream */
2243 str=(unsigned char *) AcquireQuantumMemory((size_t) count+1,sizeof(*str));
2244 if (str == (unsigned char *) NULL)
2245 {
2246 PString=(unsigned char *) RelinquishMagickMemory(PString);
2247 return 0;
2248 }
2249 for (i=0; i < (ssize_t) count; i++)
2250 {
2251 c=ReadBlobByte(ifile);
2252 if (c == EOF)
2253 {
2254 str=(unsigned char *) RelinquishMagickMemory(str);
2255 PString=(unsigned char *) RelinquishMagickMemory(PString);
2256 return -1;
2257 }
2258 str[i]=(unsigned char) c;
2259 }
2260
2261 /* we currently skip thumbnails, since it does not make
2262 * any sense preserving them in a real world application
2263 */
2264 if (ID != THUMBNAIL_ID)
2265 {
2266 /* now finish up by formatting this binary data into
2267 * ASCII equivalent
2268 */
2269 if (strlen((const char *)PString) > 0)
2270 (void) FormatLocaleString(temp,MagickPathExtent,"8BIM#%d#%s=",ID,
2271 PString);
2272 else
2273 (void) FormatLocaleString(temp,MagickPathExtent,"8BIM#%d=",ID);
2274 (void) WriteBlobString(ofile,temp);
2275 if (ID == IPTC_ID)
2276 {
2277 formatString(ofile, "IPTC", 4);
2278 formatIPTCfromBuffer(ofile, (char *)str, (ssize_t) count);
2279 }
2280 else
2281 formatString(ofile, (char *)str, (ssize_t) count);
2282 }
2283 str=(unsigned char *) RelinquishMagickMemory(str);
2284 PString=(unsigned char *) RelinquishMagickMemory(PString);
2285 resCount++;
2286 c=ReadBlobByte(ifile);
2287 }
2288 return resCount;
2289 }
2290
WriteMETAImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)2291 static MagickBooleanType WriteMETAImage(const ImageInfo *image_info,
2292 Image *image,ExceptionInfo *exception)
2293 {
2294 const StringInfo
2295 *profile;
2296
2297 MagickBooleanType
2298 status;
2299
2300 size_t
2301 length;
2302
2303 /*
2304 Open image file.
2305 */
2306 assert(image_info != (const ImageInfo *) NULL);
2307 assert(image_info->signature == MagickCoreSignature);
2308 assert(image != (Image *) NULL);
2309 assert(image->signature == MagickCoreSignature);
2310 if (image->debug != MagickFalse)
2311 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2312 length=0;
2313 if (LocaleCompare(image_info->magick,"8BIM") == 0)
2314 {
2315 /*
2316 Write 8BIM image.
2317 */
2318 profile=GetImageProfile(image,"8bim");
2319 if (profile == (StringInfo *) NULL)
2320 ThrowWriterException(CoderError,"No8BIMDataIsAvailable");
2321 assert(exception != (ExceptionInfo *) NULL);
2322 assert(exception->signature == MagickCoreSignature);
2323 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2324 if (status == MagickFalse)
2325 return(status);
2326 (void) WriteBlob(image,GetStringInfoLength(profile),
2327 GetStringInfoDatum(profile));
2328 (void) CloseBlob(image);
2329 return(MagickTrue);
2330 }
2331 if (LocaleCompare(image_info->magick,"iptc") == 0)
2332 {
2333 size_t
2334 length;
2335
2336 unsigned char
2337 *info;
2338
2339 profile=GetImageProfile(image,"iptc");
2340 if (profile == (StringInfo *) NULL)
2341 profile=GetImageProfile(image,"8bim");
2342 if (profile == (StringInfo *) NULL)
2343 ThrowWriterException(CoderError,"No8BIMDataIsAvailable");
2344 assert(exception != (ExceptionInfo *) NULL);
2345 assert(exception->signature == MagickCoreSignature);
2346 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2347 info=GetStringInfoDatum(profile);
2348 length=GetStringInfoLength(profile);
2349 length=GetIPTCStream(&info,length);
2350 if (length == 0)
2351 ThrowWriterException(CoderError,"NoIPTCProfileAvailable");
2352 (void) WriteBlob(image,length,info);
2353 (void) CloseBlob(image);
2354 return(MagickTrue);
2355 }
2356 if (LocaleCompare(image_info->magick,"8BIMTEXT") == 0)
2357 {
2358 Image
2359 *buff;
2360
2361 profile=GetImageProfile(image,"8bim");
2362 if (profile == (StringInfo *) NULL)
2363 ThrowWriterException(CoderError,"No8BIMDataIsAvailable");
2364 assert(exception != (ExceptionInfo *) NULL);
2365 assert(exception->signature == MagickCoreSignature);
2366 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2367 if (status == MagickFalse)
2368 return(status);
2369 buff=AcquireImage((ImageInfo *) NULL,exception);
2370 if (buff == (Image *) NULL)
2371 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2372 AttachBlob(buff->blob,GetStringInfoDatum(profile),
2373 GetStringInfoLength(profile));
2374 format8BIM(buff,image);
2375 (void) DetachBlob(buff->blob);
2376 buff=DestroyImage(buff);
2377 (void) CloseBlob(image);
2378 return(MagickTrue);
2379 }
2380 if (LocaleCompare(image_info->magick,"8BIMWTEXT") == 0)
2381 return(MagickFalse);
2382 if (LocaleCompare(image_info->magick,"IPTCTEXT") == 0)
2383 {
2384 Image
2385 *buff;
2386
2387 unsigned char
2388 *info;
2389
2390 profile=GetImageProfile(image,"8bim");
2391 if (profile == (StringInfo *) NULL)
2392 ThrowWriterException(CoderError,"No8BIMDataIsAvailable");
2393 info=GetStringInfoDatum(profile);
2394 length=GetStringInfoLength(profile);
2395 length=GetIPTCStream(&info,length);
2396 if (length == 0)
2397 ThrowWriterException(CoderError,"NoIPTCProfileAvailable");
2398 assert(exception != (ExceptionInfo *) NULL);
2399 assert(exception->signature == MagickCoreSignature);
2400 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2401 if (status == MagickFalse)
2402 return(status);
2403 buff=AcquireImage((ImageInfo *) NULL,exception);
2404 if (buff == (Image *) NULL)
2405 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2406 AttachBlob(buff->blob,info,length);
2407 formatIPTC(buff,image);
2408 (void) DetachBlob(buff->blob);
2409 buff=DestroyImage(buff);
2410 (void) CloseBlob(image);
2411 return(MagickTrue);
2412 }
2413 if (LocaleCompare(image_info->magick,"IPTCWTEXT") == 0)
2414 return(MagickFalse);
2415 if ((LocaleCompare(image_info->magick,"APP1") == 0) ||
2416 (LocaleCompare(image_info->magick,"EXIF") == 0) ||
2417 (LocaleCompare(image_info->magick,"XMP") == 0))
2418 {
2419 /*
2420 (void) Write APP1 image.
2421 */
2422 profile=GetImageProfile(image,image_info->magick);
2423 if (profile == (StringInfo *) NULL)
2424 ThrowWriterException(CoderError,"NoAPP1DataIsAvailable");
2425 assert(exception != (ExceptionInfo *) NULL);
2426 assert(exception->signature == MagickCoreSignature);
2427 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2428 if (status == MagickFalse)
2429 return(status);
2430 (void) WriteBlob(image,GetStringInfoLength(profile),
2431 GetStringInfoDatum(profile));
2432 (void) CloseBlob(image);
2433 return(MagickTrue);
2434 }
2435 if ((LocaleCompare(image_info->magick,"ICC") == 0) ||
2436 (LocaleCompare(image_info->magick,"ICM") == 0))
2437 {
2438 /*
2439 Write ICM image.
2440 */
2441 profile=GetImageProfile(image,"icc");
2442 if (profile == (StringInfo *) NULL)
2443 ThrowWriterException(CoderError,"NoColorProfileIsAvailable");
2444 assert(exception != (ExceptionInfo *) NULL);
2445 assert(exception->signature == MagickCoreSignature);
2446 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2447 if (status == MagickFalse)
2448 return(status);
2449 (void) WriteBlob(image,GetStringInfoLength(profile),
2450 GetStringInfoDatum(profile));
2451 (void) CloseBlob(image);
2452 return(MagickTrue);
2453 }
2454 return(MagickFalse);
2455 }
2456