/* * Seek to a random row+sample in a file. * * Only used by TIFFReadScanline, and is only used on * strip organized files. We do some tricky stuff to try * and avoid reading the whole compressed raw data for big * strips. */ static int TIFFSeek(TIFF* tif, uint32 row, uint16 sample ) { register TIFFDirectory *td = &tif->tif_dir; uint32 strip; int whole_strip; tmsize_t read_ahead = 0; /* ** Establish what strip we are working from. */ if (row >= td->td_imagelength) { /* out of range */ TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "%lu: Row out of range, max %lu", (unsigned long) row, (unsigned long) td->td_imagelength); return (0); } if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { if (sample >= td->td_samplesperpixel) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "%lu: Sample out of range, max %lu", (unsigned long) sample, (unsigned long) td->td_samplesperpixel); return (0); } strip = (uint32)sample*td->td_stripsperimage + row/td->td_rowsperstrip; } else strip = row / td->td_rowsperstrip; /* * Do we want to treat this strip as one whole chunk or * read it a few lines at a time? */ #if defined(CHUNKY_STRIP_READ_SUPPORT) if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount) return 0; whole_strip = tif->tif_dir.td_stripbytecount[strip] < 10 || isMapped(tif); #else whole_strip = 1; #endif if( !whole_strip ) { read_ahead = tif->tif_scanlinesize * 16 + 5000; } /* * If we haven't loaded this strip, do so now, possibly * only reading the first part. */ if (strip != tif->tif_curstrip) { /* different strip, refill */ if( whole_strip ) { if (!TIFFFillStrip(tif, strip)) return (0); } else { if( !TIFFFillStripPartial(tif,strip,read_ahead,1) ) return 0; } } /* ** If we already have some data loaded, do we need to read some more? */ else if( !whole_strip ) { if( ((tif->tif_rawdata + tif->tif_rawdataloaded) - tif->tif_rawcp) < read_ahead && (uint64) tif->tif_rawdataoff+tif->tif_rawdataloaded < td->td_stripbytecount[strip] ) { if( !TIFFFillStripPartial(tif,strip,read_ahead,0) ) return 0; } } if (row < tif->tif_row) { /* * Moving backwards within the same strip: backup * to the start and then decode forward (below). * * NB: If you're planning on lots of random access within a * strip, it's better to just read and decode the entire * strip, and then access the decoded data in a random fashion. */ if( tif->tif_rawdataoff != 0 ) { if( !TIFFFillStripPartial(tif,strip,read_ahead,1) ) return 0; } else { if (!TIFFStartStrip(tif, strip)) return (0); } } if (row != tif->tif_row) { /* * Seek forward to the desired row. */ /* TODO: Will this really work with partial buffers? */ if (!(*tif->tif_seek)(tif, row - tif->tif_row)) return (0); tif->tif_row = row; } return (1); }
/* * Read the specified strip and setup for decoding. The data buffer is * expanded, as necessary, to hold the strip's data. */ int TIFFFillStrip(TIFF* tif, uint32 strip) { static const char module[] = "TIFFFillStrip"; TIFFDirectory *td = &tif->tif_dir; if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount) return 0; if ((tif->tif_flags&TIFF_NOREADRAW)==0) { uint64 bytecount = td->td_stripbytecount[strip]; if ((int64)bytecount <= 0) { #if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) TIFFErrorExt(tif->tif_clientdata, module, "Invalid strip byte count %I64u, strip %lu", (unsigned __int64) bytecount, (unsigned long) strip); #else TIFFErrorExt(tif->tif_clientdata, module, "Invalid strip byte count %llu, strip %lu", (unsigned long long) bytecount, (unsigned long) strip); #endif return (0); } if (isMapped(tif) && (isFillOrder(tif, td->td_fillorder) || (tif->tif_flags & TIFF_NOBITREV))) { /* * The image is mapped into memory and we either don't * need to flip bits or the compression routine is * going to handle this operation itself. In this * case, avoid copying the raw data and instead just * reference the data from the memory mapped file * image. This assumes that the decompression * routines do not modify the contents of the raw data * buffer (if they try to, the application will get a * fault since the file is mapped read-only). */ if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) { _TIFFfree(tif->tif_rawdata); tif->tif_rawdata = NULL; tif->tif_rawdatasize = 0; } tif->tif_flags &= ~TIFF_MYBUFFER; /* * We must check for overflow, potentially causing * an OOB read. Instead of simple * * td->td_stripoffset[strip]+bytecount > tif->tif_size * * comparison (which can overflow) we do the following * two comparisons: */ if (bytecount > (uint64)tif->tif_size || td->td_stripoffset[strip] > (uint64)tif->tif_size - bytecount) { /* * This error message might seem strange, but * it's what would happen if a read were done * instead. */ #if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) TIFFErrorExt(tif->tif_clientdata, module, "Read error on strip %lu; " "got %I64u bytes, expected %I64u", (unsigned long) strip, (unsigned __int64) tif->tif_size - td->td_stripoffset[strip], (unsigned __int64) bytecount); #else TIFFErrorExt(tif->tif_clientdata, module, "Read error on strip %lu; " "got %llu bytes, expected %llu", (unsigned long) strip, (unsigned long long) tif->tif_size - td->td_stripoffset[strip], (unsigned long long) bytecount); #endif tif->tif_curstrip = NOSTRIP; return (0); } tif->tif_rawdatasize = (tmsize_t)bytecount; tif->tif_rawdata = tif->tif_base + (tmsize_t)td->td_stripoffset[strip]; tif->tif_rawdataoff = 0; tif->tif_rawdataloaded = (tmsize_t) bytecount; /* * When we have tif_rawdata reference directly into the memory mapped file * we need to be pretty careful about how we use the rawdata. It is not * a general purpose working buffer as it normally otherwise is. So we * keep track of this fact to avoid using it improperly. */ tif->tif_flags |= TIFF_BUFFERMMAP; } else { /* * Expand raw data buffer, if needed, to hold data * strip coming from file (perhaps should set upper * bound on the size of a buffer we'll use?). */ tmsize_t bytecountm; bytecountm=(tmsize_t)bytecount; if ((uint64)bytecountm!=bytecount) { TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow"); return(0); } if (bytecountm > tif->tif_rawdatasize) { tif->tif_curstrip = NOSTRIP; if ((tif->tif_flags & TIFF_MYBUFFER) == 0) { TIFFErrorExt(tif->tif_clientdata, module, "Data buffer too small to hold strip %lu", (unsigned long) strip); return (0); } if (!TIFFReadBufferSetup(tif, 0, bytecountm)) return (0); } if (tif->tif_flags&TIFF_BUFFERMMAP) { tif->tif_curstrip = NOSTRIP; if (!TIFFReadBufferSetup(tif, 0, bytecountm)) return (0); } if (TIFFReadRawStrip1(tif, strip, tif->tif_rawdata, bytecountm, module) != bytecountm) return (0); tif->tif_rawdataoff = 0; tif->tif_rawdataloaded = bytecountm; if (!isFillOrder(tif, td->td_fillorder) && (tif->tif_flags & TIFF_NOBITREV) == 0) TIFFReverseBits(tif->tif_rawdata, bytecountm); } } return (TIFFStartStrip(tif, strip)); }
static int TIFFFillStripPartial( TIFF *tif, int strip, tmsize_t read_ahead, int restart ) { static const char module[] = "TIFFFillStripPartial"; register TIFFDirectory *td = &tif->tif_dir; tmsize_t unused_data; uint64 read_offset; tmsize_t cc, to_read; /* tmsize_t bytecountm; */ if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount) return 0; /* * Expand raw data buffer, if needed, to hold data * strip coming from file (perhaps should set upper * bound on the size of a buffer we'll use?). */ /* bytecountm=(tmsize_t) td->td_stripbytecount[strip]; */ if (read_ahead*2 > tif->tif_rawdatasize) { assert( restart ); tif->tif_curstrip = NOSTRIP; if ((tif->tif_flags & TIFF_MYBUFFER) == 0) { TIFFErrorExt(tif->tif_clientdata, module, "Data buffer too small to hold part of strip %lu", (unsigned long) strip); return (0); } if (!TIFFReadBufferSetup(tif, 0, read_ahead*2)) return (0); } if( restart ) { tif->tif_rawdataloaded = 0; tif->tif_rawdataoff = 0; } /* ** If we are reading more data, move any unused data to the ** start of the buffer. */ if( tif->tif_rawdataloaded > 0 ) unused_data = tif->tif_rawdataloaded - (tif->tif_rawcp - tif->tif_rawdata); else unused_data = 0; if( unused_data > 0 ) { assert((tif->tif_flags&TIFF_BUFFERMMAP)==0); memmove( tif->tif_rawdata, tif->tif_rawcp, unused_data ); } /* ** Seek to the point in the file where more data should be read. */ read_offset = td->td_stripoffset[strip] + tif->tif_rawdataoff + tif->tif_rawdataloaded; if (!SeekOK(tif, read_offset)) { TIFFErrorExt(tif->tif_clientdata, module, "Seek error at scanline %lu, strip %lu", (unsigned long) tif->tif_row, (unsigned long) strip); return 0; } /* ** How much do we want to read? */ to_read = tif->tif_rawdatasize - unused_data; if( (uint64) to_read > td->td_stripbytecount[strip] - tif->tif_rawdataoff - tif->tif_rawdataloaded ) { to_read = (tmsize_t) td->td_stripbytecount[strip] - tif->tif_rawdataoff - tif->tif_rawdataloaded; } assert((tif->tif_flags&TIFF_BUFFERMMAP)==0); cc = TIFFReadFile(tif, tif->tif_rawdata + unused_data, to_read); if (cc != to_read) { #if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) TIFFErrorExt(tif->tif_clientdata, module, "Read error at scanline %lu; got %I64u bytes, expected %I64u", (unsigned long) tif->tif_row, (unsigned __int64) cc, (unsigned __int64) to_read); #else TIFFErrorExt(tif->tif_clientdata, module, "Read error at scanline %lu; got %llu bytes, expected %llu", (unsigned long) tif->tif_row, (unsigned long long) cc, (unsigned long long) to_read); #endif return 0; } tif->tif_rawdataoff = tif->tif_rawdataoff + tif->tif_rawdataloaded - unused_data ; tif->tif_rawdataloaded = unused_data + to_read; tif->tif_rawcp = tif->tif_rawdata; if (!isFillOrder(tif, td->td_fillorder) && (tif->tif_flags & TIFF_NOBITREV) == 0) { assert((tif->tif_flags&TIFF_BUFFERMMAP)==0); TIFFReverseBits(tif->tif_rawdata + unused_data, to_read ); } /* ** When starting a strip from the beginning we need to ** restart the decoder. */ if( restart ) return TIFFStartStrip(tif, strip); else return 1; }
/* * Read the specified strip and setup for decoding. * The data buffer is expanded, as necessary, to * hold the strip's data. */ static int TIFFFillStrip(TIFF* tif, tstrip_t strip) { static const char module[] = "TIFFFillStrip"; TIFFDirectory *td = &tif->tif_dir; tsize_t bytecount; bytecount = td->td_stripbytecount[strip]; if (bytecount <= 0) { TIFFError(tif->tif_name, "%lu: Invalid strip byte count, strip %lu", (u_long) bytecount, (u_long) strip); return (0); } if (isMapped(tif) && (isFillOrder(tif, td->td_fillorder) || (tif->tif_flags & TIFF_NOBITREV))) { /* * The image is mapped into memory and we either don't * need to flip bits or the compression routine is going * to handle this operation itself. In this case, avoid * copying the raw data and instead just reference the * data from the memory mapped file image. This assumes * that the decompression routines do not modify the * contents of the raw data buffer (if they try to, * the application will get a fault since the file is * mapped read-only). */ if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) _TIFFfree(tif->tif_rawdata); tif->tif_flags &= ~TIFF_MYBUFFER; if ( td->td_stripoffset[strip] + bytecount > tif->tif_size) { /* * This error message might seem strange, but it's * what would happen if a read were done instead. */ TIFFError(module, "%s: Read error on strip %lu; got %lu bytes, expected %lu", tif->tif_name, (u_long) strip, (u_long) tif->tif_size - td->td_stripoffset[strip], (u_long) bytecount); tif->tif_curstrip = NOSTRIP; return (0); } tif->tif_rawdatasize = bytecount; tif->tif_rawdata = tif->tif_base + td->td_stripoffset[strip]; } else { /* * Expand raw data buffer, if needed, to * hold data strip coming from file * (perhaps should set upper bound on * the size of a buffer we'll use?). */ if (bytecount > tif->tif_rawdatasize) { tif->tif_curstrip = NOSTRIP; if ((tif->tif_flags & TIFF_MYBUFFER) == 0) { TIFFError(module, "%s: Data buffer too small to hold strip %lu", tif->tif_name, (u_long) strip); return (0); } if (!TIFFReadBufferSetup(tif, 0, TIFFroundup(bytecount, 1024))) return (0); } if (TIFFReadRawStrip1(tif, strip, (u_char *)tif->tif_rawdata, bytecount, module) != bytecount) return (0); if (!isFillOrder(tif, td->td_fillorder) && (tif->tif_flags & TIFF_NOBITREV) == 0) TIFFReverseBits(tif->tif_rawdata, bytecount); } return (TIFFStartStrip(tif, strip)); }
/* * Read the specified strip and setup for decoding. The data buffer is * expanded, as necessary, to hold the strip's data. */ int TIFFFillStrip(TIFF* tif, tstrip_t strip) { static const char module[] = "TIFFFillStrip"; TIFFDirectory *td = &tif->tif_dir; if ((tif->tif_flags&TIFF_NOREADRAW)==0) { /* * FIXME: butecount should have tsize_t type, but for now * libtiff defines tsize_t as a signed 32-bit integer and we * are losing ability to read arrays larger than 2^31 bytes. * So we are using uint32 instead of tsize_t here. */ uint32 bytecount = td->td_stripbytecount[strip]; if (bytecount <= 0) { TIFFErrorExt(tif->tif_clientdata, module, "%s: Invalid strip byte count %lu, strip %lu", tif->tif_name, (unsigned long) bytecount, (unsigned long) strip); return (0); } if (isMapped(tif) && (isFillOrder(tif, td->td_fillorder) || (tif->tif_flags & TIFF_NOBITREV))) { /* * The image is mapped into memory and we either don't * need to flip bits or the compression routine is * going to handle this operation itself. In this * case, avoid copying the raw data and instead just * reference the data from the memory mapped file * image. This assumes that the decompression * routines do not modify the contents of the raw data * buffer (if they try to, the application will get a * fault since the file is mapped read-only). */ if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) _TIFFfree(tif->tif_rawdata); tif->tif_flags &= ~TIFF_MYBUFFER; /* * We must check for overflow, potentially causing * an OOB read. Instead of simple * * td->td_stripoffset[strip]+bytecount > tif->tif_size * * comparison (which can overflow) we do the following * two comparisons: */ if (bytecount > tif->tif_size || td->td_stripoffset[strip] > tif->tif_size - bytecount) { /* * This error message might seem strange, but * it's what would happen if a read were done * instead. */ TIFFErrorExt(tif->tif_clientdata, module, "%s: Read error on strip %lu; " "got %lu bytes, expected %lu", tif->tif_name, (unsigned long) strip, (unsigned long) tif->tif_size - td->td_stripoffset[strip], (unsigned long) bytecount); tif->tif_curstrip = NOSTRIP; return (0); } tif->tif_rawdatasize = bytecount; tif->tif_rawdata = tif->tif_base + td->td_stripoffset[strip]; } else { /* * Expand raw data buffer, if needed, to hold data * strip coming from file (perhaps should set upper * bound on the size of a buffer we'll use?). */ if (bytecount > (uint32)tif->tif_rawdatasize) { tif->tif_curstrip = NOSTRIP; if ((tif->tif_flags & TIFF_MYBUFFER) == 0) { TIFFErrorExt(tif->tif_clientdata, module, "%s: Data buffer too small to hold strip %lu", tif->tif_name, (unsigned long) strip); return (0); } if (!TIFFReadBufferSetup(tif, 0, TIFFroundup(bytecount, 1024))) return (0); } if ((uint32)TIFFReadRawStrip1(tif, strip, (unsigned char *)tif->tif_rawdata, bytecount, module) != bytecount) return (0); if (!isFillOrder(tif, td->td_fillorder) && (tif->tif_flags & TIFF_NOBITREV) == 0) TIFFReverseBits(tif->tif_rawdata, bytecount); } } return (TIFFStartStrip(tif, strip)); }
static int TIFFFillStripPartial( TIFF *tif, int strip, tmsize_t read_ahead, int restart ) { static const char module[] = "TIFFFillStripPartial"; register TIFFDirectory *td = &tif->tif_dir; tmsize_t unused_data; uint64 read_offset; tmsize_t to_read; tmsize_t read_ahead_mod; /* tmsize_t bytecountm; */ if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount) return 0; /* * Expand raw data buffer, if needed, to hold data * strip coming from file (perhaps should set upper * bound on the size of a buffer we'll use?). */ /* bytecountm=(tmsize_t) td->td_stripbytecount[strip]; */ /* Not completely sure where the * 2 comes from, but probably for */ /* an exponentional growth strategy of tif_rawdatasize */ if( read_ahead < TIFF_TMSIZE_T_MAX / 2 ) read_ahead_mod = read_ahead * 2; else read_ahead_mod = read_ahead; if (read_ahead_mod > tif->tif_rawdatasize) { assert( restart ); tif->tif_curstrip = NOSTRIP; if ((tif->tif_flags & TIFF_MYBUFFER) == 0) { TIFFErrorExt(tif->tif_clientdata, module, "Data buffer too small to hold part of strip %lu", (unsigned long) strip); return (0); } } if( restart ) { tif->tif_rawdataloaded = 0; tif->tif_rawdataoff = 0; } /* ** If we are reading more data, move any unused data to the ** start of the buffer. */ if( tif->tif_rawdataloaded > 0 ) unused_data = tif->tif_rawdataloaded - (tif->tif_rawcp - tif->tif_rawdata); else unused_data = 0; if( unused_data > 0 ) { assert((tif->tif_flags&TIFF_BUFFERMMAP)==0); memmove( tif->tif_rawdata, tif->tif_rawcp, unused_data ); } /* ** Seek to the point in the file where more data should be read. */ read_offset = td->td_stripoffset[strip] + tif->tif_rawdataoff + tif->tif_rawdataloaded; if (!SeekOK(tif, read_offset)) { TIFFErrorExt(tif->tif_clientdata, module, "Seek error at scanline %lu, strip %lu", (unsigned long) tif->tif_row, (unsigned long) strip); return 0; } /* ** How much do we want to read? */ if( read_ahead_mod > tif->tif_rawdatasize ) to_read = read_ahead_mod - unused_data; else to_read = tif->tif_rawdatasize - unused_data; if( (uint64) to_read > td->td_stripbytecount[strip] - tif->tif_rawdataoff - tif->tif_rawdataloaded ) { to_read = (tmsize_t) td->td_stripbytecount[strip] - tif->tif_rawdataoff - tif->tif_rawdataloaded; } assert((tif->tif_flags&TIFF_BUFFERMMAP)==0); if( !TIFFReadAndRealloc( tif, to_read, unused_data, 1, /* is_strip */ 0, /* strip_or_tile */ module) ) { return 0; } 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) && (tif->tif_flags & TIFF_NOBITREV) == 0) { assert((tif->tif_flags&TIFF_BUFFERMMAP)==0); TIFFReverseBits(tif->tif_rawdata + unused_data, to_read ); } /* ** When starting a strip from the beginning we need to ** restart the decoder. */ if( restart ) { #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 { return 1; } }