From fcf71c36d9ec305a463c046fe5629fe0e89e9e5f Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 9 Dec 2014 00:17:02 -0500 Subject: [PATCH] tiff io: avoid over-allocation + add more tests --- src/tiff_reader.cpp | 43 +++++++++++++++++++++++++++++++++++++++---- tests/cxx/tiff_io.cpp | 21 +++++++++++++++++++++ 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/src/tiff_reader.cpp b/src/tiff_reader.cpp index ca9a5085a..d9365056a 100644 --- a/src/tiff_reader.cpp +++ b/src/tiff_reader.cpp @@ -136,6 +136,8 @@ private: unsigned photometric_; unsigned bands_; bool is_tiled_; + unsigned planar_config_; + unsigned compression_; public: enum TiffType { @@ -158,6 +160,9 @@ public: bool is_tiled() const { return is_tiled_; } unsigned tile_width() const { return tile_width_; } unsigned tile_height() const { return tile_height_; } + unsigned rows_per_strip() const { return rows_per_strip_; } + unsigned planar_config() const { return planar_config_; } + unsigned compression() const { return compression_; } private: tiff_reader(const tiff_reader&); tiff_reader& operator=(const tiff_reader&); @@ -207,7 +212,9 @@ tiff_reader::tiff_reader(std::string const& file_name) bps_(0), photometric_(0), bands_(1), - is_tiled_(false) + is_tiled_(false), + planar_config_(PLANARCONFIG_CONTIG), + compression_(COMPRESSION_NONE) { if (!stream_) throw image_reader_exception("TIFF reader: cannot open file "+ file_name); init(); @@ -228,7 +235,9 @@ tiff_reader::tiff_reader(char const* data, std::size_t size) bps_(0), photometric_(0), bands_(1), - is_tiled_(false) + is_tiled_(false), + planar_config_(PLANARCONFIG_CONTIG), + compression_(COMPRESSION_NONE) { if (!stream_) throw image_reader_exception("TIFF reader: cannot open image stream "); stream_.seekg(0, std::ios::beg); @@ -257,6 +266,15 @@ void tiff_reader::init() TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width_); TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height_); + if (width_ > 10000 || height_ > 10000) + { + throw image_reader_exception("Can't allocate tiff > 10000x10000"); + } + + TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &planar_config_); + TIFFGetField(tif, TIFFTAG_COMPRESSION, &compression_ ); + TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rows_per_strip_); + std::uint16_t orientation; if (TIFFGetField(tif, TIFFTAG_ORIENTATION, &orientation) == 0) { @@ -273,7 +291,7 @@ void tiff_reader::init() MAPNIK_LOG_DEBUG(tiff_reader) << "reading tiled tiff"; read_method_ = tiled; } - else if (TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rows_per_strip_)!=0) + else if (rows_per_strip_ > 0) { MAPNIK_LOG_DEBUG(tiff_reader) << "reading striped tiff"; read_method_ = stripped; @@ -291,6 +309,23 @@ void tiff_reader::init() premultiplied_alpha_ = true; } } + + if (!is_tiled_ && + compression_ == COMPRESSION_NONE && + planar_config_ == PLANARCONFIG_CONTIG) + { + if (height_ > 128 * 1024 * 1024) + { + std::size_t line_size = (bands_ * width_ * bps_ + 7) / 8; + std::size_t default_strip_height = 8192 / line_size; + if (default_strip_height == 0) default_strip_height = 1; + std::size_t num_strips = height_ / default_strip_height; + if (num_strips > 128 * 1024 * 1024) + { + throw image_reader_exception("Can't allocate tiff"); + } + } + } } template @@ -606,7 +641,7 @@ void tiff_reader::read_stripped(unsigned x0,unsigned y0,image_data_rgba8& ima if (!TIFFReadRGBAStrip(tif,y,buf.get())) { - std::clog << "TIFFReadRGBAStrip failed"; + std::clog << "TIFFReadRGBAStrip failed at " << y << " for " << width_ << "/" << height_ << "\n"; break; } row=y+ty0-y0; diff --git a/tests/cxx/tiff_io.cpp b/tests/cxx/tiff_io.cpp index 8603f274f..ecac0d18e 100644 --- a/tests/cxx/tiff_io.cpp +++ b/tests/cxx/tiff_io.cpp @@ -10,6 +10,7 @@ mapnik::tiff_reader tiff_reader(filename); \ REQUIRE( tiff_reader.width() == 256 ); \ REQUIRE( tiff_reader.height() == 256 ); \ + REQUIRE( tiff_reader.planar_config() == PLANARCONFIG_CONTIG ); \ std::unique_ptr reader(mapnik::get_image_reader(filename,"tiff")); \ REQUIRE( reader->width() == 256 ); \ REQUIRE( reader->height() == 256 ); \ @@ -54,11 +55,13 @@ TEST_CASE("tiff io") { SECTION("rgba8 striped") { TIFF_ASSERT("./tests/data/tiff/ndvi_256x256_rgba8_striped.tif") + REQUIRE( tiff_reader.rows_per_strip() == 1 ); REQUIRE( tiff_reader.bits_per_sample() == 8 ); REQUIRE( tiff_reader.is_tiled() == false ); REQUIRE( tiff_reader.tile_width() == 0 ); REQUIRE( tiff_reader.tile_height() == 0 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_RGB ); + REQUIRE( tiff_reader.compression() == COMPRESSION_ADOBE_DEFLATE ); mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); @@ -68,11 +71,13 @@ SECTION("rgba8 striped") { SECTION("rgba8 tiled") { TIFF_ASSERT("./tests/data/tiff/ndvi_256x256_rgba8_tiled.tif") + REQUIRE( tiff_reader.rows_per_strip() == 0 ); REQUIRE( tiff_reader.bits_per_sample() == 8 ); REQUIRE( tiff_reader.is_tiled() == true ); REQUIRE( tiff_reader.tile_width() == 256 ); REQUIRE( tiff_reader.tile_height() == 256 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_RGB ); + REQUIRE( tiff_reader.compression() == COMPRESSION_LZW ); mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); @@ -82,11 +87,13 @@ SECTION("rgba8 tiled") { SECTION("rgb8 striped") { TIFF_ASSERT("./tests/data/tiff/ndvi_256x256_rgb8_striped.tif") + REQUIRE( tiff_reader.rows_per_strip() == 10 ); REQUIRE( tiff_reader.bits_per_sample() == 8 ); REQUIRE( tiff_reader.is_tiled() == false ); REQUIRE( tiff_reader.tile_width() == 0 ); REQUIRE( tiff_reader.tile_height() == 0 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_RGB ); + REQUIRE( tiff_reader.compression() == COMPRESSION_NONE ); mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); @@ -96,11 +103,13 @@ SECTION("rgb8 striped") { SECTION("rgb8 tiled") { TIFF_ASSERT("./tests/data/tiff/ndvi_256x256_rgb8_tiled.tif") + REQUIRE( tiff_reader.rows_per_strip() == 0 ); REQUIRE( tiff_reader.bits_per_sample() == 8 ); REQUIRE( tiff_reader.is_tiled() == true ); REQUIRE( tiff_reader.tile_width() == 256 ); REQUIRE( tiff_reader.tile_height() == 256 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_RGB ); + REQUIRE( tiff_reader.compression() == COMPRESSION_LZW ); mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); @@ -110,11 +119,13 @@ SECTION("rgb8 tiled") { SECTION("gray8 striped") { TIFF_ASSERT("./tests/data/tiff/ndvi_256x256_gray8_striped.tif") + REQUIRE( tiff_reader.rows_per_strip() == 32 ); REQUIRE( tiff_reader.bits_per_sample() == 8 ); REQUIRE( tiff_reader.is_tiled() == false ); REQUIRE( tiff_reader.tile_width() == 0 ); REQUIRE( tiff_reader.tile_height() == 0 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK ); + REQUIRE( tiff_reader.compression() == COMPRESSION_NONE ); mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); @@ -124,11 +135,13 @@ SECTION("gray8 striped") { SECTION("gray8 tiled") { TIFF_ASSERT("./tests/data/tiff/ndvi_256x256_gray8_tiled.tif") + REQUIRE( tiff_reader.rows_per_strip() == 0 ); REQUIRE( tiff_reader.bits_per_sample() == 8 ); REQUIRE( tiff_reader.is_tiled() == true ); REQUIRE( tiff_reader.tile_width() == 256 ); REQUIRE( tiff_reader.tile_height() == 256 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK ); + REQUIRE( tiff_reader.compression() == COMPRESSION_LZW ); mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); @@ -138,11 +151,13 @@ SECTION("gray8 tiled") { SECTION("gray16 striped") { TIFF_ASSERT("./tests/data/tiff/ndvi_256x256_gray16_striped.tif") + REQUIRE( tiff_reader.rows_per_strip() == 16 ); REQUIRE( tiff_reader.bits_per_sample() == 16 ); REQUIRE( tiff_reader.is_tiled() == false ); REQUIRE( tiff_reader.tile_width() == 0 ); REQUIRE( tiff_reader.tile_height() == 0 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK ); + REQUIRE( tiff_reader.compression() == COMPRESSION_NONE ); mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); @@ -152,11 +167,13 @@ SECTION("gray16 striped") { SECTION("gray16 tiled") { TIFF_ASSERT("./tests/data/tiff/ndvi_256x256_gray16_tiled.tif") + REQUIRE( tiff_reader.rows_per_strip() == 0 ); REQUIRE( tiff_reader.bits_per_sample() == 16 ); REQUIRE( tiff_reader.is_tiled() == true ); REQUIRE( tiff_reader.tile_width() == 256 ); REQUIRE( tiff_reader.tile_height() == 256 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK ); + REQUIRE( tiff_reader.compression() == COMPRESSION_LZW ); mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); @@ -166,11 +183,13 @@ SECTION("gray16 tiled") { SECTION("gray32f striped") { TIFF_ASSERT("./tests/data/tiff/ndvi_256x256_gray32f_striped.tif") + REQUIRE( tiff_reader.rows_per_strip() == 8 ); REQUIRE( tiff_reader.bits_per_sample() == 32 ); REQUIRE( tiff_reader.is_tiled() == false ); REQUIRE( tiff_reader.tile_width() == 0 ); REQUIRE( tiff_reader.tile_height() == 0 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK ); + REQUIRE( tiff_reader.compression() == COMPRESSION_NONE ); mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); @@ -180,11 +199,13 @@ SECTION("gray32f striped") { SECTION("gray32f tiled") { TIFF_ASSERT("./tests/data/tiff/ndvi_256x256_gray32f_tiled.tif") + REQUIRE( tiff_reader.rows_per_strip() == 0 ); REQUIRE( tiff_reader.bits_per_sample() == 32 ); REQUIRE( tiff_reader.is_tiled() == true ); REQUIRE( tiff_reader.tile_width() == 256 ); REQUIRE( tiff_reader.tile_height() == 256 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK ); + REQUIRE( tiff_reader.compression() == COMPRESSION_LZW ); mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader );