added the check_file_limits() method to Imager
authorTony Cook <tony@develop-help.com>
Mon, 4 Jun 2012 10:00:15 +0000 (20:00 +1000)
committerTony Cook <tony@develop-help.com>
Mon, 4 Jun 2012 10:00:15 +0000 (20:00 +1000)
This exposes the i_int_check_image_file_limits() API.

Since I'd expected people to be able to write file handlers in perl,
such authors need access to the file size limit checking mechanism.

Imager.pm
Imager.xs
lib/Imager/Files.pod
limits.c
t/t1000files.t

index 3fbfc7e..7650a46 100644 (file)
--- a/Imager.pm
+++ b/Imager.pm
@@ -3900,6 +3900,41 @@ sub get_file_limits {
   i_get_image_file_limits();
 }
 
+my @check_args = qw(width height channels sample_size);
+
+sub check_file_limits {
+  my $class = shift;
+
+  my %opts =
+    (
+     channels => 3,
+     sample_size => 1,
+     @_,
+    );
+
+  if ($opts{sample_size} && $opts{sample_size} eq 'float') {
+    $opts{sample_size} = length(pack("d", 0));
+  }
+
+  for my $name (@check_args) {
+    unless (defined $opts{$name}) {
+      $class->_set_error("check_file_limits: $name must be defined");
+      return;
+    }
+    unless ($opts{$name} == int($opts{$name})) {
+      $class->_set_error("check_file_limits: $name must be a positive integer");
+      return;
+    }
+  }
+
+  my $result = i_int_check_image_file_limits(@opts{@check_args});
+  unless ($result) {
+    $class->_set_error($class->_error_as_msg());
+  }
+
+  return $result;
+}
+
 # Shortcuts that can be exported
 
 sub newcolor { Imager::Color->new(@_); }
@@ -4398,6 +4433,8 @@ image
 
 box() - L<Imager::Draw/box()> - draw a filled or outline box.
 
+check_file_limits() - L<Imager::Files/check_file_limits()>
+
 circle() - L<Imager::Draw/circle()> - draw a filled circle
 
 close_log() - L<Imager::ImageTypes/close_log()> - close the Imager
index 95c6f8e..c499da3 100644 (file)
--- a/Imager.xs
+++ b/Imager.xs
@@ -1059,6 +1059,14 @@ i_get_image_file_limits()
           PUSHs(sv_2mortal(newSVuv(bytes)));
         }
 
+bool
+i_int_check_image_file_limits(width, height, channels, sample_size)
+       i_img_dim width
+       i_img_dim height
+       int channels
+       size_t sample_size
+  PROTOTYPE: DISABLE
+
 MODULE = Imager                PACKAGE = Imager::IO    PREFIX = io_
 
 Imager::IO
index 050b198..b8884c3 100644 (file)
@@ -488,6 +488,37 @@ You can get the current limits with the get_file_limits() method:
   my ($max_width, $max_height, $max_bytes) =
      Imager->get_file_limits();
 
+=item check_file_limits()
+X<class methods, check_file_limits()>X<check_file_limits()>
+
+Intended for use by file handlers to check that the size of a file is
+within the limits set by C<set_file_limits()>.
+
+Parameters:
+
+=over
+
+=item *
+
+C<width>, C<height> - the width and height of the image in pixels.
+Must be a positive integer. Required.
+
+=item *
+
+C<channels> - the number of channels in the image, including the alpha
+channel if any.  Must be a positive integer between 1 and 4
+inclusive.  Default: 3.
+
+=item *
+
+C<sample_size> - the number of bytes stored per sample.  Must be a
+positive integer or C<"float">.  Note that this should be the sample
+size of the Imager image you will be creating, not the sample size in
+the source, eg. if the source has 32-bit samples this should be
+C<"float"> since Imager doesn't have 32-bit/sample images.
+
+=back
+
 =back
 
 =head1 TYPE SPECIFIC INFORMATION
index f7a7484..c029254 100644 (file)
--- a/limits.c
+++ b/limits.c
@@ -157,7 +157,7 @@ i_int_check_image_file_limits(i_img_dim width, i_img_dim height, int channels, s
   }
 
   if (height <= 0) {
-    i_push_errorf(0, "file size limit - image height %" i_DF " is not positive",
+    i_push_errorf(0, "file size limit - image height of %" i_DF " is not positive",
                  i_DFc(height));
     return 0;
   }
index cfad2c8..22cbdf0 100644 (file)
@@ -4,7 +4,7 @@
 # the file format
 
 use strict;
-use Test::More tests => 67;
+use Test::More tests => 85;
 use Imager;
 
 -d "testout" or mkdir "testout";
@@ -60,6 +60,37 @@ 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->check_file_limits(width => 100, height => 30),
+   "check 100 x 30 (def channels, sample_size) ok")
+  or diag(Imager->errstr);
+ok(Imager->check_file_limits(width => 100, height => 100, channels => 1),
+   "check 100 x 100 x 1 (def sample_size) ok")
+  or diag(Imager->errstr);
+ok(Imager->check_file_limits(width => 100, height => 100, channels => 1),
+   "check 100 x 100 x 1 (def sample_size) ok")
+  or diag(Imager->errstr);
+ok(!Imager->check_file_limits(width => 100, height => 100, channels => 1, sample_size => "float"),
+   "check 100 x 100 x 1 x float should fail");
+ok(!Imager->check_file_limits(width => 100, height => 100, channels => 0),
+   "0 channels should fail");
+is(Imager->errstr, "file size limit - channels 0 out of range",
+   "check error message");
+ok(!Imager->check_file_limits(width => 0, height => 100),
+   "0 width should fail");
+is(Imager->errstr, "file size limit - image width of 0 is not positive",
+   "check error message");
+ok(!Imager->check_file_limits(width => 100, height => 0),
+   "0 height should fail");
+is(Imager->errstr, "file size limit - image height of 0 is not positive",
+   "check error message");
+ok(!Imager->check_file_limits(width => 10, height => 10, sample_size => 0),
+   "0 sample_size should fail");
+is(Imager->errstr, "file size limit - sample_size 0 out of range",
+   "check error message");
+ok(!Imager->check_file_limits(width => 10, height => 10, sample_size => 1000),
+   "1000 sample_size should fail");
+is(Imager->errstr, "file size limit - sample_size 1000 out of range",
+   "check error message");
 ok(Imager->set_file_limits(reset=>1, height => 99),
    "set height and reset");
 is_deeply([ Imager->get_file_limits() ], [ 0, 99, 0x40000000 ],
@@ -69,6 +100,16 @@ ok(Imager->set_file_limits(reset=>1),
 is_deeply([ Imager->get_file_limits() ], [ 0, 0, 0x40000000 ],
          "check all are reset");
 
+# bad parameters
+is_deeply([ Imager->check_file_limits() ], [],
+         "missing size paramaters");
+is(Imager->errstr, "check_file_limits: width must be defined",
+   "check message");
+is_deeply([ Imager->check_file_limits(width => 100.5) ], [],
+         "non-integer parameter");
+is(Imager->errstr, "check_file_limits: width must be a positive integer",
+   "check message");
+
 # test error handling for loading file handers
 {
   # first, no module at all