• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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,"&lt;",'<' },
157   { 4,"&gt;",'>' },
158 #endif
159   { 5,"&amp;",'&' },
160   { 6,"&quot;",'"' },
161   { 6,"&apos;",'\''}
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,&quoted)==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,&quoted)==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,&quoted)==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,&quoted)==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,&quoted)==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,&quoted)==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,"&amp;");
1791       break;
1792 #ifdef HANDLE_GT_LT
1793     case '<':
1794       (void) WriteBlobString(ofile,"&lt;");
1795       break;
1796     case '>':
1797       (void) WriteBlobString(ofile,"&gt;");
1798       break;
1799 #endif
1800     case '"':
1801       (void) WriteBlobString(ofile,"&quot;");
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