]> git.imager.perl.org - imager.git/commitdiff
- convert t/t107bmp.t to Test::More
authorTony Cook <tony@develop=help.com>
Wed, 24 Aug 2005 01:10:49 +0000 (01:10 +0000)
committerTony Cook <tony@develop=help.com>
Wed, 24 Aug 2005 01:10:49 +0000 (01:10 +0000)
- convert t/t108tga.t to Test::More
- error messages generated reading JPEG or PNG images are now
  available via errstr()
- implement/test/document set_file_limits()/get_file_limits() methods,
  which allow limits on the size of image files read.

22 files changed:
Changes
Imager.pm
Imager.xs
Makefile.PL
TODO
bmp.c
gif.c
image.h
imagei.h
jpeg.c
lib/Imager/Files.pod
limits.c [new file with mode: 0644]
png.c
pnm.c
t/t1000files.t
t/t101jpeg.t
t/t102png.t
t/t104ppm.t
t/t105gif.t
t/t107bmp.t
t/t108tga.t
tga.c

diff --git a/Changes b/Changes
index 34243b4f828d3a1cb33d29dbb1d1ad8e44bb5af7..f6c467047adc645cb0fd609c8f56cda28fc6b433 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1126,6 +1126,10 @@ Revision history for Perl extension Imager.
   parameter and $ENV{HOME} not set.
 - added VERSION numbers to most .pms
 - convert t/t104ppm.t to Test::More
+- convert t/t107bmp.t to Test::More
+- convert t/t108tga.t to Test::More
+- error messages generated reading JPEG or PNG images are now
+  available via errstr()
 
 =================================================================
 
