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