1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                            SSSSS  FFFFF  W   W                              %
7 %                            SS     F      W   W                              %
8 %                             SSS   FFF    W   W                              %
9 %                               SS  F      W W W                              %
10 %                            SSSSS  F       W W                               %
11 %                                                                             %
12 %                                                                             %
13 %                    Read/Write ImageMagick Image Format                      %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                   Cristy                                    %
17 %                                 July 1992                                   %
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/constitute.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/resource_.h"
54 #include "MagickCore/quantum-private.h"
55 #include "MagickCore/static.h"
56 #include "MagickCore/string_.h"
57 #include "MagickCore/module.h"
58 #include "MagickCore/transform.h"
59 #include "MagickCore/utility.h"
60 #include "MagickCore/utility-private.h"
61 
62 /*
63 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
64 %                                                                             %
65 %                                                                             %
66 %                                                                             %
67 %   I s S F W                                                                 %
68 %                                                                             %
69 %                                                                             %
70 %                                                                             %
71 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
72 %
73 %  IsSFW() returns MagickTrue if the image format type, identified by the
74 %  magick string, is SFW.
75 %
76 %  The format of the IsSFW method is:
77 %
78 %      MagickBooleanType IsSFW(const unsigned char *magick,const size_t length)
79 %
80 %  A description of each parameter follows:
81 %
82 %    o magick: compare image format pattern against these bytes.
83 %
84 %    o length: Specifies the length of the magick string.
85 %
86 */
IsSFW(const unsigned char * magick,const size_t length)87 static MagickBooleanType IsSFW(const unsigned char *magick,const size_t length)
88 {
89   if (length < 5)
90     return(MagickFalse);
91   if (LocaleNCompare((const char *) magick,"SFW94",5) == 0)
92     return(MagickTrue);
93   return(MagickFalse);
94 }
95 
96 /*
97 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
98 %                                                                             %
99 %                                                                             %
100 %                                                                             %
101 %   R e a d S F W I m a g e                                                   %
102 %                                                                             %
103 %                                                                             %
104 %                                                                             %
105 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
106 %
107 %  ReadSFWImage() reads a Seattle Film Works image file and returns it.
108 %  It allocates the memory necessary for the new Image structure and returns a
109 %  pointer to the new image.
110 %
111 %  The format of the ReadSFWImage method is:
112 %
113 %      Image *ReadSFWImage(const ImageInfo *image_info,ExceptionInfo *exception)
114 %
115 %  A description of each parameter follows:
116 %
117 %    o image_info: the image info.
118 %
119 %    o exception: return any errors or warnings in this structure.
120 %
121 */
122 
SFWScan(const unsigned char * p,const unsigned char * q,const unsigned char * target,const size_t length)123 static unsigned char *SFWScan(const unsigned char *p,const unsigned char *q,
124   const unsigned char *target,const size_t length)
125 {
126   register ssize_t
127     i;
128 
129   while ((p+length) < q)
130   {
131     for (i=0; i < (ssize_t) length; i++)
132       if (p[i] != target[i])
133         break;
134     if (i == (ssize_t) length)
135       return((unsigned char *) p);
136     p++;
137   }
138   return((unsigned char *) NULL);
139 }
140 
TranslateSFWMarker(unsigned char * marker)141 static void TranslateSFWMarker(unsigned char *marker)
142 {
143   switch (marker[1])
144   {
145     case 0xc8: marker[1]=0xd8; break;  /* soi */
146     case 0xd0: marker[1]=0xe0; break;  /* app */
147     case 0xcb: marker[1]=0xdb; break;  /* dqt */
148     case 0xa0: marker[1]=0xc0; break;  /* sof */
149     case 0xa4: marker[1]=0xc4; break;  /* sof */
150     case 0xca: marker[1]=0xda; break;  /* sos */
151     case 0xc9: marker[1]=0xd9; break;  /* eoi */
152     default: break;
153   }
154 }
155 
ReadSFWImage(const ImageInfo * image_info,ExceptionInfo * exception)156 static Image *ReadSFWImage(const ImageInfo *image_info,ExceptionInfo *exception)
157 {
158   static unsigned char
159     HuffmanTable[] =
160     {
161       0xFF, 0xC4, 0x01, 0xA2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01,
162       0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
163       0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
164       0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
165       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04,
166       0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x10, 0x00, 0x02, 0x01,
167       0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00,
168       0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21,
169       0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32,
170       0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1,
171       0xF0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18,
172       0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36,
173       0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
174       0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64,
175       0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77,
176       0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A,
177       0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3,
178       0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5,
179       0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
180       0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9,
181       0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA,
182       0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0x11,
183       0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04,
184       0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04,
185       0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13,
186       0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09,
187       0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24,
188       0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28,
189       0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45,
190       0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
191       0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73,
192       0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85,
193       0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
194       0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9,
195       0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2,
196       0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4,
197       0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
198       0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
199       0xF9, 0xFA
200     };
201 
202   FILE
203     *file;
204 
205   Image
206     *flipped_image,
207     *jpeg_image,
208     *image;
209 
210   ImageInfo
211     *read_info;
212 
213   int
214     unique_file;
215 
216   MagickBooleanType
217     status;
218 
219   register unsigned char
220     *header,
221     *data;
222 
223   size_t
224     extent;
225 
226   ssize_t
227     count;
228 
229   unsigned char
230     *buffer,
231     *offset;
232 
233   /*
234     Open image file.
235   */
236   assert(image_info != (const ImageInfo *) NULL);
237   assert(image_info->signature == MagickCoreSignature);
238   if (image_info->debug != MagickFalse)
239     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
240       image_info->filename);
241   assert(exception != (ExceptionInfo *) NULL);
242   assert(exception->signature == MagickCoreSignature);
243   image=AcquireImage(image_info,exception);
244   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
245   if (status == MagickFalse)
246     {
247       image=DestroyImageList(image);
248       return((Image *) NULL);
249     }
250   /*
251     Read image into a buffer.
252   */
253   if (GetBlobSize(image) != (size_t) GetBlobSize(image))
254     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
255   if (GetBlobSize(image) < 141)
256     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
257   buffer=(unsigned char *) AcquireQuantumMemory((size_t) GetBlobSize(image)+
258     MagickPathExtent,sizeof(*buffer));
259   if (buffer == (unsigned char *) NULL)
260     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
261   count=ReadBlob(image,(size_t) GetBlobSize(image),buffer);
262   if ((count != (ssize_t) GetBlobSize(image)) ||
263       (LocaleNCompare((char *) buffer,"SFW",3) != 0))
264     {
265       buffer=(unsigned char *) RelinquishMagickMemory(buffer);
266       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
267     }
268   (void) CloseBlob(image);
269   /*
270     Find the start of the JFIF data
271   */
272   header=SFWScan(buffer,buffer+count-1,(const unsigned char *)
273     "\377\310\377\320",4);
274   if ((header == (unsigned char *) NULL) ||
275       ((header+140) > (buffer+GetBlobSize(image))))
276     {
277       buffer=(unsigned char *) RelinquishMagickMemory(buffer);
278       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
279     }
280   TranslateSFWMarker(header);  /* translate soi and app tags */
281   TranslateSFWMarker(header+2);
282   (void) memcpy(header+6,"JFIF\0\001\0",7);  /* JFIF magic */
283   /*
284     Translate remaining markers.
285   */
286   offset=header+2;
287   offset+=(((unsigned int) offset[2]) << 8)+offset[3]+2;
288   for ( ; ; )
289   {
290     if ((offset+4) > (buffer+count-1))
291       {
292         buffer=(unsigned char *) RelinquishMagickMemory(buffer);
293         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
294       }
295     TranslateSFWMarker(offset);
296     if (offset[1] == 0xda)
297       break;
298     offset+=(((unsigned int) offset[2]) << 8)+offset[3]+2;
299   }
300   offset--;
301   data=SFWScan(offset,buffer+count-1,(const unsigned char *) "\377\311",2);
302   if (data == (unsigned char *) NULL)
303     {
304       buffer=(unsigned char *) RelinquishMagickMemory(buffer);
305       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
306     }
307   TranslateSFWMarker(data++);  /* translate eoi marker */
308   /*
309     Write JFIF file.
310   */
311   read_info=CloneImageInfo(image_info);
312   SetImageInfoBlob(read_info,(void *) NULL,0);
313   file=(FILE *) NULL;
314   unique_file=AcquireUniqueFileResource(read_info->filename);
315   if (unique_file != -1)
316     file=fopen_utf8(read_info->filename,"wb");
317   if ((unique_file == -1) || (file == (FILE *) NULL))
318     {
319       buffer=(unsigned char *) RelinquishMagickMemory(buffer);
320       read_info=DestroyImageInfo(read_info);
321       (void) CopyMagickString(image->filename,read_info->filename,
322         MagickPathExtent);
323       ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
324         image->filename);
325       image=DestroyImageList(image);
326       return((Image *) NULL);
327     }
328   extent=fwrite(header,(size_t) (offset-header+1),1,file);
329   (void) extent;
330   extent=fwrite(HuffmanTable,1,sizeof(HuffmanTable)/sizeof(*HuffmanTable),file);
331   extent=fwrite(offset+1,(size_t) (data-offset),1,file);
332   status=ferror(file) != 0 ? MagickFalse : MagickTrue;
333   (void) fclose(file);
334   (void) close(unique_file);
335   buffer=(unsigned char *) RelinquishMagickMemory(buffer);
336   if (status == MagickFalse)
337     {
338       char
339         *message;
340 
341       (void) remove_utf8(read_info->filename);
342       read_info=DestroyImageInfo(read_info);
343       message=GetExceptionMessage(errno);
344       (void) ThrowMagickException(exception,GetMagickModule(),FileOpenError,
345         "UnableToWriteFile","`%s': %s",image->filename,message);
346       message=DestroyString(message);
347       image=DestroyImageList(image);
348       return((Image *) NULL);
349     }
350   /*
351     Read JPEG image.
352   */
353   (void) CopyMagickString(read_info->magick,"JPEG",MagickPathExtent);
354   jpeg_image=ReadImage(read_info,exception);
355   (void) RelinquishUniqueFileResource(read_info->filename);
356   read_info=DestroyImageInfo(read_info);
357   if (jpeg_image == (Image *) NULL)
358     {
359       image=DestroyImageList(image);
360       return(jpeg_image);
361     }
362   (void) CopyMagickString(jpeg_image->filename,image->filename,
363     MagickPathExtent);
364   (void) CopyMagickString(jpeg_image->magick,image->magick,MagickPathExtent);
365   image=DestroyImageList(image);
366   image=jpeg_image;
367   /*
368     Correct image orientation.
369   */
370   flipped_image=FlipImage(image,exception);
371   if (flipped_image != (Image *) NULL)
372     {
373       DuplicateBlob(flipped_image,image);
374       image=DestroyImage(image);
375       image=flipped_image;
376     }
377   return(GetFirstImageInList(image));
378 }
379 
380 /*
381 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
382 %                                                                             %
383 %                                                                             %
384 %                                                                             %
385 %   R e g i s t e r S F W I m a g e                                           %
386 %                                                                             %
387 %                                                                             %
388 %                                                                             %
389 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
390 %
391 %  RegisterSFWImage() adds attributes for the SFW image format to
392 %  the list of supported formats.  The attributes include the image format
393 %  tag, a method to read and/or write the format, whether the format
394 %  supports the saving of more than one frame to the same file or blob,
395 %  whether the format supports native in-memory I/O, and a brief
396 %  description of the format.
397 %
398 %  The format of the RegisterSFWImage method is:
399 %
400 %      size_t RegisterSFWImage(void)
401 %
402 */
RegisterSFWImage(void)403 ModuleExport size_t RegisterSFWImage(void)
404 {
405   MagickInfo
406     *entry;
407 
408   entry=AcquireMagickInfo("SFW","SFW","Seattle Film Works");
409   entry->decoder=(DecodeImageHandler *) ReadSFWImage;
410   entry->magick=(IsImageFormatHandler *) IsSFW;
411   entry->flags|=CoderDecoderSeekableStreamFlag;
412   entry->flags^=CoderAdjoinFlag;
413   (void) RegisterMagickInfo(entry);
414   return(MagickImageCoderSignature);
415 }
416 
417 /*
418 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
419 %                                                                             %
420 %                                                                             %
421 %                                                                             %
422 %   U n r e g i s t e r S F W I m a g e                                       %
423 %                                                                             %
424 %                                                                             %
425 %                                                                             %
426 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
427 %
428 %  UnregisterSFWImage() removes format registrations made by the
429 %  SFW module from the list of supported formats.
430 %
431 %  The format of the UnregisterSFWImage method is:
432 %
433 %      UnregisterSFWImage(void)
434 %
435 */
UnregisterSFWImage(void)436 ModuleExport void UnregisterSFWImage(void)
437 {
438   (void) UnregisterMagickInfo("SFW");
439 }
440