index fd4280e678080c323deeca610d9f343090887cd1..c888d5eb22dc9785c60c9ea88dbe6443e4b48443 100644 (file)
--- a/Imager.pm
+++ b/Imager.pm
@@ -1142,7 +1142,7 @@ sub read {
   if ( $input{'type'} eq 'jpeg' ) {
     ($self->{IMG},$self->{IPTCRAW}) = i_readjpeg_wiol( $IO );
     if ( !defined($self->{IMG}) ) {
-      $self->{ERRSTR}='unable to read jpeg image'; return undef;
+      $self->{ERRSTR}=$self->_error_as_msg(); return undef;
     }
     $self->{DEBUG} && print "loading a jpeg file\n";
     return $self;
@@ -1169,7 +1169,7 @@ sub read {
   if ( $input{'type'} eq 'png' ) {
     $self->{IMG}=i_readpng_wiol( $IO, -1 ); # Fixme, check if that length parameter is ever needed
     if ( !defined($self->{IMG}) ) {
-      $self->{ERRSTR}='unable to read png image';
+      $self->{ERRSTR} = $self->_error_as_msg();
       return undef;
     }
     $self->{DEBUG} && print "loading a png file\n";
@@ -2632,6 +2632,32 @@ sub string {
   return $self;
 }
 
+my @file_limit_names = qw/width height bytes/;
+
+sub set_file_limits {
+  shift;
+
+  my %opts = @_;
+  my %values;
+  
+  if ($opts{reset}) {
+    @values{@file_limit_names} = (0) x @file_limit_names;
+  }
+  else {
+    @values{@file_limit_names} = i_get_image_file_limits();
+  }
+
+  for my $key (keys %values) {
+    defined $opts{$key} and $values{$key} = $opts{$key};
+  }
+
+  i_set_image_file_limits($values{width}, $values{height}, $values{bytes});
+}
+
+sub get_file_limits {
+  i_get_image_file_limits();
+}
+
 # Shortcuts that can be exported
 
 sub newcolor { Imager::Color->new(@_); }
@@ -2956,6 +2982,8 @@ getcolorcount() -  L<Imager::ImageTypes>
 getcolors() - L<Imager::ImageTypes> - get colors from the image
 palette, if it has one
 
+get_file_limits() - L<Imager::Files/"Limiting the sizes of images you read">
+
 getheight() - L<Imager::ImageTypes>
 
 getpixel() - L<Imager::Draw/setpixel and getpixel>
@@ -3005,6 +3033,8 @@ setcolors() - L<Imager::ImageTypes> - set palette colors in a paletted image
 
 setpixel() - L<Imager::Draw/setpixel and getpixel>
 
+set_file_limits() - L<Imager::Files/"Limiting the sizes of images you read">
+
 string() - L<Imager::Font/string> - draw text on an image
 
 tags() -  L<Imager::ImageTypes> - fetch image tags
@@ -3101,6 +3131,8 @@ invert image - L<Imager::Filter/hardinvert>
 
 JPEG - L<Imager::Files/"JPEG">
 
+limiting image sizes - L<Imager::Files/"Limiting the sizes of images you read">
+
 lines, drawing - L<Imager::Draw/line>
 
 matrix - L<Imager::Matrix2d>, 
index 3e0e4d3a41e02e303b4a8ae784fb6a2d79a3200b..43ea0d85691814c05db310d1eecbd05026bfe10f 100644 (file)
--- a/Imager.xs
+++ b/Imager.xs
@@ -943,7 +943,6 @@ i_rgb_to_hsv(c)
         i_rgb_to_hsvf(RETVAL);
       OUTPUT:
         RETVAL
-        
 
 MODULE = Imager                PACKAGE = Imager::ImgRaw        PREFIX = IIM_
 
@@ -1026,6 +1025,24 @@ io_slurp(ig)
               myfree(data);
 
 
+undef_int
+i_set_image_file_limits(width, height, bytes)
+       int width
+       int height
+       int bytes
+
+void
+i_get_image_file_limits()
+      PREINIT:
+        int width, height, bytes;
+      PPCODE:
+        if (i_get_image_file_limits(&width, &height, &bytes)) {
+         EXTEND(SP, 3);
+          PUSHs(sv_2mortal(newSViv(width)));
+          PUSHs(sv_2mortal(newSViv(height)));
+          PUSHs(sv_2mortal(newSViv(bytes)));
+        }
+
 MODULE = Imager                PACKAGE = Imager::IO    PREFIX = io_glue_
 
 void
index d01aae6fd1c924121328f4da434bb314e321464b..0262e44b2196e764e91657dff6623d69a40503ce 100644 (file)
@@ -102,7 +102,7 @@ if (defined $Config{'d_dlsymun'}) { $OSDEF  .= ' -DDLSYMUN'; }
           filters.o dynaload.o stackmach.o datatypes.o
           regmach.o trans2.o quant.o error.o convert.o
           map.o tags.o palimg.o maskimg.o img16.o rotate.o
-           bmp.o tga.o rgb.o color.o fills.o imgdouble.o);
+           bmp.o tga.o rgb.o color.o fills.o imgdouble.o limits.o);
 
 %opts=(
        'NAME'         => 'Imager',
diff --git a/TODO b/TODO
index d72e4f789446d8e2d234732017273524b40d38bc..7d31e142ee9bf4abc1f6f7c09489143fd600b44a 100644 (file)
--- a/TODO
+++ b/TODO
@@ -14,15 +14,15 @@ not commitments.
    - check llist_push() calls
 
 - fix Imager::Color warning when $ENV{HOME} isn't set from
-  _get_gimp_color()
+  _get_gimp_color() (done)
   http://rt.cpan.org/NoAuth/Bug.html?id=13143
 
-- module version numbers
-  http://rt.cpan.org/NoAuth/Bug.html?id=13047
+- module version numbers (done)
+  http://rt.cpan.org/NoAuth/Bug.html?id=13047 
 
 - allow limits to be set on the size of an image read from a file.  This is
   to prevent an attacker supplying huge images that consume all of 
-  memory causing a denial of service attack.
+  memory causing a denial of service attack. (done)
 
 - implement gsamp()/gsampf()/plin() etc methods for those low level image
   interfaces which don't yet have methods.
@@ -50,7 +50,7 @@ not commitments.
     http://nntp.perl.org/group/perl.perl5.porters/102434
   (#1521, #5608, #8231, #11429, #13058)
 
-- have $img->read() act like ($img) = Imager->read_multi()
+- have $img->read() act like ($img) = Imager->read_multi() on GIFs
 
 - figure out what the nearest_color filter does, and document it
 
diff --git a/bmp.c b/bmp.c
index b78d55337bdfd9c0b76d5fd11d4a38436ebd7531..2e55f52a0ab00c5347ff4806086a32e205f11dea 100644 (file)
--- a/bmp.c
+++ b/bmp.c
@@ -1,5 +1,5 @@
-#include "image.h"
 #include <stdarg.h>
+#include "imagei.h"
 
 /*
 =head1 NAME
@@ -132,6 +132,11 @@ i_readbmp_wiol(io_glue *ig) {
           "clr_important %d\n", filesize, offbits, xsize, ysize, planes, 
           bit_count, compression, size_image, xres, yres, clr_used, 
           clr_important));
+
+  if (!i_int_check_image_file_limits(xsize, ysize, 3, sizeof(i_sample_t))) {
+    mm_log((1, "i_readbmp_wiol: image size exceeds limits\n"));
+    return NULL;
+  }
   
   switch (bit_count) {
   case 1:
diff --git a/gif.c b/gif.c
index 6d6255afed87f0db8b98cbf304e4f1d2e4b51e62..a426f1c897a925c1c2c3579876c5b43613dcfab8 100644 (file)
--- a/gif.c
+++ b/gif.c
@@ -1,4 +1,4 @@
-#include "image.h"
+#include "imagei.h"
 #include <gif_lib.h>
 #ifdef _MSCVER
 #include <io.h>
@@ -177,6 +177,15 @@ i_readgif_low(GifFileType *GifFile, int **colour_table, int *colours) {
     cmapcnt++;
   }
   
+  if (!i_int_check_image_file_limits(GifFile->SWidth, GifFile->SHeight, 3, sizeof(i_sample_t))) {
+    if (colour_table && *colour_table) {
+      myfree(*colour_table);
+      *colour_table = NULL;
+    }
+    DGifCloseFile(GifFile);
+    mm_log((1, "i_readgif: image size exceeds limits\n"));
+    return NULL;
+  }
 
   im = i_img_empty_ch(NULL, GifFile->SWidth, GifFile->SHeight, 3);
   if (!im) {
@@ -564,6 +573,11 @@ i_img **i_readgif_multi_low(GifFileType *GifFile, int *count) {
       channels = 3;
       if (got_gce && trans_index >= 0)
         channels = 4;
+      if (!i_int_check_image_file_limits(Width, Height, channels, sizeof(i_sample_t))) {
+       free_images(results, *count);
+       mm_log((1, "i_readgif: image size exceeds limits\n"));
+       return NULL;
+      }
       img = i_img_pal_new(Width, Height, channels, 256);
       if (!img) {
         free_images(results, *count);
diff --git a/image.h b/image.h
index 1de0b5cba253d612af239aad0a793369b432edf3..3ea6c4ebcf2a84da4439042319767f7f3cdf6f7a 100644 (file)
--- a/image.h
+++ b/image.h
@@ -793,4 +793,10 @@ extern int i_tags_set_color(i_img_tags *tags, char const *name, int code,
                             i_color const *value);
 extern void i_tags_print(i_img_tags *tags);
 
+/* image file limits */
+extern int
+i_set_image_file_limits(int width, int height, int bytes);
+extern int
+i_get_image_file_limits(int *width, int *height, int *bytes);
+
 #endif
index 3f2133d9a2ddd227f2548852760aa913aac22e5f..1dc7f4cdeb7f19dd769d63d03fbdcce53c3b7e58 100644 (file)
--- a/imagei.h
+++ b/imagei.h
@@ -41,6 +41,9 @@ extern int i_setcolors_forward(i_img *im, int index, i_color *colors,
 
 extern void i_get_combine(int combine, i_fill_combine_f *, i_fill_combinef_f *);
 
+extern int
+i_int_check_image_file_limits(int width, int height, int channels, int sample_size);
+
 #include "ext.h"
 
 extern UTIL_table_t i_UTIL_table;
diff --git a/jpeg.c b/jpeg.c
index 8437575fc3e2567a8b59051a256eac42ec108319..84bc9e3acd78ee444751c2e0ecaeb6f04b8ed198 100644 (file)
--- a/jpeg.c
+++ b/jpeg.c
@@ -28,7 +28,7 @@ Reads and writes JPEG images
 #include <setjmp.h>
 
 #include "iolayer.h"
-#include "image.h"
+#include "imagei.h"
 #include "jpeglib.h"
 #include "jerror.h"
 #include <errno.h>
@@ -370,6 +370,13 @@ i_readjpeg_wiol(io_glue *data, int length, char** iptc_itext, int *itlength) {
 
   (void) jpeg_read_header(&cinfo, TRUE);
   (void) jpeg_start_decompress(&cinfo);
+  if (!i_int_check_image_file_limits(cinfo.output_width, cinfo.output_height,
+                                    cinfo.output_components, sizeof(i_sample_t))) {
+    mm_log((1, "i_readjpeg: image size exceeds limits\n"));
+
+    jpeg_destroy_decompress(&cinfo);
+    return NULL;
+  }
   im=i_img_empty_ch(NULL,cinfo.output_width,cinfo.output_height,cinfo.output_components);
   if (!im) {
     jpeg_destroy_decompress(&cinfo);
index 12ab284588fb9546df23f1572e6047490e596c52..b78b6ea10d8042a497d3a64aeafaeae5a65cac70 100644 (file)
@@ -18,6 +18,8 @@ Imager::Files - working with image files
   my @imgs = Imager->read_multi(file=>$filename)
     or die "Cannot read: ", Imager->errstr;
 
+  Imager->set_file_limits(width=>$max_width, height=>$max_height)
+
 =head1 DESCRIPTION
 
 You can read and write a variety of images formats, assuming you have
@@ -167,6 +169,64 @@ Return either a valid Imager file type, or undef.
   # I'm writing jpegs to weird filenames
   local $Imager::FORMATGUESS = sub { 'jpeg' };
 
+=head2 Limiting the sizes of images you read
+
+In some cases you will be receiving images from an untested source,
+such as submissions via CGI.  To prevent such images from consuming
+large amounts of memory, you can set limits on the dimensions of
+images you read from files:
+
+=over
+
+=item *
+
+width - limit the width in pixels of the image
+
+=item *
+
+height - limit the height in pixels of the image
+
+=item *
+
+bytes - limits the amount of storage used by the image.  This depends
+on the width, height, channels and sample size of the image.  For
+paletted images this is calculated as if the image was expanded to a
+direct color image.
+
+=back
+
+To set the limits, call the class method set_file_limits:
+
+  Imager->set_file_limits(width=>$max_width, height=>$max_height);
+
+You can pass any or all of the limits above, any limits you do not
+pass are left as they were.
+
+Any limit of zero is treated as unlimited.
+
+By default, all of the limits are zero, or unlimited.
+
+You can reset all of the limited to their defaults by passing in the
+reset parameter as a true value:
+
+  # no limits
+  Imager->set_file_limits(reset=>1);
+
+This can be used with the other limits to reset all but the limit you
+pass:
+
+  # only width is limited
+  Imager->set_file_limits(reset=>1, width=>100);
+
+  # only bytes is limited
+  Imager->set_file_limits(reset=>1, bytes=>10_000_000);
+
+You can get the current limits with the get_file_limits() method:
+
+  my ($max_width, $max_height, $max_bytes) =
+     Imager->get_file_limits();
+
+
 =head1 TYPE SPECIFIC INFORMATION
 
 The different image formats can write different image type, and some have
diff --git a/limits.c b/limits.c
new file mode 100644 (file)
index 0000000..01e8902
--- /dev/null
+++ b/limits.c
@@ -0,0 +1,125 @@
+/*
+=head1 NAME
+
+limits.c - manages data/functions for limiting the sizes of images read from files.
+
+=head1 SYNOPSIS
+
+  // user code
+  if (!i_set_image_file_limits(max_width, max_height, max_bytes)) {
+    // error
+  }
+  i_get_image_file_limits(&max_width, &max_height, &max_bytes);
+
+  // file reader implementations
+  if (!i_int_check_image_file_limits(width, height, channels, sizeof(i_sample_t))) {
+    // error handling
+  }
+
+=head1 DESCRIPTION
+
+Manage limits for image files read by Imager.
+
+Setting a value of zero means that limit will be ignored.
+  
+ */
+
+#include "imagei.h"
+
+static int max_width, max_height;
+static int max_bytes;
+
+int
+i_set_image_file_limits(int width, int height, int bytes) {
+  i_clear_error();
+
+  if (width < 0) {
+    i_push_error(0, "width must be non-negative");
+    return 0;
+  }
+  if (height < 0) {
+    i_push_error(0, "height must be non-negative");
+    return 0;
+  }
+  if (bytes < 0) {
+    i_push_error(0, "bytes must be non-negative");
+    return 0;
+  }
+
+  max_width = width;
+  max_height = height;
+  max_bytes = bytes;
+
+  return 1;
+}
+
+int
+i_get_image_file_limits(int *width, int *height, int *bytes) {
+  i_clear_error();
+
+  *width = max_width;
+  *height = max_height;
+  *bytes = max_bytes;
+
+  return 1;
+}
+
+int
+i_int_check_image_file_limits(int width, int height, int channels, int sample_size) {
+  i_clear_error();
+  
+  if (width <= 0) {
+    i_push_errorf(0, "file size limit - image width of %d is not positive",
+                 width);
+    return 0;
+  }
+  if (max_width && width > max_width) {
+    i_push_errorf(0, "file size limit - image width of %d exceeds limit of %d",
+                width, max_width);
+    return 0;
+  }
+
+  if (height <= 0) {
+    i_push_errorf(0, "file size limit - image height %d is not positive",
+                 height);
+    return 0;
+  }
+
+  if (max_height && height > max_height) {
+    i_push_errorf(0, "file size limit - image height of %d "
+                 "exceeds limit of %d", height, max_height);
+    return 0;
+  }
+
+  if (channels < 1 || channels > MAXCHANNELS) {
+    i_push_errorf(0, "file size limit - channels %d out of range",
+                 channels);
+    return 0;
+  }
+  
+  if (sample_size < 1 || sample_size > sizeof(long double)) {
+    i_push_errorf(0, "file size limit - sample_size %d out of range",
+                 sample_size);
+    return 0;
+  }
+
+  /* This overflow check is a bit more paranoid than usual.
+     We don't protect it under max_bytes since we always want to check 
+     for overflow.
+  */
+  int bytes = width * height * channels * sample_size;
+  if (bytes / width != height * channels * sample_size
+      || bytes / height != width * channels * sample_size) {
+    i_push_error(0, "file size limit - integer overflow calculating storage");
+    return 0;
+  }
+  if (max_bytes) {
+    if (bytes > max_bytes) {
+      i_push_errorf(0, "file size limit - storage size of %d "
+                   "exceeds limit of %d", bytes, max_bytes);
+      return 0;
+    }
+  }
+
+  return 1;
+}
diff --git a/png.c b/png.c
index 728593759facd606e97c9a22113d8bf703cc4529..684d53f971e854b97724dd70b552cd27ff0bda47 100644 (file)
--- a/png.c
+++ b/png.c
@@ -1,5 +1,5 @@
 #include "iolayer.h"
-#include "image.h"
+#include "imagei.h"
 #include "png.h"
 
 /* Check to see if a file is a PNG file using png_sig_cmp().  png_sig_cmp()
@@ -237,6 +237,12 @@ i_readpng_wiol(io_glue *ig, int length) {
 
   mm_log((1,"i_readpng_wiol: channels %d\n",channels));
 
+  if (!i_int_check_image_file_limits(width, height, channels, sizeof(i_sample_t))) {
+    mm_log((1, "i_readpnm: image size exceeds limits\n"));
+    png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+    return NULL;
+  }
+
   png_set_strip_16(png_ptr);
   png_set_packing(png_ptr);
   if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr);
diff --git a/pnm.c b/pnm.c
index fd9b585861a8a53a29241d7dcc418556fa59b316..eef179973ee830763462fbeb89f9e796f0823153 100644 (file)
--- a/pnm.c
+++ b/pnm.c
@@ -1,6 +1,7 @@
 #include "image.h"
 #include "log.h"
 #include "iolayer.h"
+#include "imagei.h"
 
 #include <stdlib.h>
 #include <errno.h>
@@ -343,6 +344,11 @@ i_readpnm_wiol(io_glue *ig, int length) {
   channels = (type == 3 || type == 6) ? 3:1;
   pcount = width*height*channels;
 
+  if (!i_int_check_image_file_limits(width, height, channels, sizeof(i_sample_t))) {
+    mm_log((1, "i_readpnm: image size exceeds limits\n"));
+    return NULL;
+  }
+
   mm_log((1, "i_readpnm: (%d x %d), channels = %d, maxval = %d\n", width, height, channels, maxval));
   
   im = i_img_empty_ch(NULL, width, height, channels);
index e7938eeb6b0feff73bf335525779f0ac894f8721..0497fdfaee8fa706757cde8ef926596c222b86bf 100644 (file)
@@ -5,7 +5,7 @@
 
 use strict;
 use lib 't';
-use Test::More tests => 3;
+use Test::More tests => 12;
 use Imager;
 
 Imager::init_log("testout/t1000files.log", 1);
@@ -45,3 +45,23 @@ PERL
   is($out, '', "output should be empty");
 }
 
+# test the file limit functions
+# by default the limits are zero (unlimited)
+print "# image file limits\n";
+is_deeply([ Imager->get_file_limits() ], [0, 0, 0],
+         "check defaults");
+ok(Imager->set_file_limits(width=>100), "set only width");
+is_deeply([ Imager->get_file_limits() ], [100, 0, 0 ],
+         "check width set");
+ok(Imager->set_file_limits(height=>150, bytes=>10000),
+   "set height and bytes");
+is_deeply([ Imager->get_file_limits() ], [ 100, 150, 10000 ],
+         "check all values now set");
+ok(Imager->set_file_limits(reset=>1, height => 99),
+   "set height and reset");
+is_deeply([ Imager->get_file_limits() ], [ 0, 99, 0 ],
+         "check only height is set");
+ok(Imager->set_file_limits(reset=>1),
+   "just reset");
+is_deeply([ Imager->get_file_limits() ], [ 0, 0, 0 ],
+         "check all are reset");
index fdb79d12ee93d0adb3ccd7475f6ee64dead981de..b99f0448c51bb765e371080aadf1fae273c85e46 100644 (file)
@@ -2,7 +2,7 @@
 use strict;
 use lib 't';
 use Imager qw(:all);
-use Test::More tests => 9;
+use Test::More tests => 24;
 
 init_log("testout/t101jpeg.log",1);
 
@@ -74,5 +74,41 @@ if (!i_has_format("jpeg")) {
   # check that the i_format tag is set
   my @fmt = $imoo->tags(name=>'i_format');
   is($fmt[0], 'jpeg', 'i_format tag');
+
+  { # check file limits are checked
+    my $limit_file = "testout/t101.jpg";
+    ok(Imager->set_file_limits(reset=>1, width=>149), "set width limit 149");
+    my $im = Imager->new;
+    ok(!$im->read(file=>$limit_file),
+       "should fail read due to size limits");
+    print "# ",$im->errstr,"\n";
+    like($im->errstr, qr/image width/, "check message");
+    
+    ok(Imager->set_file_limits(reset=>1, height=>149), "set height limit 149");
+    ok(!$im->read(file=>$limit_file),
+       "should fail read due to size limits");
+    print "# ",$im->errstr,"\n";
+    like($im->errstr, qr/image height/, "check message");
+    
+    ok(Imager->set_file_limits(reset=>1, width=>150), "set width limit 150");
+    ok($im->read(file=>$limit_file),
+       "should succeed - just inside width limit");
+    ok(Imager->set_file_limits(reset=>1, height=>150), "set height limit 150");
+    ok($im->read(file=>$limit_file),
+       "should succeed - just inside height limit");
+    
+    # 150 x 150 x 3 channel image uses 67500 bytes
+    ok(Imager->set_file_limits(reset=>1, bytes=>67499),
+       "set bytes limit 67499");
+    ok(!$im->read(file=>$limit_file),
+       "should fail - too many bytes");
+    print "# ",$im->errstr,"\n";
+    like($im->errstr, qr/storage size/, "check error message");
+    ok(Imager->set_file_limits(reset=>1, bytes=>67500),
+       "set bytes limit 67500");
+    ok($im->read(file=>$limit_file),
+       "should succeed - just inside bytes limit");
+    Imager->set_file_limits(reset=>1);
+  }
 }
 
index dc4dc065f2e1bf51bd58b91537b583ee4b6bd6ba..f3bcad4fe5623f460500d487fdc2cbdf2bcf4cca 100644 (file)
@@ -1,7 +1,7 @@
 #!perl -w
 use strict;
 use lib 't';
-use Test::More tests => 13;
+use Test::More tests => 28;
 # Before `make install' is performed this script should be runnable with
 # `make test'. After `make install' it should work as `perl test.pl'
 
@@ -115,4 +115,41 @@ if (!i_has_format("png")) {
 # upgrade libpng
 EOS
   }
+
+  { # check file limits are checked
+    my $limit_file = "testout/t102.png";
+    ok(Imager->set_file_limits(reset=>1, width=>149), "set width limit 149");
+    my $im = Imager->new;
+    ok(!$im->read(file=>$limit_file),
+       "should fail read due to size limits");
+    print "# ",$im->errstr,"\n";
+    like($im->errstr, qr/image width/, "check message");
+    
+    ok(Imager->set_file_limits(reset=>1, height=>149), "set height limit 149");
+    ok(!$im->read(file=>$limit_file),
+       "should fail read due to size limits");
+    print "# ",$im->errstr,"\n";
+    like($im->errstr, qr/image height/, "check message");
+    
+    ok(Imager->set_file_limits(reset=>1, width=>150), "set width limit 150");
+    ok($im->read(file=>$limit_file),
+       "should succeed - just inside width limit");
+    ok(Imager->set_file_limits(reset=>1, height=>150), "set height limit 150");
+    ok($im->read(file=>$limit_file),
+       "should succeed - just inside height limit");
+    
+    # 150 x 150 x 3 channel image uses 67500 bytes
+    ok(Imager->set_file_limits(reset=>1, bytes=>67499),
+       "set bytes limit 67499");
+    ok(!$im->read(file=>$limit_file),
+       "should fail - too many bytes");
+    print "# ",$im->errstr,"\n";
+    like($im->errstr, qr/storage size/, "check error message");
+    ok(Imager->set_file_limits(reset=>1, bytes=>67500),
+       "set bytes limit 67500");
+    ok($im->read(file=>$limit_file),
+       "should succeed - just inside bytes limit");
+    Imager->set_file_limits(reset=>1);
+  }
+
 }
index e6e28790db59e32356066a17ae54be2fb2d4fca8..da4eb38f22893899c2c204423a007a928c6ecf57 100644 (file)
@@ -1,11 +1,9 @@
 #!perl -w
 use Imager ':all';
-use Test::More tests => 45;
-BEGIN { require "t/testtools.pl"; }
+use lib 't';
+use Test::More tests => 60;
 use strict;
 
-print "1..45\n";
-
 init_log("testout/t104ppm.log",1);
 
 my $green = i_color_new(0,255,0,255);
@@ -161,6 +159,42 @@ check_gray(Imager::i_get_pixel($ooim->{IMG}, 1, 1), 255);
   is($type, 'pnm', "check i_format");
 }
 
+{ # check file limits are checked
+  my $limit_file = "testout/t104.ppm";
+  ok(Imager->set_file_limits(reset=>1, width=>149), "set width limit 149");
+  my $im = Imager->new;
+  ok(!$im->read(file=>$limit_file),
+     "should fail read due to size limits");
+  print "# ",$im->errstr,"\n";
+  like($im->errstr, qr/image width/, "check message");
+
+  ok(Imager->set_file_limits(reset=>1, height=>149), "set height limit 149");
+  ok(!$im->read(file=>$limit_file),
+     "should fail read due to size limits");
+  print "# ",$im->errstr,"\n";
+  like($im->errstr, qr/image height/, "check message");
+
+  ok(Imager->set_file_limits(reset=>1, width=>150), "set width limit 150");
+  ok($im->read(file=>$limit_file),
+     "should succeed - just inside width limit");
+  ok(Imager->set_file_limits(reset=>1, height=>150), "set height limit 150");
+  ok($im->read(file=>$limit_file),
+     "should succeed - just inside height limit");
+  
+  # 150 x 150 x 3 channel image uses 67500 bytes
+  ok(Imager->set_file_limits(reset=>1, bytes=>67499),
+     "set bytes limit 67499");
+  ok(!$im->read(file=>$limit_file),
+     "should fail - too many bytes");
+  print "# ",$im->errstr,"\n";
+  like($im->errstr, qr/storage size/, "check error message");
+  ok(Imager->set_file_limits(reset=>1, bytes=>67500),
+     "set bytes limit 67500");
+  ok($im->read(file=>$limit_file),
+     "should succeed - just inside bytes limit");
+  Imager->set_file_limits(reset=>1);
+}
+
 sub openimage {
   my $fname = shift;
   local(*FH);
index e6b386b2894eb3cd891e7449e871c3ece7b5ed26..084c15651a7695832f886fe37304693fcd1d68ee 100644 (file)
@@ -2,7 +2,7 @@
 use strict;
 $|=1;
 use lib 't';
-use Test::More tests => 69;
+use Test::More tests => 84;
 use Imager qw(:all);
 BEGIN { require "t/testtools.pl"; }
 use Carp 'confess';
@@ -528,6 +528,42 @@ EOS
       my ($type) = $im->tags(name=>'i_format');
       is($type, 'gif', 'check i_format for single image read');
     }
+
+  { # check file limits are checked
+    my $limit_file = "testout/t105.gif";
+    ok(Imager->set_file_limits(reset=>1, width=>149), "set width limit 149");
+    my $im = Imager->new;
+    ok(!$im->read(file=>$limit_file),
+       "should fail read due to size limits");
+    print "# ",$im->errstr,"\n";
+    like($im->errstr, qr/image width/, "check message");
+    
+    ok(Imager->set_file_limits(reset=>1, height=>149), "set height limit 149");
+    ok(!$im->read(file=>$limit_file),
+       "should fail read due to size limits");
+    print "# ",$im->errstr,"\n";
+    like($im->errstr, qr/image height/, "check message");
+    
+    ok(Imager->set_file_limits(reset=>1, width=>150), "set width limit 150");
+    ok($im->read(file=>$limit_file),
+       "should succeed - just inside width limit");
+    ok(Imager->set_file_limits(reset=>1, height=>150), "set height limit 150");
+    ok($im->read(file=>$limit_file),
+       "should succeed - just inside height limit");
+    
+    # 150 x 150 x 3 channel image uses 67500 bytes
+    ok(Imager->set_file_limits(reset=>1, bytes=>67499),
+       "set bytes limit 67499");
+    ok(!$im->read(file=>$limit_file),
+       "should fail - too many bytes");
+    print "# ",$im->errstr,"\n";
+    like($im->errstr, qr/storage size/, "check error message");
+    ok(Imager->set_file_limits(reset=>1, bytes=>67500),
+       "set bytes limit 67500");
+    ok($im->read(file=>$limit_file),
+       "should succeed - just inside bytes limit");
+    Imager->set_file_limits(reset=>1);
+  }
 }
 
 sub test_readgif_cb {
index ba1981cc2187b3155206b78bdab2eb1254821172..014b440c6040b5d02aef86eb093ce93379a0d5cf 100644 (file)
@@ -1,9 +1,10 @@
 #!perl -w
-print "1..74\n";
-use Imager qw(:all);
 use strict;
+use lib 't';
+use Test::More tests => 89;
+use Imager qw(:all);
 init_log("testout/t107bmp.log",1);
-BEGIN { require 't/testtools.pl'; } # BEGIN to apply prototypes
+#BEGIN { require 't/testtools.pl'; } # BEGIN to apply prototypes
 
 my $base_diff = 0;
 # if you change this make sure you generate new compressed versions
@@ -20,60 +21,53 @@ i_conv($img,[0.1, 0.2, 0.4, 0.2, 0.1]);
 
 Imager::i_tags_add($img, 'i_xres', 0, '300', 0);
 Imager::i_tags_add($img, 'i_yres', 0, undef, 300);
-write_test(1, $img, "testout/t107_24bit.bmp");
+write_test($img, "testout/t107_24bit.bmp");
 # 'webmap' is noticably faster than the default
 my $im8 = Imager::i_img_to_pal($img, { make_colors=>'webmap', 
                                       translate=>'errdiff'});
-write_test(2, $im8, "testout/t107_8bit.bmp");
+write_test($im8, "testout/t107_8bit.bmp");
 # use a fixed palette so we get reproducible results for the compressed
 # version
 my @pal16 = map { NC($_) } 
   qw(605844 966600 0148b2 00f800 bf0a33 5e009e
      2ead1b 0000f8 004b01 fd0000 0e1695 000002);
 my $im4 = Imager::i_img_to_pal($img, { colors=>\@pal16, make_colors=>'none' });
-write_test(3, $im4, "testout/t107_4bit.bmp");
+write_test($im4, "testout/t107_4bit.bmp");
 my $im1 = Imager::i_img_to_pal($img, { colors=>[ NC(0, 0, 0), NC(176, 160, 144) ],
                               make_colors=>'none', translate=>'errdiff' });
-write_test(4, $im1, "testout/t107_1bit.bmp");
+write_test($im1, "testout/t107_1bit.bmp");
 my $bi_rgb = 0;
 my $bi_rle8 = 1;
 my $bi_rle4 = 2;
 my $bi_bitfields = 3;
-read_test(5, "testout/t107_24bit.bmp", $img, 
+read_test("testout/t107_24bit.bmp", $img, 
           bmp_compression=>0, bmp_bit_count => 24);
-read_test(6, "testout/t107_8bit.bmp", $im8, 
+read_test("testout/t107_8bit.bmp", $im8, 
           bmp_compression=>0, bmp_bit_count => 8);
-read_test(7, "testout/t107_4bit.bmp", $im4, 
+read_test("testout/t107_4bit.bmp", $im4, 
           bmp_compression=>0, bmp_bit_count => 4);
-read_test(8, "testout/t107_1bit.bmp", $im1, bmp_compression=>0, 
+read_test("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, 
+read_test("testimg/comp4.bmp", $im4, 
           bmp_compression=>$bi_rle4, bmp_bit_count => 4);
-read_test(10, "testimg/comp8.bmp", $im8, 
+read_test("testimg/comp8.bmp", $im8, 
           bmp_compression=>$bi_rle8, bmp_bit_count => 8);
 
 my $imoo = Imager->new;
-if ($imoo->read(file=>'testout/t107_24bit.bmp')) {
-  print "ok 11\n";
-}
-else {
-  print "not ok 11 # ",$imoo->errstr,"\n";
-}
-if ($imoo->write(file=>'testout/t107_oo.bmp')) {
-  print "ok 12\n";
-}
-else {
-  print "not 12 # ",$imoo->errstr,"\n";
-}
+# read via OO
+ok($imoo->read(file=>'testout/t107_24bit.bmp'), "read via OO")
+  or print "# ",$imoo->errstr,"\n";
+
+ok($imoo->write(file=>'testout/t107_oo.bmp'), "write via OO")
+  or print "# ",$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:
@@ -90,9 +84,10 @@ my @tests =
      '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',
+   [ 'bad1wid0.bmp', 'file size limit - image width of 0 is not positive',
      'width 0 (1-bit)' ],
-   [ 'bad4oflow.bmp', 'integer overflow calculating image allocation',
+   [ 'bad4oflow.bmp', 
+     'file size limit - integer overflow calculating storage',
      'overflow integers on 32-bit machines (1-bit)', '32bitonly' ],
    [ 'short1.bmp', 'failed reading 1-bit bmp data', 
      'short 1-bit' ],
@@ -108,11 +103,11 @@ my @tests =
      'short uncompressed 4-bit' ],
    [ 'short4rle.bmp', 'missing data during decompression', 
      'short compressed 4-bit' ],
-   [ 'bad4wid0.bmp', 'Image sizes must be positive',
+   [ 'bad4wid0.bmp', 'file size limit - image width of 0 is not positive',
      'width 0 (4-bit)' ],
-   [ 'bad4widbig.bmp', 'Image sizes must be positive',
+   [ 'bad4widbig.bmp', 'file size limit - image width of -2147483628 is not positive',
      'width big (4-bit)' ],
-   [ 'bad4oflow.bmp', 'integer overflow calculating image allocation',
+   [ 'bad4oflow.bmp', 'file size limit - integer overflow calculating storage',
      'overflow integers on 32-bit machines (4-bit)', '32bitonly' ],
 
    # 8-bit/pixel BMPs
@@ -124,17 +119,17 @@ my @tests =
      'short uncompressed 8-bit' ],
    [ 'short8rle.bmp', 'missing data during decompression', 
      'short compressed 8-bit' ],
-   [ 'bad8wid0.bmp', 'Image sizes must be positive',
+   [ 'bad8wid0.bmp', 'file size limit - image width of 0 is not positive',
      'width 0 (8-bit)' ],
-   [ 'bad8oflow.bmp', 'integer overflow calculating image allocation',
+   [ 'bad8oflow.bmp', 'file size limit - integer overflow calculating storage',
      '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',
+   [ 'bad24wid0.bmp', 'file size limit - image width of 0 is not positive',
      'width 0 (24-bit)' ],
-   [ 'bad24oflow.bmp', 'integer overflow calculating image allocation',
+   [ 'bad24oflow.bmp', 'file size limit - integer overflow calculating storage',
      'overflow integers on 32-bit machines (24-bit)', '32bitonly' ],
    [ 'bad24comp.bmp', 'unknown 24-bit BMP compression (4)',
      'bad compression (24-bit)' ],
@@ -143,13 +138,12 @@ 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;
+ SKIP:
+  {
+    skip("only tested on 32-bit machines", 2)
+      if $bit32only && $intsize != 4;
+    ok(!$imoo->read(file=>"testimg/$file"), $comment);
+    is($imoo->errstr, $error, "check error message");
   }
 }
 
@@ -171,46 +165,79 @@ for my $comp (@comp) {
 
   my $base_im = Imager->new;
   my $got_base = 
-    okn($test_num++, $base_im->read(file=>"testimg/$base_file"),
+    ok($base_im->read(file=>"testimg/$base_file"),
         "read original")
       or print "# ",$base_im->errstr,"\n";
   my $off_im = Imager->new;
   my $got_off =
-    okn($test_num++, $off_im->read(file=>"testimg/$off_file"),
+    ok($off_im->read(file=>"testimg/$off_file"),
         "read offset file")
       or print "# ",$off_im->errstr,"\n";
-  if ($got_base && $got_off) {
-    okn($test_num++, !i_img_diff($base_im->{IMG}, $off_im->{IMG}), 
+ SKIP:
+  {
+    skip("missed one file", 1)
+      unless $got_base && $got_off;
+    is(i_img_diff($base_im->{IMG}, $off_im->{IMG}), 0,
         "compare base and offset image ($bits bits)");
   }
-  else {
-    skipn($test_num++, 1, "missed one file");
-  }
+}
+
+{ # check file limits are checked
+  my $limit_file = "testout/t104.ppm";
+  ok(Imager->set_file_limits(reset=>1, width=>149), "set width limit 149");
+  my $im = Imager->new;
+  ok(!$im->read(file=>$limit_file),
+     "should fail read due to size limits");
+  print "# ",$im->errstr,"\n";
+  like($im->errstr, qr/image width/, "check message");
+
+  ok(Imager->set_file_limits(reset=>1, height=>149), "set height limit 149");
+  ok(!$im->read(file=>$limit_file),
+     "should fail read due to size limits");
+  print "# ",$im->errstr,"\n";
+  like($im->errstr, qr/image height/, "check message");
+
+  ok(Imager->set_file_limits(reset=>1, width=>150), "set width limit 150");
+  ok($im->read(file=>$limit_file),
+     "should succeed - just inside width limit");
+  ok(Imager->set_file_limits(reset=>1, height=>150), "set height limit 150");
+  ok($im->read(file=>$limit_file),
+     "should succeed - just inside height limit");
+  
+  # 150 x 150 x 3 channel image uses 67500 bytes
+  ok(Imager->set_file_limits(reset=>1, bytes=>67499),
+     "set bytes limit 67499");
+  ok(!$im->read(file=>$limit_file),
+     "should fail - too many bytes");
+  print "# ",$im->errstr,"\n";
+  like($im->errstr, qr/storage size/, "check error message");
+  ok(Imager->set_file_limits(reset=>1, bytes=>67500),
+     "set bytes limit 67500");
+  ok($im->read(file=>$limit_file),
+     "should succeed - just inside bytes limit");
+  Imager->set_file_limits(reset=>1);
 }
                               
 sub write_test {
-  my ($test_num, $im, $filename) = @_;
+  my ($im, $filename) = @_;
   local *FH;
 
   if (open FH, "> $filename") {
     binmode FH;
     my $IO = Imager::io_new_fd(fileno(FH));
-    if (Imager::i_writebmp_wiol($im, $IO)) {
-      print "ok $test_num\n";
-    }
-    else {
-      print "not ok $test_num # ",Imager->_error_as_msg(),"\n";
+    unless (ok(Imager::i_writebmp_wiol($im, $IO), $filename)) {
+      print "# ",Imager->_error_as_msg(),"\n";
     }
     undef $IO;
     close FH;
   }
   else {
-    print "not ok $test_num # $!\n";
+    fail("could not open $filename: $!");
   }
 }
 
 sub read_test {
-  my ($test_num, $filename, $im, %tags) = @_;
+  my ($filename, $im, %tags) = @_;
   local *FH;
   
   print "# read_test: $filename\n";
@@ -224,7 +251,7 @@ sub read_test {
     if ($im_read) {
       my $diff = i_img_diff($im, $im_read);
       if ($diff > $base_diff) {
-        print "not ok $test_num # image mismatch $diff\n";
+       fail("image mismatch reading $filename");
       }
       else {
         my $tags_ok = 1;
@@ -247,12 +274,7 @@ sub read_test {
             }
           }
         }
-        if ($tags_ok) {
-          print "ok $test_num\n";
-        }
-        else {
-          print "not ok $test_num # bad tag values\n";
-        }
+        ok($tags_ok, "reading $filename");
         #  for my $i (0 .. Imager::i_tags_count($im_read)-1) {
         #    my ($name, $value) = Imager::i_tags_get($im_read, $i);
         #    print "# tag '$name' => '$value'\n";
@@ -260,13 +282,13 @@ sub read_test {
       }
     }
     else {
-      print "not ok $test_num # ",Imager->_error_as_msg(),"\n";
+      fail("could not read $filename: ".Imager->_error_as_msg());
     }
     undef $IO;
     close FH;
   }
   else {
-    print "not ok $test_num # $!\n";
+    fail("could not open $filename: $!");
   }
 }
 
index 437f0f17a1c90d94ea6273e6fbfa66bccef6fc48..a19591f6ead99dd4ba39c96f16ede8c662fe1859 100644 (file)
@@ -1,7 +1,7 @@
 #!perl -w
-print "1..21\n";
 use Imager qw(:all);
 use strict;
+use Test::More tests=>36;
 BEGIN { require "t/testtools.pl"; }
 init_log("testout/t108tga.log",1);
 
@@ -9,19 +9,19 @@ init_log("testout/t108tga.log",1);
 my $img = create_test_image();
 my $base_diff = 0;
 
-write_test(1, $img, "testout/t108_24bit.tga", 0, 0, "");
-write_test(2, $img, "testout/t108_24bit_rle.tga", 0, 1, "");
-write_test(3, $img, "testout/t108_15bit.tga", 1, 1, "");
-write_test(4, $img, "testout/t108_15bit_rle.tga", 1, 1, "");
+write_test($img, "testout/t108_24bit.tga", 0, 0, "");
+write_test($img, "testout/t108_24bit_rle.tga", 0, 1, "");
+write_test($img, "testout/t108_15bit.tga", 1, 1, "");
+write_test($img, "testout/t108_15bit_rle.tga", 1, 1, "");
 
 # 'webmap' is noticably faster than the default
 my $im8 = Imager::i_img_to_pal($img, { make_colors=>'webmap',
                                       translate=>'errdiff'});
 
-write_test(5, $im8, "testout/t108_8bit.tga", 0, 0, "");
-write_test(6, $im8, "testout/t108_8bit_rle.tga", 0, 1, "");
-write_test(7, $im8, "testout/t108_8_15bit.tga", 1, 0, "");
-write_test(8, $im8, "testout/t108_8_15bit_rle.tga", 1, 1, "");
+write_test($im8, "testout/t108_8bit.tga", 0, 0, "");
+write_test($im8, "testout/t108_8bit_rle.tga", 0, 1, "");
+write_test($im8, "testout/t108_8_15bit.tga", 1, 0, "");
+write_test($im8, "testout/t108_8_15bit_rle.tga", 1, 1, "");
 
 
 # use a fixed palette so we get reproducible results for the compressed
@@ -40,13 +40,13 @@ my $im1 = Imager::i_img_to_pal($img, { colors=>\@bit1,
                                       make_colors=>'none',
                                       translate=>'errdiff' });
 
-write_test(9, $im4, "testout/t108_4bit.tga", 0, 1, "");
-write_test(10, $im1, "testout/t108_1bit.tga", 0, 1, "This is a comment!");
+write_test($im4, "testout/t108_4bit.tga", 0, 1, "");
+write_test($im1, "testout/t108_1bit.tga", 0, 1, "This is a comment!");
 
-read_test(11, "testout/t108_24bit.tga", $img);
-read_test(12, "testout/t108_8bit.tga",  $im8);
-read_test(13, "testout/t108_4bit.tga",  $im4);
-read_test(14, "testout/t108_1bit.tga",  $im1);
+read_test("testout/t108_24bit.tga", $img);
+read_test("testout/t108_8bit.tga",  $im8);
+read_test("testout/t108_4bit.tga",  $im4);
+read_test("testout/t108_1bit.tga",  $im1);
 
 # the following might have slight differences
 
@@ -55,55 +55,85 @@ $base_diff = i_img_diff($img, $im8) * 2;
 print "# base difference $base_diff\n";
 
 my $imoo = Imager->new;
-if ($imoo->read(file=>'testout/t108_24bit.tga')) {
-  print "ok 15\n";
-} else {
-  print "not ok 15 # ",$imoo->errstr,"\n";
-}
+ok($imoo->read(file=>'testout/t108_24bit.tga'),
+   "OO read image")
+  or print "# ",$imoo->errstr,"\n";
 
-if ($imoo->write(file=>'testout/t108_oo.tga')) {
-  print "ok 16\n";
-} else {
-  print "not ok 16 # ",$imoo->errstr,"\n";
-}
+ok($imoo->write(file=>'testout/t108_oo.tga'),
+   "OO write image")
+  or print "# ",$imoo->errstr,"\n";
 
 my ($type) = $imoo->tags(name=>'i_format');
-isn(17, $type, 'tga', "check i_format tag");
+is($type, 'tga', "check i_format tag");
 
 # in 0.44 and earlier, reading an image with an idstring of 128 or more
 # bytes would result in an allocation error, if the platform char type
 # was signed
 $imoo = Imager->new;
-okn(18, $imoo->read(file=>'testimg/longid.tga'), "read long id image");
+ok($imoo->read(file=>'testimg/longid.tga'), "read long id image");
 my ($id) = $imoo->tags(name=>'tga_idstring');
-isn(19, $id, "X" x 128, "check tga_idstring tag");
+is($id, "X" x 128, "check tga_idstring tag");
 my ($bitspp) = $imoo->tags(name=>'tga_bitspp');
-isn(20, $bitspp, 24, "check tga_bitspp tag");
+is($bitspp, 24, "check tga_bitspp tag");
 my ($compressed) = $imoo->tags(name=>'compressed');
-isn(21, $compressed, 1, "check compressed tag");
+is($compressed, 1, "check compressed tag");
+
+{ # check file limits are checked
+  my $limit_file = "testout/t108_24bit.tga";
+  ok(Imager->set_file_limits(reset=>1, width=>149), "set width limit 149");
+  my $im = Imager->new;
+  ok(!$im->read(file=>$limit_file),
+     "should fail read due to size limits");
+  print "# ",$im->errstr,"\n";
+  like($im->errstr, qr/image width/, "check message");
+  
+  ok(Imager->set_file_limits(reset=>1, height=>149), "set height limit 149");
+  ok(!$im->read(file=>$limit_file),
+     "should fail read due to size limits");
+  print "# ",$im->errstr,"\n";
+  like($im->errstr, qr/image height/, "check message");
+  
+  ok(Imager->set_file_limits(reset=>1, width=>150), "set width limit 150");
+  ok($im->read(file=>$limit_file),
+     "should succeed - just inside width limit");
+  ok(Imager->set_file_limits(reset=>1, height=>150), "set height limit 150");
+  ok($im->read(file=>$limit_file),
+     "should succeed - just inside height limit");
+  
+  # 150 x 150 x 3 channel image uses 67500 bytes
+  ok(Imager->set_file_limits(reset=>1, bytes=>67499),
+     "set bytes limit 67499");
+  ok(!$im->read(file=>$limit_file),
+     "should fail - too many bytes");
+  print "# ",$im->errstr,"\n";
+  like($im->errstr, qr/storage size/, "check error message");
+  ok(Imager->set_file_limits(reset=>1, bytes=>67500),
+     "set bytes limit 67500");
+  ok($im->read(file=>$limit_file),
+     "should succeed - just inside bytes limit");
+  Imager->set_file_limits(reset=>1);
+}
 
 sub write_test {
-  my ($test_num, $im, $filename, $wierdpack, $compress, $idstring) = @_;
+  my ($im, $filename, $wierdpack, $compress, $idstring) = @_;
   local *FH;
 
   if (open FH, "> $filename") {
     binmode FH;
     my $IO = Imager::io_new_fd(fileno(FH));
-    if (Imager::i_writetga_wiol($im, $IO, $wierdpack, $compress, $idstring)) {
-      print "ok $test_num\n";
-    } else {
-      print "not ok $test_num # ",Imager->_error_as_msg(),"\n";
-    }
+    ok(Imager::i_writetga_wiol($im, $IO, $wierdpack, $compress, $idstring),
+       "write $filename")
+      or print "# ",Imager->_error_as_msg(),"\n";
     undef $IO;
     close FH;
   } else {
-    print "not ok $test_num # $!\n";
+    fail("write $filename: open failed: $!");
   }
 }
 
 
 sub read_test {
-  my ($test_num, $filename, $im, %tags) = @_;
+  my ($filename, $im, %tags) = @_;
   local *FH;
 
   if (open FH, "< $filename") {
@@ -112,17 +142,15 @@ sub read_test {
     my $im_read = Imager::i_readtga_wiol($IO,-1);
     if ($im_read) {
       my $diff = i_img_diff($im, $im_read);
-      if ($diff > $base_diff) {
-        print "not ok $test_num # image mismatch $diff\n";
-      }
-      print "ok $test_num\n";
+      cmp_ok($diff, '<=', $base_diff,
+            "check read image vs original");
     } else {
-      print "not ok $test_num # ",Imager->_error_as_msg(),"\n";
+      fail("read $filename ".Imager->_error_as_msg());
     }
     undef $IO;
     close FH;
   } else {
-    print "not ok $test_num # $!\n";
+    fail("read $filename, open failure: $!");
   }
 }
 
diff --git a/tga.c b/tga.c
index 13758117f0576e4108b63b949410a9cc2cb9ddda..2e373534c02698e723e78250ba6ea965cbabf602 100644 (file)
--- a/tga.c
+++ b/tga.c
@@ -1,4 +1,4 @@
-#include "image.h"
+#include "imagei.h"
 #include "log.h"
 #include "iolayer.h"
 
@@ -645,6 +645,7 @@ i_readtga_wiol(io_glue *ig, int length) {
 
   width = header.width;
   height = header.height;
+
   
   /* Set tags here */
   
@@ -713,6 +714,12 @@ i_readtga_wiol(io_glue *ig, int length) {
     channels = 1;
     break;
   }
+
+  if (!i_int_check_image_file_limits(width, height, channels, 
+                                    sizeof(i_sample_t))) {
+    mm_log((1, "i_readtga_wiol: image size exceeds limits\n"));
+    return NULL;
+  }
   
   img = mapped ? 
     i_img_pal_new(width, height, channels, 256) :