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