--- old/Source/FreeImage/PluginTIFF.cpp +++ new/Source/FreeImage/PluginTIFF.cpp @@ -122,9 +122,14 @@ static int s_format_id; typedef struct { + //! FreeImage IO functions FreeImageIO *io; + //! FreeImage handle fi_handle handle; + //! LibTIFF handle TIFF *tif; + //! Count the number of thumbnails already read (used to avoid recursion on loading) + unsigned thumbnailCount; } fi_TIFFIO; // ---------------------------------------------------------- @@ -184,10 +189,8 @@ */ TIFF * TIFFFdOpen(thandle_t handle, const char *name, const char *mode) { - TIFF *tif; - // Open the file; the callback will set everything up - tif = TIFFClientOpen(name, mode, handle, + TIFF *tif = TIFFClientOpen(name, mode, handle, _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc, _tiffSizeProc, _tiffMapProc, _tiffUnmapProc); @@ -460,9 +463,8 @@ } } - else { - - dib = FreeImage_AllocateHeader(header_only, width, height, MIN(bpp, 32), FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); + else if (bpp <= 32) { + dib = FreeImage_AllocateHeader(header_only, width, height, bpp, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); } @@ -1050,9 +1052,12 @@ Open(FreeImageIO *io, fi_handle handle, BOOL read) { // wrapper for TIFF I/O fi_TIFFIO *fio = (fi_TIFFIO*)malloc(sizeof(fi_TIFFIO)); - if(!fio) return NULL; + if (!fio) { + return NULL; + } fio->io = io; fio->handle = handle; + fio->thumbnailCount = 0; if (read) { fio->tif = TIFFFdOpen((thandle_t)fio, "", "r"); @@ -1108,7 +1113,28 @@ */ static BOOL IsValidBitsPerSample(uint16 photometric, uint16 bitspersample, uint16 samplesperpixel) { + // get the pixel depth in bits + const uint16 pixel_depth = bitspersample * samplesperpixel; + // check for a supported pixel depth + switch (pixel_depth) { + case 1: + case 4: + case 8: + case 16: + case 24: + case 32: + case 48: + case 64: + case 96: + case 128: + // OK, go on + break; + default: + // unsupported pixel depth + return FALSE; + } + switch(bitspersample) { case 1: case 4: @@ -1148,6 +1174,8 @@ default: return FALSE; } + + return FALSE; } static TIFFLoadMethod @@ -1237,16 +1265,31 @@ static void ReadThumbnail(FreeImageIO *io, fi_handle handle, void *data, TIFF *tiff, FIBITMAP *dib) { FIBITMAP* thumbnail = NULL; + + fi_TIFFIO *fio = (fi_TIFFIO*)data; + + /* + Thumbnail loading can cause recursions because of the way + functions TIFFLastDirectory and TIFFSetSubDirectory are working. + We use here a hack to count the number of times the ReadThumbnail function was called. + We only allow one call, check for this + */ + if (fio->thumbnailCount > 0) { + return; + } + else { + // update the thumbnail count (used to avoid recursion) + fio->thumbnailCount++; + } // read exif thumbnail (IFD 1) ... - /* - // this code can cause unwanted recursion causing an overflow, it is thus disabled until we have a better solution - // do we really need to read a thumbnail from the Exif segment ? knowing that TIFF store the thumbnail in the subIFD ... - // toff_t exif_offset = 0; if(TIFFGetField(tiff, TIFFTAG_EXIFIFD, &exif_offset)) { + // this code can cause unwanted recursion causing an overflow, because of the way TIFFLastDirectory work + // => this is checked using + if(!TIFFLastDirectory(tiff)) { // save current position const long tell_pos = io->tell_proc(handle); @@ -1264,7 +1307,6 @@ TIFFSetDirectory(tiff, cur_dir); } } - */ // ... or read the first subIFD @@ -1281,6 +1323,8 @@ const long tell_pos = io->tell_proc(handle); const uint16 cur_dir = TIFFCurrentDirectory(tiff); + // this code can cause unwanted recursion causing an overflow, because of the way TIFFSetSubDirectory work + if(TIFFSetSubDirectory(tiff, subIFD_offsets[0])) { // load the thumbnail int page = -1; @@ -2041,7 +2085,7 @@ } // calculate src line and dst pitch - int dst_pitch = FreeImage_GetPitch(dib); + unsigned dst_pitch = FreeImage_GetPitch(dib); uint32 tileRowSize = (uint32)TIFFTileRowSize(tif); uint32 imageRowSize = (uint32)TIFFScanlineSize(tif); @@ -2071,7 +2115,7 @@ BYTE *src_bits = tileBuffer; BYTE *dst_bits = bits + rowSize; for(int k = 0; k < nrows; k++) { - memcpy(dst_bits, src_bits, src_line); + memcpy(dst_bits, src_bits, MIN(dst_pitch, src_line)); src_bits += tileRowSize; dst_bits -= dst_pitch; }