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