From: Tony Cook Date: Thu, 25 Nov 2004 12:39:05 +0000 (+0000) Subject: - added many bad BMP files to test various code paths in bmp.c, and X-Git-Tag: Imager-0.48^2~294 X-Git-Url: http://git.imager.perl.org/imager.git/commitdiff_plain/662e3c02015f0421f6f764564ad73ba34f448af3 - added many bad BMP files to test various code paths in bmp.c, and made many minor fixes to bmp.c to make them work: - it was possible for various types of read failures to SEGV, both as NULL pointer dereferences and buffer overflows - some errors, like palettes being too large for the number of bits per pixel, were not being caught - failing to read all of a packed data structure would not cause a read failure - invalid compression types were not always caught - error messages are more consistent (still not always great messages, but one step at a time) - added bmp_compression_name, bmp_used_colors, bmp_filesize, bmp_bit_count tags on reading a BMP file --- diff --git a/Changes b/Changes index 54c871bf..9e2059d3 100644 --- a/Changes +++ b/Changes @@ -891,6 +891,19 @@ Revision history for Perl extension Imager. - set i_format to jpeg for jpeg files and test for it - set i_format to png when reading png files and test for it - i_yres was being set to the xres when reading a png file +- added many bad BMP files to test various code paths in bmp.c, and + made many minor fixes to bmp.c to make them work: + - it was possible for various types of read failures to SEGV, both + as NULL pointer dereferences and buffer overflows + - some errors, like palettes being too large for the number of bits + per pixel, were not being caught + - failing to read all of a packed data structure would not cause + a read failure + - invalid compression types were not always caught + - error messages are more consistent (still not always great messages, + but one step at a time) +- added bmp_compression_name, bmp_used_colors, bmp_filesize, bmp_bit_count + tags on reading a BMP file ================================================================= diff --git a/MANIFEST b/MANIFEST index 0cff47aa..43653ca7 100644 --- a/MANIFEST +++ b/MANIFEST @@ -2,56 +2,40 @@ Changes Imager.pm Imager.xs MANIFEST -README Makefile.PL +README +bigtest.perl Library selection tester bmp.c Reading and writing Windows BMP files -tga.c Reading and writing Targa files -rgb.c Reading and writing SGI rgb files color.c Color translation and handling conv.c convert.c +datatypes.c +datatypes.h +doco.perl draw.c -polygon.c draw.h -fills.c Generic fills -map.c +dynaload.c +dynaload.h +dynfilt/Makefile.PL +dynfilt/compile.txt +dynfilt/dt2.c +dynfilt/dt2.exp +dynfilt/dyntest.c +dynfilt/dyntest.exp +dynfilt/flines.c +dynfilt/flines.exp +dynfilt/mandelbrot.c +dynfilt/mandelbrot.exp +dynfilt/pluginst.h +errep.perl error.c -gaussian.c -ppport.h -image.c -image.h -imagei.h -datatypes.h -datatypes.c +ext.h +feat.c feat.h -img16.c -imgdouble.c Implements double/sample images -io.c -imio.h -log.c -log.h -jpeg.c -png.c -gif.c -tiff.c -quant.c -raw.c -pnm.c +fills.c Generic fills +filterlist.perl filters.c -feat.c font.c -freetyp2.c Implements freetype2 font support -maskimg.c -palimg.c -regmach.c -regmach.h -rotate.c -stackmach.c -stackmach.h -tags.c -trans2.c -iolayer.h -iolayer.c fontfiles/ExistenceTest.afm please edit ExistenceTest.sfd in CVS fontfiles/ExistenceTest.pfb to change these files, edited and fontfiles/ExistenceTest.ttf generated using pfaedit @@ -60,33 +44,65 @@ fontfiles/NameTest.ttf test glyph_names() - see t38ft2font.t fontfiles/dcr10.afm fontfiles/dcr10.pfb fontfiles/dodge.ttf +freetyp2.c Implements freetype2 font support +gaussian.c +gif.c +image.c +image.h +imagei.h +img16.c +imgdouble.c Implements double/sample images +imio.h +io.c +iolayer.c +iolayer.h +jpeg.c lib/Imager/Color.pm lib/Imager/Color/Float.pm lib/Imager/Color/Table.pm +lib/Imager/Draw.pod +lib/Imager/Engines.pod lib/Imager/Expr.pm lib/Imager/Expr/Assem.pm lib/Imager/Files.pod -lib/Imager/Draw.pod -lib/Imager/Transformations.pod -lib/Imager/ImageTypes.pod -lib/Imager/Filters.pod -lib/Imager/Engines.pod lib/Imager/Fill.pm +lib/Imager/Filters.pod lib/Imager/Font.pm lib/Imager/Font/BBox.pm -lib/Imager/Font/Type1.pm -lib/Imager/Font/Truetype.pm lib/Imager/Font/FreeType2.pm +lib/Imager/Font/Image.pm +lib/Imager/Font/Truetype.pm +lib/Imager/Font/Type1.pm lib/Imager/Font/Win32.pm lib/Imager/Font/Wrap.pm -lib/Imager/Font/Image.pm lib/Imager/Fountain.pm -lib/Imager/interface.pod +lib/Imager/ImageTypes.pod lib/Imager/Matrix2d.pm -lib/Imager/regmach.pod lib/Imager/Regops.pm lib/Imager/Transform.pm -t/testtools.pl +lib/Imager/Transformations.pod +lib/Imager/interface.pod +lib/Imager/regmach.pod +log.c +log.h +map.c +maskimg.c +palimg.c +plug.h +png.c +pnm.c +polygon.c +ppport.h +quant.c +raw.c +regmach.c +regmach.h +regops.perl +rgb.c Reading and writing SGI rgb files +rotate.c +spot.perl For making an ordered dither matrix from a spot function +stackmach.c +stackmach.h t/t00basic.t t/t01introvert.t t/t020masked.t @@ -131,6 +147,27 @@ t/t70newgif.t t/t75polyaa.t t/t80texttools.t Test text wrapping t/t90cc.t +t/testtools.pl +tags.c +testimg/bad1oflow.bmp 1-bit/pixel, overflow integer on 32-bit machines +testimg/bad1wid0.bmp 1-bit/pixel, zero width +testimg/bad24comp.bmp 24-bit/pixel, bad compression +testimg/bad24oflow.bmp 24-bit/pixel, overflow integer on 32-bit machines +testimg/bad24wid0.bmp 24-bit/pixel, 0 width +testimg/bad4oflow.bmp 4-bit/pixel, overflow integer on 32-bit machines +testimg/bad4wid0.bmp 4-bit/pixel, 0 width +testimg/bad4widbig.bmp 4-bit/pixel, large width +testimg/bad8comp.bmp 8-bit/pixel, bad compression +testimg/bad8oflow.bmp 8-bit/pixel, overflow integer on 32-bit machines +testimg/bad8useda.bmp 8-bit/pixel, bad colors used value +testimg/bad8wid0.bmp 8-bit/pixel, width 0 +testimg/badbits.bmp bad bits value in header +testimg/badcomp1.bmp bad compression for 1-bit/pixel +testimg/badcomp4.bmp bad compression for 4-bit/pixel +testimg/badplanes.bmp bad planes value in header +testimg/badused1.bmp 1-bit/pixel, out of range colors used value +testimg/badused4a.bmp 4-bit/pixel, badly out of range used value (SEGV test) +testimg/badused4b.bmp 4-bit/pixel, just out of range used value (SEGV test) testimg/bandw.gif testimg/comp4.bmp Compressed 4-bit/pixel BMP testimg/comp4.tif 4-bit/pixel paletted TIFF @@ -156,31 +193,19 @@ testimg/scale.ppm testimg/scalei.gif testimg/screen2.gif testimg/screen3.gif +testimg/short1.bmp 1-bit/pixel, data missing from EOF +testimg/short24.bmp 24-bit/pixel, data missing from EOF +testimg/short4.bmp truncated 4bit/pixel uncompressed BMP +testimg/short4rle.bmp truncated 4bit/pixel compressed BMP +testimg/short8.bmp 8-bit/pixel, data missing from EOF +testimg/short8rle.bmp 8-bit/pixel compressed, data missing from EOF testimg/simple.pbm testimg/test_gimp_pal A simple GIMP palette file testimg/trimgdesc.gif testimg/trmiddesc.gif -typemap -dynaload.c -dynaload.h -ext.h -plug.h -filterlist.perl -doco.perl -errep.perl -regops.perl -spot.perl For making an ordered dither matrix from a spot function +tga.c Reading and writing Targa files +tiff.c +trans2.c transform.perl Shell interface to Imager::Transform -bigtest.perl Library selection tester -dynfilt/pluginst.h -dynfilt/dyntest.c -dynfilt/dyntest.exp -dynfilt/dt2.c -dynfilt/dt2.exp -dynfilt/mandelbrot.c -dynfilt/mandelbrot.exp -dynfilt/flines.c -dynfilt/flines.exp -dynfilt/compile.txt -dynfilt/Makefile.PL +typemap win32.c Implements font support through Win32 GDI diff --git a/bmp.c b/bmp.c index 286b3dc8..4e103272 100644 --- a/bmp.c +++ b/bmp.c @@ -44,8 +44,8 @@ static int write_4bit_data(io_glue *ig, i_img *im); static int write_8bit_data(io_glue *ig, i_img *im); static int write_24bit_data(io_glue *ig, i_img *im); static int read_bmp_pal(io_glue *ig, i_img *im, int count); -static i_img *read_1bit_bmp(io_glue *ig, int xsize, int ysize, - int clr_used); +static i_img *read_1bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used, + int compression); static i_img *read_4bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used, int compression); static i_img *read_8bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used, @@ -102,16 +102,18 @@ BI_BITFIELDS images too, but I need a test image. i_img * i_readbmp_wiol(io_glue *ig) { - int b_magic, m_magic, filesize, dummy, infohead_size; + int b_magic, m_magic, filesize, res1, res2, infohead_size; int xsize, ysize, planes, bit_count, compression, size_image, xres, yres; int clr_used, clr_important, offbits; i_img *im; + + mm_log((1, "i_readbmp_wiol(ig %p)\n", ig)); io_glue_commit_types(ig); i_clear_error(); if (!read_packed(ig, "CCVvvVVVVvvVVVVVV", &b_magic, &m_magic, &filesize, - &dummy, &dummy, &offbits, &infohead_size, + &res1, &res2, &offbits, &infohead_size, &xsize, &ysize, &planes, &bit_count, &compression, &size_image, &xres, &yres, &clr_used, &clr_important)) { @@ -123,10 +125,16 @@ i_readbmp_wiol(io_glue *ig) { i_push_error(0, "not a BMP file"); return 0; } + + mm_log((1, " bmp header: filesize %d offbits %d xsize %d ysize %d planes %d " + "bit_count %d compression %d size %d xres %d yres %d clr_used %d " + "clr_important %d\n", filesize, offbits, xsize, ysize, planes, + bit_count, compression, size_image, xres, yres, clr_used, + clr_important)); switch (bit_count) { case 1: - im = read_1bit_bmp(ig, xsize, ysize, clr_used); + im = read_1bit_bmp(ig, xsize, ysize, clr_used, compression); break; case 4: @@ -148,17 +156,23 @@ i_readbmp_wiol(io_glue *ig) { return NULL; } - /* store the resolution */ - if (xres && !yres) - yres = xres; - else if (yres && !xres) - xres = yres; - if (xres) { - i_tags_set_float(&im->tags, "i_xres", 0, xres * 0.0254); - i_tags_set_float(&im->tags, "i_yres", 0, yres * 0.0254); + if (im) { + /* store the resolution */ + if (xres && !yres) + yres = xres; + else if (yres && !xres) + xres = yres; + if (xres) { + i_tags_set_float(&im->tags, "i_xres", 0, xres * 0.0254); + i_tags_set_float(&im->tags, "i_yres", 0, yres * 0.0254); + } + i_tags_addn(&im->tags, "bmp_compression", 0, compression); + i_tags_addn(&im->tags, "bmp_important_colors", 0, clr_important); + i_tags_addn(&im->tags, "bmp_used_colors", 0, clr_used); + i_tags_addn(&im->tags, "bmp_filesize", 0, filesize); + i_tags_addn(&im->tags, "bmp_bit_count", 0, bit_count); + i_tags_add(&im->tags, "i_format", 0, "bmp", 3, 0); } - i_tags_addn(&im->tags, "bmp_compression", 0, compression); - i_tags_addn(&im->tags, "bmp_important_colors", 0, clr_important); return im; } @@ -195,31 +209,31 @@ int read_packed(io_glue *ig, char *format, ...) { switch (*format) { case 'v': - if (ig->readcb(ig, buf, 2) == -1) + if (ig->readcb(ig, buf, 2) != 2) return 0; *p = buf[0] + (buf[1] << 8); break; case 'V': - if (ig->readcb(ig, buf, 4) == -1) + if (ig->readcb(ig, buf, 4) != 4) return 0; *p = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24); break; case 'C': - if (ig->readcb(ig, buf, 1) == -1) + if (ig->readcb(ig, buf, 1) != 1) return 0; *p = buf[0]; break; case 'c': - if (ig->readcb(ig, buf, 1) == -1) + if (ig->readcb(ig, buf, 1) != 1) return 0; *p = (char)buf[0]; break; case '3': /* extension - 24-bit number */ - if (ig->readcb(ig, buf, 3) == -1) + if (ig->readcb(ig, buf, 3) != 3) return 0; *p = buf[0] + (buf[1] << 8) + (buf[2] << 16); break; @@ -590,8 +604,10 @@ read_bmp_pal(io_glue *ig, i_img *im, int count) { c.channel[0] = r; c.channel[1] = g; c.channel[2] = b; - if (i_addcolors(im, &c, 1) < 0) + if (i_addcolors(im, &c, 1) < 0) { + i_push_error(0, "out of space in image palette"); return 0; + } } return 1; @@ -607,7 +623,8 @@ Returns the image or NULL. =cut */ static i_img * -read_1bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used) { +read_1bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used, + int compression) { i_img *im; int x, y, lasty, yinc; i_palidx *line, *p; @@ -616,6 +633,11 @@ read_1bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used) { int byte, bit; unsigned char *in; + if (compression != BI_RGB) { + i_push_errorf(0, "unknown 1-bit BMP compression (%d)", compression); + return NULL; + } + line_size = (line_size+3) / 4 * 4; if (ysize > 0) { @@ -630,13 +652,21 @@ read_1bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used) { lasty = ysize; yinc = 1; } - im = i_img_pal_new(xsize, ysize, 3, 256); if (!clr_used) clr_used = 2; + if (clr_used < 0 || clr_used > 2) { + i_push_errorf(0, "out of range colors used (%d)", clr_used); + return NULL; + } + im = i_img_pal_new(xsize, ysize, 3, 256); + if (!im) + return NULL; if (!read_bmp_pal(ig, im, clr_used)) { i_img_destroy(im); return NULL; } + + i_tags_add(&im->tags, "bmp_compression_name", 0, "BI_RGB", -1, 0); packed = mymalloc(line_size); line = mymalloc(xsize+8); @@ -644,7 +674,7 @@ read_1bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used) { if (ig->readcb(ig, packed, line_size) != line_size) { myfree(packed); myfree(line); - i_push_error(0, "reading 1-bit bmp data"); + i_push_error(0, "failed reading 1-bit bmp data"); i_img_destroy(im); return NULL; } @@ -705,9 +735,17 @@ read_4bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used, lasty = ysize; yinc = 1; } - im = i_img_pal_new(xsize, ysize, 3, 256); if (!clr_used) clr_used = 16; + + if (clr_used > 16 || clr_used < 0) { + i_push_errorf(0, "out of range colors used (%d)", clr_used); + return NULL; + } + + im = i_img_pal_new(xsize, ysize, 3, 256); + if (!im) /* error should have been pushed already */ + return NULL; if (!read_bmp_pal(ig, im, clr_used)) { i_img_destroy(im); return NULL; @@ -719,11 +757,12 @@ read_4bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used, packed = mymalloc(line_size); line = mymalloc(xsize+1); if (compression == BI_RGB) { + i_tags_add(&im->tags, "bmp_compression_name", 0, "BI_RGB", -1, 0); while (y != lasty) { if (ig->readcb(ig, packed, line_size) != line_size) { myfree(packed); myfree(line); - i_push_error(0, "reading 4-bit bmp data"); + i_push_error(0, "failed reading 4-bit bmp data"); i_img_destroy(im); return NULL; } @@ -745,6 +784,7 @@ read_4bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used, int want_high; int count; + i_tags_add(&im->tags, "bmp_compression_name", 0, "BI_RLE4", -1, 0); x = 0; while (1) { /* there's always at least 2 bytes in a sequence */ @@ -814,7 +854,7 @@ read_4bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used, else { /*if (compression == BI_RLE4) {*/ myfree(packed); myfree(line); - i_push_error(0, "bad compression for 4-bit image"); + i_push_errorf(0, "unknown 4-bit BMP compression (%d)", compression); i_img_destroy(im); return NULL; } @@ -854,9 +894,16 @@ read_8bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used, lasty = ysize; yinc = 1; } - im = i_img_pal_new(xsize, ysize, 3, 256); if (!clr_used) clr_used = 256; + if (clr_used > 256 || clr_used < 0) { + i_push_errorf(0, "out of range colors used (%d)", clr_used); + return NULL; + } + + im = i_img_pal_new(xsize, ysize, 3, 256); + if (!im) + return NULL; if (!read_bmp_pal(ig, im, clr_used)) { i_img_destroy(im); return NULL; @@ -864,10 +911,11 @@ read_8bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used, line = mymalloc(line_size); if (compression == BI_RGB) { + i_tags_add(&im->tags, "bmp_compression_name", 0, "BI_RGB", -1, 0); while (y != lasty) { if (ig->readcb(ig, line, line_size) != line_size) { myfree(line); - i_push_error(0, "reading 8-bit bmp data"); + i_push_error(0, "failed reading 8-bit bmp data"); i_img_destroy(im); return NULL; } @@ -882,6 +930,7 @@ read_8bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used, int count; unsigned char packed[2]; + i_tags_add(&im->tags, "bmp_compression_name", 0, "BI_RLE8", -1, 0); x = 0; while (1) { /* there's always at least 2 bytes in a sequence */ @@ -935,7 +984,7 @@ read_8bit_bmp(io_glue *ig, int xsize, int ysize, int clr_used, } else { myfree(line); - i_push_errorf(0, "unknown 8-bit BMP compression %d", compression); + i_push_errorf(0, "unknown 8-bit BMP compression (%d)", compression); i_img_destroy(im); return NULL; } @@ -986,6 +1035,8 @@ read_direct_bmp(io_glue *ig, int xsize, int ysize, int bit_count, int i; int extras; char junk[4]; + const char *compression_name; + int bytes; unpack_code[0] = *("v3V"+pix_size-2); unpack_code[1] = '\0'; @@ -1006,6 +1057,7 @@ read_direct_bmp(io_glue *ig, int xsize, int ysize, int bit_count, yinc = 1; } if (compression == BI_RGB) { + compression_name = "BI_RGB"; masks = std_masks[pix_size-2]; /* there's a potential "palette" after the header */ @@ -1019,6 +1071,8 @@ read_direct_bmp(io_glue *ig, int xsize, int ysize, int bit_count, } else if (compression == BI_BITFIELDS) { int pos, bit; + compression_name = "BI_BITFIELDS"; + for (i = 0; i < 3; ++i) { if (!read_packed(ig, "V", masks.masks+i)) { i_push_error(0, "reading pixel masks"); @@ -1034,16 +1088,32 @@ read_direct_bmp(io_glue *ig, int xsize, int ysize, int bit_count, masks.shifts[i] = pos - 8; } } + else { + i_push_errorf(0, "unknown 24-bit BMP compression (%d)", compression); + return NULL; + } im = i_img_empty(NULL, xsize, ysize); + if (!im) + return NULL; - line = mymalloc(sizeof(i_color) * xsize); + i_tags_add(&im->tags, "bmp_compression_name", 0, compression_name, -1, 0); + + /* I wasn't able to make this overflow in testing, but better to be + safe */ + bytes = sizeof(i_color) * xsize; + if (bytes / sizeof(i_color) != xsize) { + i_img_destroy(im); + i_push_error(0, "integer overflow calculating buffer size"); + return NULL; + } + line = mymalloc(bytes); while (y != lasty) { p = line; for (x = 0; x < xsize; ++x) { unsigned pixel; if (!read_packed(ig, unpack_code, &pixel)) { - i_push_error(0, "reading image data"); + i_push_error(0, "failed reading image data"); myfree(line); i_img_destroy(im); return NULL; diff --git a/lib/Imager/Files.pod b/lib/Imager/Files.pod index 48e54409..fe748bcb 100644 --- a/lib/Imager/Files.pod +++ b/lib/Imager/Files.pod @@ -501,10 +501,26 @@ Packed RGB values. =back +=item bmp_compression_name + +The bmp_compression value as a BI_* string + =item bmp_important_colors The number of important colors as defined by the writer of the image. +=item bmp_used_colors + +Number of color used from the BMP header + +=item bmp_filesize + +The file size from the BMP header + +=item bmp_bit_count + +Number of bits stored per pixel. (24, 8, 4 or 1) + =back =head2 TGA (TarGA) diff --git a/t/t107bmp.t b/t/t107bmp.t index 375375c8..62d8d9c7 100644 --- a/t/t107bmp.t +++ b/t/t107bmp.t @@ -1,8 +1,9 @@ #!perl -w -print "1..12\n"; +print "1..62\n"; use Imager qw(:all); use strict; init_log("testout/t107bmp.log",1); +require 't/testtools.pl'; my $base_diff = 0; # if you change this make sure you generate new compressed versions @@ -38,15 +39,21 @@ my $bi_rgb = 0; my $bi_rle8 = 1; my $bi_rle4 = 2; my $bi_bitfields = 3; -read_test(5, "testout/t107_24bit.bmp", $img, bmp_compression=>0); -read_test(6, "testout/t107_8bit.bmp", $im8, bmp_compression=>0); -read_test(7, "testout/t107_4bit.bmp", $im4, bmp_compression=>0); -read_test(8, "testout/t107_1bit.bmp", $im1, bmp_compression=>0); +read_test(5, "testout/t107_24bit.bmp", $img, + bmp_compression=>0, bmp_bit_count => 24); +read_test(6, "testout/t107_8bit.bmp", $im8, + bmp_compression=>0, bmp_bit_count => 8); +read_test(7, "testout/t107_4bit.bmp", $im4, + bmp_compression=>0, bmp_bit_count => 4); +read_test(8, "testout/t107_1bit.bmp", $im1, bmp_compression=>0, + bmp_bit_count=>1); # the following might have slight differences $base_diff = i_img_diff($img, $im8) * 2; print "# base difference $base_diff\n"; -read_test(9, "testimg/comp4.bmp", $im4, bmp_compression=>$bi_rle4); -read_test(10, "testimg/comp8.bmp", $im8, bmp_compression=>$bi_rle8); +read_test(9, "testimg/comp4.bmp", $im4, + bmp_compression=>$bi_rle4, bmp_bit_count => 4); +read_test(10, "testimg/comp8.bmp", $im8, + bmp_compression=>$bi_rle8, bmp_bit_count => 8); my $imoo = Imager->new; if ($imoo->read(file=>'testout/t107_24bit.bmp')) { @@ -62,6 +69,90 @@ else { print "not 12 # ",$imoo->errstr,"\n"; } +# various invalid format tests +# we have so many different test images to try to detect all the possible +# failure paths in the code, adding these did detect real problems +print "# catch various types of invalid bmp files\n"; +my $test_num = 13; +my @tests = + ( + # entries in each array ref are: + # - basename of an invalid BMP file + # - error message that should be produced + # - description of what is being tested + # - possible flag to indicate testing only on 32-bit machines + [ 'badplanes.bmp', 'not a BMP file', "invalid planes value" ], + [ 'badbits.bmp', 'unknown bit count for BMP file (5)', + 'should fail to read invalid bits' ], + + # 1-bit/pixel BMPs + [ 'badused1.bmp', 'out of range colors used (3)', + 'out of range palette size (1-bit)' ], + [ 'badcomp1.bmp', 'unknown 1-bit BMP compression (1)', + 'invalid compression value (1-bit)' ], + [ 'bad1wid0.bmp', 'Image sizes must be positive', + 'width 0 (1-bit)' ], + [ 'bad4oflow.bmp', 'integer overflow calculating image allocation', + 'overflow integers on 32-bit machines (1-bit)', '32bitonly' ], + [ 'short1.bmp', 'failed reading 1-bit bmp data', + 'short 1-bit' ], + + # 4-bit/pixel BMPs + [ 'badused4a.bmp', 'out of range colors used (272)', + 'should fail to read invalid pal size (272) (4-bit)' ], + [ 'badused4b.bmp', 'out of range colors used (17)', + 'should fail to read invalid pal size (17) (4-bit)' ], + [ 'badcomp4.bmp', 'unknown 4-bit BMP compression (1)', + 'invalid compression value (4-bit)' ], + [ 'short4.bmp', 'failed reading 4-bit bmp data', + 'short uncompressed 4-bit' ], + [ 'short4rle.bmp', 'missing data during decompression', + 'short compressed 4-bit' ], + [ 'bad4wid0.bmp', 'Image sizes must be positive', + 'width 0 (4-bit)' ], + [ 'bad4widbig.bmp', 'Image sizes must be positive', + 'width big (4-bit)' ], + [ 'bad4oflow.bmp', 'integer overflow calculating image allocation', + 'overflow integers on 32-bit machines (4-bit)', '32bitonly' ], + + # 8-bit/pixel BMPs + [ 'bad8useda.bmp', 'out of range colors used (257)', + 'should fail to read invalid pal size (8-bit)' ], + [ 'bad8comp.bmp', 'unknown 8-bit BMP compression (2)', + 'invalid compression value (8-bit)' ], + [ 'short8.bmp', 'failed reading 8-bit bmp data', + 'short uncompressed 8-bit' ], + [ 'short8rle.bmp', 'missing data during decompression', + 'short compressed 8-bit' ], + [ 'bad8wid0.bmp', 'Image sizes must be positive', + 'width 0 (8-bit)' ], + [ 'bad8oflow.bmp', 'integer overflow calculating image allocation', + 'overflow integers on 32-bit machines (8-bit)', '32bitonly' ], + + # 24-bit/pixel BMPs + [ 'short24.bmp', 'failed reading image data', + 'short 24-bit' ], + [ 'bad24wid0.bmp', 'Image sizes must be positive', + 'width 0 (24-bit)' ], + [ 'bad24oflow.bmp', 'integer overflow calculating image allocation', + 'overflow integers on 32-bit machines (24-bit)', '32bitonly' ], + [ 'bad24comp.bmp', 'unknown 24-bit BMP compression (4)', + 'bad compression (24-bit)' ], + ); +use Config; +my $intsize = $Config{intsize}; +for my $test (@tests) { + my ($file, $error, $comment, $bit32only) = @$test; + if (!$bit32only || $intsize == 4) { + okn($test_num++, !$imoo->read(file=>"testimg/$file"), $comment); + isn($test_num++, $imoo->errstr, $error, "check error message"); + } + else { + skipn($test_num, 2, "only tested on 32-bit machines"); + $test_num += 2; + } +} + sub write_test { my ($test_num, $im, $filename) = @_; local *FH; @@ -86,6 +177,10 @@ sub write_test { sub read_test { my ($test_num, $filename, $im, %tags) = @_; local *FH; + + print "# read_test: $filename\n"; + + $tags{i_format} = "bmp"; if (open FH, "< $filename") { binmode FH; @@ -101,9 +196,19 @@ sub read_test { for my $tag (keys %tags) { if (my $index = Imager::i_tags_find($im_read, $tag, 0)) { my ($name, $value) = Imager::i_tags_get($im_read, $index); - if ($value != $tags{$tag}) { - print "# tag $tag value mismatch $tags{$tag} != $value\n"; - $tags_ok = 0; + my $exp_value = $tags{$tag}; + print "# tag $name = '$value' - expect '$exp_value'\n"; + if ($exp_value =~ /\d/) { + if ($value != $tags{$tag}) { + print "# tag $tag value mismatch $tags{$tag} != $value\n"; + $tags_ok = 0; + } + } + else { + if ($value ne $tags{$tag}) { + print "# tag $tag value mismatch $tags{$tag} != $value\n"; + $tags_ok = 0; + } } } }