From cf096692e43eaf02c67098e91f1e68b505c172b8 Mon Sep 17 00:00:00 2001 From: erouault Date: Thu, 29 Jun 2017 07:37:12 +0000 Subject: * libtiff/tiffiop.h, libtiff/tif_jpeg.c, libtiff/tif_jpeg_12.c, libtiff/tif_read.c: make TIFFReadScanline() works in CHUNKY_STRIP_READ_SUPPORT mode with JPEG stream with multiple scans. Also make configurable through a LIBTIFF_JPEG_MAX_ALLOWED_SCAN_NUMBER environment variable the maximum number of scans allowed. Defaults to 100. --- ChangeLog | 9 +++++++ libtiff/tif_jpeg.c | 65 ++++++++++++++++++++++++++++++++++++++++++--------- libtiff/tif_jpeg_12.c | 1 + libtiff/tif_read.c | 25 +++++++++++++++++--- libtiff/tiffiop.h | 3 ++- 5 files changed, 88 insertions(+), 15 deletions(-) diff --git a/ChangeLog b/ChangeLog index ab792220..c4ef9a7c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2017-06-29 Even Rouault + + * libtiff/tiffiop.h, libtiff/tif_jpeg.c, libtiff/tif_jpeg_12.c, + libtiff/tif_read.c: make TIFFReadScanline() works in + CHUNKY_STRIP_READ_SUPPORT mode with JPEG stream with multiple scans. + Also make configurable through a LIBTIFF_JPEG_MAX_ALLOWED_SCAN_NUMBER + environment variable the maximum number of scans allowed. Defaults to + 100. + 2017-06-27 Even Rouault * libtiff/tif_dirread.c: in TIFFReadDirEntryFloat(), check that a diff --git a/libtiff/tif_jpeg.c b/libtiff/tif_jpeg.c index e28fd667..833ca63f 100644 --- a/libtiff/tif_jpeg.c +++ b/libtiff/tif_jpeg.c @@ -1,4 +1,4 @@ -/* $Id: tif_jpeg.c,v 1.130 2017-06-24 15:33:28 erouault Exp $ */ +/* $Id: tif_jpeg.c,v 1.131 2017-06-29 07:37:12 erouault Exp $ */ /* * Copyright (c) 1994-1997 Sam Leffler @@ -49,6 +49,7 @@ int TIFFFillStrip(TIFF* tif, uint32 strip); int TIFFFillTile(TIFF* tif, uint32 tile); int TIFFReInitJPEG_12( TIFF *tif, int scheme, int is_encode ); +int TIFFJPEGIsFullStripRequired_12(TIFF* tif); /* We undefine FAR to avoid conflict with JPEG definition */ @@ -179,6 +180,7 @@ typedef struct { int jpegtablesmode; /* What to put in JPEGTables */ int ycbcrsampling_fetched; + int max_allowed_scan_number; } JPEGState; #define JState(tif) ((JPEGState*)(tif)->tif_data) @@ -250,13 +252,14 @@ TIFFjpeg_progress_monitor(j_common_ptr cinfo) { const int scan_no = ((j_decompress_ptr)cinfo)->input_scan_number; - const int MAX_SCANS = 100; - if (scan_no >= MAX_SCANS) + if (scan_no >= sp->max_allowed_scan_number) { TIFFErrorExt(((JPEGState *) cinfo)->tif->tif_clientdata, "TIFFjpeg_progress_monitor", - "Scan number %d exceeds maximum scans (%d)", - scan_no, MAX_SCANS); + "Scan number %d exceeds maximum scans (%d). This limit " + "can be raised through the LIBTIFF_JPEG_MAX_ALLOWED_SCAN_NUMBER " + "environment variable.", + scan_no, sp->max_allowed_scan_number); jpeg_abort(cinfo); /* clean up libjpeg state */ LONGJMP(sp->exit_jmpbuf, 1); /* return to libtiff caller */ @@ -375,9 +378,14 @@ TIFFjpeg_has_multiple_scans(JPEGState* sp) static int TIFFjpeg_start_decompress(JPEGState* sp) { + const char* sz_max_allowed_scan_number; /* progress monitor */ sp->cinfo.d.progress = &sp->progress; sp->progress.progress_monitor = TIFFjpeg_progress_monitor; + sp->max_allowed_scan_number = 100; + sz_max_allowed_scan_number = getenv("LIBTIFF_JPEG_MAX_ALLOWED_SCAN_NUMBER"); + if( sz_max_allowed_scan_number ) + sp->max_allowed_scan_number = atoi(sz_max_allowed_scan_number); return CALLVJPEG(sp, jpeg_start_decompress(&sp->cinfo.d)); } @@ -629,9 +637,8 @@ std_term_source(j_decompress_ptr cinfo) } static void -TIFFjpeg_data_src(JPEGState* sp, TIFF* tif) +TIFFjpeg_data_src(JPEGState* sp) { - (void) tif; sp->cinfo.d.src = &sp->src; sp->src.init_source = std_init_source; sp->src.fill_input_buffer = std_fill_input_buffer; @@ -657,9 +664,9 @@ tables_init_source(j_decompress_ptr cinfo) } static void -TIFFjpeg_tables_src(JPEGState* sp, TIFF* tif) +TIFFjpeg_tables_src(JPEGState* sp) { - TIFFjpeg_data_src(sp, tif); + TIFFjpeg_data_src(sp); sp->src.init_source = tables_init_source; } @@ -1016,7 +1023,7 @@ JPEGSetupDecode(TIFF* tif) /* Read JPEGTables if it is present */ if (TIFFFieldSet(tif,FIELD_JPEGTABLES)) { - TIFFjpeg_tables_src(sp, tif); + TIFFjpeg_tables_src(sp); if(TIFFjpeg_read_header(sp,FALSE) != JPEG_HEADER_TABLES_ONLY) { TIFFErrorExt(tif->tif_clientdata, "JPEGSetupDecode", "Bogus JPEGTables field"); return (0); @@ -1038,11 +1045,47 @@ JPEGSetupDecode(TIFF* tif) } /* Set up for reading normal data */ - TIFFjpeg_data_src(sp, tif); + TIFFjpeg_data_src(sp); tif->tif_postdecode = _TIFFNoPostDecode; /* override byte swapping */ return (1); } +/* Returns 1 if the full strip should be read, even when doing scanline per */ +/* scanline decoding. This happens when the JPEG stream uses multiple scans. */ +/* Currently only called in CHUNKY_STRIP_READ_SUPPORT mode through */ +/* scanline interface. */ +/* Only reads tif->tif_dir.td_bitspersample, tif->tif_rawdata and */ +/* tif->tif_rawcc members. */ +/* Can be called independently of the usual setup/predecode/decode states */ +int TIFFJPEGIsFullStripRequired(TIFF* tif) +{ + int ret; + JPEGState state; + +#if defined(JPEG_DUAL_MODE_8_12) && !defined(TIFFJPEGIsFullStripRequired) + if( tif->tif_dir.td_bitspersample == 12 ) + return TIFFJPEGIsFullStripRequired_12( tif ); +#endif + + memset(&state, 0, sizeof(JPEGState)); + state.tif = tif; + + TIFFjpeg_create_decompress(&state); + + TIFFjpeg_data_src(&state); + + if (TIFFjpeg_read_header(&state, TRUE) != JPEG_HEADER_OK) + { + TIFFjpeg_destroy(&state); + return (0); + } + ret = TIFFjpeg_has_multiple_scans(&state); + + TIFFjpeg_destroy(&state); + + return ret; +} + /* * Set up for decoding a strip or tile. */ diff --git a/libtiff/tif_jpeg_12.c b/libtiff/tif_jpeg_12.c index 8499e649..b458c258 100644 --- a/libtiff/tif_jpeg_12.c +++ b/libtiff/tif_jpeg_12.c @@ -4,6 +4,7 @@ #if defined(JPEG_DUAL_MODE_8_12) # define TIFFInitJPEG TIFFInitJPEG_12 +# define TIFFJPEGIsFullStripRequired TIFFJPEGIsFullStripRequired_12 int TIFFInitJPEG_12(TIFF* tif, int scheme); diff --git a/libtiff/tif_read.c b/libtiff/tif_read.c index cc4f5d2f..4f85fa93 100644 --- a/libtiff/tif_read.c +++ b/libtiff/tif_read.c @@ -1,4 +1,4 @@ -/* $Id: tif_read.c,v 1.59 2017-05-13 15:34:06 erouault Exp $ */ +/* $Id: tif_read.c,v 1.60 2017-06-29 07:37:12 erouault Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -262,6 +262,7 @@ TIFFFillStripPartial( TIFF *tif, int strip, tmsize_t read_ahead, int restart ) tif->tif_rawdataoff = tif->tif_rawdataoff + tif->tif_rawdataloaded - unused_data ; tif->tif_rawdataloaded = unused_data + to_read; + tif->tif_rawcc = tif->tif_rawdataloaded; tif->tif_rawcp = tif->tif_rawdata; if (!isFillOrder(tif, td->td_fillorder) && @@ -275,10 +276,28 @@ TIFFFillStripPartial( TIFF *tif, int strip, tmsize_t read_ahead, int restart ) ** restart the decoder. */ if( restart ) - return TIFFStartStrip(tif, strip); + { + +#ifdef JPEG_SUPPORT + /* A bit messy since breaks the codec abstraction. Ultimately */ + /* there should be a function pointer for that, but it seems */ + /* only JPEG is affected. */ + /* For JPEG, if there are multiple scans (can generally be known */ + /* with the read_ahead used), we need to read the whole strip */ + if( tif->tif_dir.td_compression==COMPRESSION_JPEG && + (uint64)tif->tif_rawcc < td->td_stripbytecount[strip] ) + { + if( TIFFJPEGIsFullStripRequired(tif) ) + { + return TIFFFillStrip(tif, strip); + } + } +#endif + + return TIFFStartStrip(tif, strip); + } else { - tif->tif_rawcc = tif->tif_rawdataloaded; return 1; } } diff --git a/libtiff/tiffiop.h b/libtiff/tiffiop.h index 73591340..2f992ef5 100644 --- a/libtiff/tiffiop.h +++ b/libtiff/tiffiop.h @@ -1,4 +1,4 @@ -/* $Id: tiffiop.h,v 1.91 2017-06-18 10:31:50 erouault Exp $ */ +/* $Id: tiffiop.h,v 1.92 2017-06-29 07:37:12 erouault Exp $ */ /* * Copyright (c) 1988-1997 Sam Leffler @@ -394,6 +394,7 @@ extern int TIFFInitOJPEG(TIFF*, int); #endif #ifdef JPEG_SUPPORT extern int TIFFInitJPEG(TIFF*, int); +extern int TIFFJPEGIsFullStripRequired(TIFF*); #endif #ifdef JBIG_SUPPORT extern int TIFFInitJBIG(TIFF*, int); -- cgit v1.2.1