]> git.imager.perl.org - imager.git/commitdiff
WIP commit
authorTony Cook <tony@develop-help.com>
Mon, 12 Sep 2011 12:37:42 +0000 (22:37 +1000)
committerTony Cook <tony@develop-help.com>
Mon, 12 Sep 2011 12:38:25 +0000 (22:38 +1000)
20 files changed:
Changes
GIF/imgif.c
GIF/t/t10gif.t
ICO/t/t10icon.t
Imager.pm
JPEG/imjpeg.c
JPEG/t/t10jpeg.t
PNG/impng.c
PNG/t/10png.t
SGI/t/20write.t
TIFF/imtiff.c
TIFF/t/t10tiff.t
bmp.c
iolayer.c
raw.c
t/t103raw.t
t/t104ppm.t
t/t107bmp.t
t/t108tga.t
tga.c

diff --git a/Changes b/Changes
index 19d5dd71153b0bcef6f63b98859599bbc442361f..21dcd188f0f0c2b3312dbaeab2c3d56df1709c9f 100644 (file)
--- a/Changes
+++ b/Changes
@@ -18,7 +18,9 @@ Imager release history.  Older releases can be found in Changes.old
    - the callback IO object did its own buffering, controlled by the
      maxbuffer parameter supplied to the read() and write() methods.
      This buffering has been removed, to avoid redundancy with the
-     common io_glue buffering.
+     common io_glue buffering.  This also avoids a bug in that code
+     which could rarely pass a zero length to the read callback and
+     then panic about the result.
 
    - the callback IO object new tests the result of calling the close
      callback, which should return true for success.
@@ -30,6 +32,8 @@ To do:
 
  - make sure i_io_close() is called and the result is checked
 
+ - remove the other cast functions from imtiff.c
+
  - remove other buffering
 
  - allow _get_writer() to produce unbuffered writers
index e6524a5fcf020b57e178e391a2e302c780a07f8a..a9875c2adc79a70ab646d36d52c32acfce98aac5 100644 (file)
@@ -1800,7 +1800,8 @@ i_writegif_wiol(io_glue *ig, i_quantize *quant, i_img **imgs,
   
   result = i_writegif_low(quant, GifFile, imgs, count);
   
-  i_io_close(ig);
+  if (i_io_close(ig))
+    return 0;
   
   return result;
 }
index 40a8860fcc2222bde5f7bc5ae313b3a97e6197cb..c926b0c6bcfe787f21b7a10e36dc6ba0d23b7642 100644 (file)
@@ -14,7 +14,7 @@ use strict;
 $|=1;
 use Test::More;
 use Imager qw(:all);
-use Imager::Test qw(is_color3 test_image test_image_raw);
+use Imager::Test qw(is_color3 test_image test_image_raw test_image_mono);
 use Imager::File::GIF;
 
 use Carp 'confess';
@@ -24,7 +24,7 @@ $SIG{__DIE__} = sub { confess @_ };
 
 init_log("testout/t105gif.log",1);
 
-plan tests => 144;
+plan tests => 146;
 
 my $green=i_color_new(0,255,0,255);
 my $blue=i_color_new(0,0,255,255);
@@ -738,6 +738,21 @@ SKIP:
   ok($im, "read image with zero-length extension");
 }
 
+
+{ # check close failures are handled correctly
+  my $im = test_image_mono();
+  my $fail_close = sub {
+    Imager::i_push_error(0, "synthetic close failure");
+    return 0;
+  };
+  ok(!$im->write(type => "gif", callback => sub { 1 },
+                closecb => $fail_close),
+     "check failing close fails");
+    like($im->errstr, qr/synthetic close failure/,
+        "check error message");
+}
+
+
 sub test_readgif_cb {
   my ($size) = @_;
 
index 707bc4b8c99d04e13d029818b936fb65502f0c9b..25b19177b874f26eae2fce04ff584a6221df1236 100644 (file)
@@ -1,7 +1,7 @@
 #!perl -w
 use strict;
-use Test::More tests => 100;
-use Imager::Test qw(is_image);
+use Test::More tests => 102;
+use Imager::Test qw(is_image test_image);
 
 BEGIN { use_ok('Imager::File::ICO'); }
 
@@ -371,3 +371,17 @@ EOS
   $vs->box(filled => 1, color => '#333366');
   is_image($im, $vs, "check we got the right colors");
 }
+
+
+{ # check close failures are handled correctly
+  my $im = test_image();
+  my $fail_close = sub {
+    Imager::i_push_error(0, "synthetic close failure");
+    return 0;
+  };
+  ok(!$im->write(type => "ico", callback => sub { 1 },
+                closecb => $fail_close),
+     "check failing close fails");
+    like($im->errstr, qr/synthetic close failure/,
+        "check error message");
+}
index aecf0c4c7b5e336790bc0269dfd922290025b3f7..53b41dd07e1a3baa7019a70127b5ecb3d4cafc2f 100644 (file)
--- a/Imager.pm
+++ b/Imager.pm
@@ -1338,11 +1338,15 @@ sub _get_reader_io {
 sub _get_writer_io {
   my ($self, $input) = @_;
 
+  my $buffered = exists $input->{buffered} ? $input->{buffered} : 1;
+
+  my $io;
+  my @extras;
   if ($input->{io}) {
     return $input->{io};
   }
   elsif ($input->{fd}) {
-    return io_new_fd($input->{fd});
+    $io = io_new_fd($input->{fd});
   }
   elsif ($input->{fh}) {
     my $fd = fileno($input->{fh});
@@ -1355,7 +1359,7 @@ sub _get_writer_io {
     # flush anything that's buffered, and make sure anything else is flushed
     $| = 1;
     select($oldfh);
-    return io_new_fd($fd);
+    $io = io_new_fd($fd);
   }
   elsif ($input->{file}) {
     my $fh = new IO::File($input->{file},"w+");
@@ -1364,28 +1368,30 @@ sub _get_writer_io {
       return;
     }
     binmode($fh) or die;
-    return (io_new_fd(fileno($fh)), $fh);
+    $io = io_new_fd(fileno($fh));
+    push @extras, $fh;
   }
   elsif ($input->{data}) {
-    return io_new_bufchain();
+    $io = io_new_bufchain();
   }
   elsif ($input->{callback} || $input->{writecb}) {
-    if ($input->{maxbuffer}) {
-      return io_new_cb($input->{callback} || $input->{writecb},
-                       $input->{readcb},
-                       $input->{seekcb}, $input->{closecb},
-                       $input->{maxbuffer});
-    }
-    else {
-      return io_new_cb($input->{callback} || $input->{writecb},
-                       $input->{readcb},
-                       $input->{seekcb}, $input->{closecb});
+    if ($input->{maxbuffer} && $input->{maxbuffer} == 1) {
+      $buffered = 0;
     }
+    $io = io_new_cb($input->{callback} || $input->{writecb},
+                   $input->{readcb},
+                   $input->{seekcb}, $input->{closecb});
   }
   else {
     $self->_set_error("file/fd/fh/data/callback parameter missing");
     return;
   }
+
+  unless ($buffered) {
+    $io->set_buffered(0);
+  }
+
+  return ($io, @extras);
 }
 
 # Read an image from file
index eea59c2810218cf1b826589df13c99f028a44369..d4341b40bd28784d32de32277a8a5152371a0ca4 100644 (file)
@@ -721,7 +721,8 @@ i_writejpeg_wiol(i_img *im, io_glue *ig, int qfactor) {
 
   jpeg_destroy_compress(&cinfo);
 
-  i_io_close(ig);
+  if (i_io_close(ig))
+    return 0;
 
   return(1);
 }
index 8c8cd7ef7255f9729efea225f079bf2df263f7e6..a88554d78c756ed256b78573dda6379486024518 100644 (file)
@@ -11,7 +11,7 @@ init_log("testout/t101jpeg.log",1);
 $Imager::formats{"jpeg"}
   or plan skip_all => "no jpeg support";
 
-plan tests => 101;
+plan tests => 103;
 
 my $green=i_color_new(0,255,0,255);
 my $blue=i_color_new(0,0,255,255);
@@ -435,3 +435,16 @@ SKIP:
 
   is_image($rdprog, $norm, "prog vs norm should be the same image");
 }
+
+{ # check close failures are handled correctly
+  my $im = test_image();
+  my $fail_close = sub {
+    Imager::i_push_error(0, "synthetic close failure");
+    return 0;
+  };
+  ok(!$im->write(type => "jpeg", callback => sub { 1 },
+                closecb => $fail_close),
+     "check failing close fails");
+    like($im->errstr, qr/synthetic close failure/,
+        "check error message");
+}
index 1fd9ba18ef6f16a24d39dc1977915b2335ce9d84..5fd41512616014621b2cdec4a1cfc46346254ec2 100644 (file)
@@ -177,7 +177,8 @@ i_writepng_wiol(i_img *im, io_glue *ig) {
 
   png_destroy_write_struct(&png_ptr, &info_ptr);
 
-  i_io_close(ig);
+  if (i_io_close(ig))
+    return 0;
 
   return(1);
 }
index 9dbc399b7410a3656f4079758945d07bb24af796..4077a99e68a487315694ef8725ef239af5f8e486 100644 (file)
@@ -2,7 +2,7 @@
 use strict;
 use Imager qw(:all);
 use Test::More;
-use Imager::Test qw(test_image_raw);
+use Imager::Test qw(test_image_raw test_image);
 
 -d "testout" or mkdir "testout";
 
@@ -11,7 +11,7 @@ init_log("testout/t102png.log",1);
 $Imager::formats{"png"}
   or plan skip_all => "No png support";
 
-plan tests => 33;
+plan tests => 35;
 
 my $green  = i_color_new(0,   255, 0,   255);
 my $blue   = i_color_new(0,   0,   255, 255);
@@ -147,6 +147,19 @@ EOS
      'test write_multi() callback failure');
 }
 
+{ # check close failures are handled correctly
+  my $im = test_image();
+  my $fail_close = sub {
+    Imager::i_push_error(0, "synthetic close failure");
+    return 0;
+  };
+  ok(!$im->write(type => "png", callback => sub { 1 },
+                closecb => $fail_close),
+     "check failing close fails");
+    like($im->errstr, qr/synthetic close failure/,
+        "check error message");
+}
+
 {
   ok(grep($_ eq 'png', Imager->read_types), "check png in read types");
   ok(grep($_ eq 'png', Imager->write_types), "check png in write types");
index 335a8c585cdafe0643c793f01b5b6dc6aae7587f..bcbf4e53dc58e1933d706fa55b2d3897ad23abfb 100644 (file)
@@ -1,7 +1,7 @@
 #!perl -w
 use strict;
 use Imager;
-use Test::More tests => 55;
+use Test::More tests => 57;
 use Imager::Test qw(test_image test_image_16 is_image);
 use IO::Seekable;
 
@@ -168,6 +168,20 @@ Imager::init_log('testout/20write.log', 2);
   }
 }
 
+
+{ # check close failures are handled correctly
+  my $im = test_image();
+  my $fail_close = sub {
+    Imager::i_push_error(0, "synthetic close failure");
+    return 0;
+  };
+  ok(!$im->write(type => "sgi", callback => sub { 1 },
+                closecb => $fail_close),
+     "check failing close fails");
+    like($im->errstr, qr/synthetic close failure/,
+        "check error message");
+}
+
 sub limited_write_io {
   my ($limit) = @_;
 
index 05af63792ac78fede80114769d80cee2a2b83631..0a38f506cd991118fc8357aad69b059e1ad37865 100644 (file)
@@ -1345,13 +1345,13 @@ i_writetiff_multi_wiol(io_glue *ig, i_img **imgs, int count) {
   tif = TIFFClientOpen("No name", 
                       "wm",
                       (thandle_t) ig, 
-                      (TIFFReadWriteProc) ig->readcb,
-                      (TIFFReadWriteProc) ig->writecb,
-                      (TIFFSeekProc)      comp_seek,
-                      (TIFFCloseProc)     ig->closecb
-                      ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
-                      (TIFFMapFileProc)   comp_mmap,
-                      (TIFFUnmapFileProc) comp_munmap);
+                      comp_read,
+                      comp_write,
+                      comp_seek,
+                      comp_close
+                      sizeproc,
+                      comp_mmap,
+                      comp_munmap);
   
 
 
@@ -1380,6 +1380,9 @@ i_writetiff_multi_wiol(io_glue *ig, i_img **imgs, int count) {
   TIFFSetErrorHandler(old_handler);
   (void) TIFFClose(tif);
 
+  if (i_io_close(ig))
+    return 0;
+
   return 1;
 }
 
@@ -1413,13 +1416,13 @@ i_writetiff_multi_wiol_faxable(io_glue *ig, i_img **imgs, int count, int fine) {
   tif = TIFFClientOpen("No name", 
                       "wm",
                       (thandle_t) ig, 
-                      (TIFFReadWriteProc) ig->readcb,
-                      (TIFFReadWriteProc) ig->writecb,
-                      (TIFFSeekProc)      comp_seek,
-                      (TIFFCloseProc)     ig->closecb
-                      ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
-                      (TIFFMapFileProc)   comp_mmap,
-                      (TIFFUnmapFileProc) comp_munmap);
+                      comp_read,
+                      comp_write,
+                      comp_seek,
+                      comp_close
+                      sizeproc,
+                      comp_mmap,
+                      comp_munmap);
   
 
 
@@ -1448,6 +1451,9 @@ i_writetiff_multi_wiol_faxable(io_glue *ig, i_img **imgs, int count, int fine) {
   (void) TIFFClose(tif);
   TIFFSetErrorHandler(old_handler);
 
+  if (i_io_close(ig))
+    return 0;
+
   return 1;
 }
 
@@ -1476,13 +1482,13 @@ i_writetiff_wiol(i_img *img, io_glue *ig) {
   tif = TIFFClientOpen("No name", 
                       "wm",
                       (thandle_t) ig, 
-                      (TIFFReadWriteProc) ig->readcb,
-                      (TIFFReadWriteProc) ig->writecb,
-                      (TIFFSeekProc)      comp_seek,
-                      (TIFFCloseProc)     ig->closecb
-                      ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
-                      (TIFFMapFileProc)   comp_mmap,
-                      (TIFFUnmapFileProc) comp_munmap);
+                      comp_read,
+                      comp_write,
+                      comp_seek,
+                      comp_close
+                      sizeproc,
+                      comp_mmap,
+                      comp_munmap);
   
 
 
@@ -1502,6 +1508,9 @@ i_writetiff_wiol(i_img *img, io_glue *ig) {
   (void) TIFFClose(tif);
   TIFFSetErrorHandler(old_handler);
 
+  if (i_io_close(ig))
+    return 0;
+
   return 1;
 }
 
@@ -1537,13 +1546,13 @@ i_writetiff_wiol_faxable(i_img *im, io_glue *ig, int fine) {
   tif = TIFFClientOpen("No name", 
                       "wm",
                       (thandle_t) ig, 
-                      (TIFFReadWriteProc) ig->readcb,
-                      (TIFFReadWriteProc) ig->writecb,
-                      (TIFFSeekProc)      comp_seek,
-                      (TIFFCloseProc)     ig->closecb
-                      ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
-                      (TIFFMapFileProc)   comp_mmap,
-                      (TIFFUnmapFileProc) comp_munmap);
+                      comp_read,
+                      comp_write,
+                      comp_seek,
+                      comp_close
+                      sizeproc,
+                      comp_mmap,
+                      comp_munmap);
   
 
 
@@ -1563,6 +1572,9 @@ i_writetiff_wiol_faxable(i_img *im, io_glue *ig, int fine) {
   (void) TIFFClose(tif);
   TIFFSetErrorHandler(old_handler);
 
+  if (i_io_close(ig))
+    return 0;
+
   return 1;
 }
 
index c93cfc0ec5ba3de2863e27d8bddd8910e9588a74..00e7f334cff548176f748fe23736e60a8a9f0d6d 100644 (file)
@@ -1,6 +1,6 @@
 #!perl -w
 use strict;
-use Test::More tests => 235;
+use Test::More tests => 239;
 use Imager qw(:all);
 use Imager::Test qw(is_image is_image_similar test_image test_image_16 test_image_double test_image_raw);
 
@@ -204,14 +204,17 @@ sub io_writer {
 }
 sub io_reader {
   my ($size, $maxread) = @_;
-  #print "io_reader($size, $maxread) pos $seekpos\n";
+  print "# io_reader($size, $maxread) pos $seekpos\n";
+  if ($seekpos + $maxread > length $work) {
+    $maxread = length($work) - $seekpos;
+  }
   my $out = substr($work, $seekpos, $maxread);
   $seekpos += length $out;
   $out;
 }
 sub io_reader2 {
   my ($size, $maxread) = @_;
-  #print "io_reader2($size, $maxread) pos $seekpos\n";
+  print "# io_reader2($size, $maxread) pos $seekpos\n";
   my $out = substr($work, $seekpos, $size);
   $seekpos += length $out;
   $out;
@@ -219,7 +222,7 @@ sub io_reader2 {
 use IO::Seekable;
 sub io_seeker {
   my ($offset, $whence) = @_;
-  #print "io_seeker($offset, $whence)\n";
+  print "# io_seeker($offset, $whence)\n";
   if ($whence == SEEK_SET) {
     $seekpos = $offset;
   }
@@ -286,6 +289,44 @@ open D3, ">testout/d3.tiff" or die;
 print D3 $work;
 close D3;
 
+
+{ # check close failures are handled correctly
+  { # single image
+    my $im = test_image();
+    my $fail_close = sub {
+      Imager::i_push_error(0, "synthetic close failure");
+      return 0;
+    };
+    $work = '';
+    $seekpos = 0;
+    ok(!$im->write(type => "tiff",
+                  readcb => \&io_reader,
+                  writecb => \&io_writer,
+                  seekcb => \&io_seeker,
+                  closecb => $fail_close),
+       "check failing close fails");
+    like($im->errstr, qr/synthetic close failure/,
+        "check error message");
+  }
+  { # multiple images
+    my $im = test_image();
+    my $fail_close = sub {
+      Imager::i_push_error(0, "synthetic close failure");
+      return 0;
+    };
+    $work = '';
+    $seekpos = 0;
+    ok(!Imager->write_multi({type => "tiff",
+                            readcb => \&io_reader,
+                            writecb => \&io_writer,
+                            seekcb => \&io_seeker,
+                            closecb => $fail_close}, $im, $im),
+       "check failing close fails");
+    like(Imager->errstr, qr/synthetic close failure/,
+        "check error message");
+  }
+}
+
 # multi-image write/read
 my @imgs;
 push(@imgs, map $ooim->copy(), 1..3);
diff --git a/bmp.c b/bmp.c
index 80c54d88c5520dcc92e864b6b5489629828e6887..ed134b2eac904a07c23632714871be7e04b2f2ca 100644 (file)
--- a/bmp.c
+++ b/bmp.c
@@ -499,7 +499,8 @@ write_1bit_data(io_glue *ig, i_img *im) {
   myfree(packed);
   myfree(line);
 
-  i_io_close(ig);
+  if (i_io_close(ig))
+    return 0;
 
   return 1;
 }
@@ -558,7 +559,8 @@ write_4bit_data(io_glue *ig, i_img *im) {
   myfree(packed);
   myfree(line);
 
-  i_io_close(ig);
+  if (i_io_close(ig))
+    return 0;
 
   return 1;
 }
@@ -604,7 +606,8 @@ write_8bit_data(io_glue *ig, i_img *im) {
   }
   myfree(line);
 
-  i_io_close(ig);
+  if (i_io_close(ig))
+    return 0;
 
   return 1;
 }
@@ -658,7 +661,8 @@ write_24bit_data(io_glue *ig, i_img *im) {
   }
   myfree(samples);
 
-  i_io_close(ig);
+  if (i_io_close(ig))
+    return 0;
 
   return 1;
 }
index 12c4419f7ffe7f74109b68b7061eb74b24620ef3..070dc506155d108350728700819732af6203fc65 100644 (file)
--- a/iolayer.c
+++ b/iolayer.c
@@ -1050,6 +1050,9 @@ static ssize_t fd_read(io_glue *igo, void *buf, size_t count) {
   result = read(ig->fd, buf, count);
 #endif
 
+  IOL_DEB(fprintf(IOL_DEBs, "fd_read(%p, %p, %u) => %d\n", ig, buf,
+                 (unsigned)count, (int)result));
+
   /* 0 is valid - means EOF */
   if (result < 0) {
     i_push_errorf(0, "read() failure: %s (%d)", my_strerror(errno), errno);
@@ -1179,6 +1182,9 @@ i_io_read_fill(io_glue *ig) {
     good = 1;
   }
 
+  if (rc < 0 && !ig->err_code)
+    ig->err_code = 1;
+
   if (good) {
     ig->read_ptr = buf_start;
     ig->read_end = work;
@@ -1458,6 +1464,9 @@ i_io_seek(io_glue *ig, off_t offset, int whence) {
   if (ig->write_ptr && ig->write_ptr != ig->write_end)
     i_io_flush(ig);
 
+  if (whence == SEEK_CUR && ig->read_ptr && ig->read_ptr != ig->read_end)
+    offset -= ig->read_end - ig->read_ptr;
+
   ig->read_ptr = ig->read_end = NULL;
   ig->write_ptr = ig->write_end = NULL;
   ig->err_code = 0;
diff --git a/raw.c b/raw.c
index f56a29b009f8e29d4b390b94bb720b70ecf268b7..bae403d07cea46b59da4b8fdf43146d083756477 100644 (file)
--- a/raw.c
+++ b/raw.c
@@ -101,7 +101,7 @@ i_readraw_wiol(io_glue *ig, i_img_dim x, i_img_dim y, int datachannels, int stor
   
   k=0;
   while( k<im->ysize ) {
-    rc = ig->readcb(ig, inbuffer, inbuflen);
+    rc = i_io_read(ig, inbuffer, inbuflen);
     if (rc != inbuflen) { 
       if (rc < 0)
        i_push_error(0, "error reading file");
@@ -140,7 +140,7 @@ i_writeraw_wiol(i_img* im, io_glue *ig) {
   
   if (im == NULL) { mm_log((1,"Image is empty\n")); return(0); }
   if (!im->virtual) {
-    rc = ig->writecb(ig,im->idata,im->bytes);
+    rc = i_io_write(ig,im->idata,im->bytes);
     if (rc != im->bytes) { 
       i_push_error(errno, "Could not write to file");
       mm_log((1,"i_writeraw: Couldn't write to file\n")); 
@@ -157,7 +157,7 @@ i_writeraw_wiol(i_img* im, io_glue *ig) {
       rc = line_size;
       while (rc == line_size && y < im->ysize) {
        i_gsamp(im, 0, im->xsize, y, data, NULL, im->channels);
-       rc = ig->writecb(ig, data, line_size);
+       rc = i_io_write(ig, data, line_size);
        ++y;
       }
       if (rc != line_size) {
@@ -176,7 +176,7 @@ i_writeraw_wiol(i_img* im, io_glue *ig) {
       rc = line_size;
       while (rc == line_size && y < im->ysize) {
        i_gpal(im, 0, im->xsize, y, data);
-       rc = ig->writecb(ig, data, line_size);
+       rc = i_io_write(ig, data, line_size);
        ++y;
       }
       myfree(data);
@@ -187,7 +187,8 @@ i_writeraw_wiol(i_img* im, io_glue *ig) {
     }
   }
 
-  ig->closecb(ig);
+  if (i_io_close(ig))
+    return 0;
 
   return(1);
 }
index 316ce271f89d1e6ffad625a8d8776f55ce4e255c..01f527295d2502582866cabd0a02e20b80d56dfb 100644 (file)
@@ -1,8 +1,8 @@
 #!perl -w
 use strict;
-use Test::More tests => 47;
+use Test::More tests => 53;
 use Imager qw(:all);
-use Imager::Test qw/is_color3 is_color4/;
+use Imager::Test qw/is_color3 is_color4 test_image test_image_mono/;
 
 -d "testout" or mkdir "testout";
 
@@ -166,7 +166,7 @@ SKIP:
   open RAW, "< testout/t103_empty.raw"
     or die "Cannot open testout/t103_empty.raw: $!";
   my $im = Imager->new(xsize => 50, ysize=>50);
-  ok(!$im->write(fh => \*RAW, type => 'raw'),
+  ok(!$im->write(fh => \*RAW, type => 'raw', buffered => 0),
      "write to open for read handle");
   cmp_ok($im->errstr, '=~', '^Could not write to file: write\(\) failure', 
         "check error message");
@@ -270,6 +270,24 @@ SKIP:
            "check last channel zeroed");
 }
 
+{
+  my @ims = ( basic => test_image(), mono => test_image_mono() );
+  push @ims, masked => test_image()->masked();
+
+  my $fail_close = sub {
+    Imager::i_push_error(0, "synthetic close failure");
+    return 0;
+  };
+
+  while (my ($type, $im) = splice(@ims, 0, 2)) {
+    my $io = Imager::io_new_cb(sub { 1 }, undef, undef, $fail_close);
+    ok(!$im->write(io => $io, type => "raw"),
+       "write $type image with a failing close handler");
+    like($im->errstr, qr/synthetic close failure/,
+        "check error message");
+  }
+}
+
 Imager->close_log;
 
 unless ($ENV{IMAGER_KEEP_FILES}) {
index 262589e509d580ebc649bab3fa053be36a2243cd..c85d7a9b87d3bec5643528fbbd0eeb651cb55349 100644 (file)
@@ -1,8 +1,8 @@
 #!perl -w
 use Imager ':all';
-use Test::More tests => 195;
+use Test::More tests => 205;
 use strict;
-use Imager::Test qw(test_image_raw test_image_16 is_color3 is_color1 is_image);
+use Imager::Test qw(test_image_raw test_image_16 is_color3 is_color1 is_image test_image_named);
 
 $| = 1;
 
@@ -598,8 +598,6 @@ print "# check error handling\n";
   }
 }
 
-Imager->close_log;
-
 { # image too large handling
   {
     ok(!Imager->new(file => "testimg/toowide.ppm", filetype => "pnm"),
@@ -615,6 +613,24 @@ Imager->close_log;
   }
 }
 
+{ # make sure close is checked for each image type
+  my $fail_close = sub {
+    Imager::i_push_error(0, "synthetic close failure");
+    return 0;
+  };
+
+  for my $type (qw(basic basic16 gray gray16 mono)) {
+    my $im = test_image_named($type);
+    my $io = Imager::io_new_cb(sub { 1 }, undef, undef, $fail_close);
+    ok(!$im->write(io => $io, type => "pnm"),
+       "write $type image with a failing close handler");
+    like($im->errstr, qr/synthetic close failure/,
+        "check error message");
+  }
+}
+
+Imager->close_log;
+
 unless ($ENV{IMAGER_KEEP_FILES}) {
   unlink "testout/t104ppm.log";
   unlink map "testout/$_", @files;
index ba516c80f18276b57e4e2bbc59bf427d7db4aee1..356d7767de55aab5b9103f932bc58f9242f5a912 100644 (file)
@@ -1,6 +1,6 @@
 #!perl -w
 use strict;
-use Test::More tests => 213;
+use Test::More tests => 215;
 use Imager qw(:all);
 use Imager::Test qw(test_image_raw is_image is_color3 test_image);
 
@@ -668,6 +668,19 @@ for my $comp (@comp) {
   is($size, 67800, "check data size");
 }
 
+{ # check close failures are handled correctly
+  my $im = test_image();
+  my $fail_close = sub {
+    Imager::i_push_error(0, "synthetic close failure");
+    return 0;
+  };
+  ok(!$im->write(type => "bmp", callback => sub { 1 },
+                closecb => $fail_close),
+     "check failing close fails");
+    like($im->errstr, qr/synthetic close failure/,
+        "check error message");
+}
+
 Imager->close_log;
 
 unless ($ENV{IMAGER_KEEP_FILES}) {
index 11be19ec6b0a9436832cf7ad1f1a72e195ce154d..cfdd66457014a6021d7b8424eb7172fa329efae6 100644 (file)
@@ -1,8 +1,8 @@
 #!perl -w
 use Imager qw(:all);
 use strict;
-use Test::More tests=>66;
-use Imager::Test qw(is_color4 is_image);
+use Test::More tests=>68;
+use Imager::Test qw(is_color4 is_image test_image);
 
 -d "testout" or mkdir "testout";
 
@@ -232,6 +232,19 @@ is($compressed, 1, "check compressed tag");
   }
 }
 
+{ # check close failures are handled correctly
+  my $im = test_image();
+  my $fail_close = sub {
+    Imager::i_push_error(0, "synthetic close failure");
+    return 0;
+  };
+  ok(!$im->write(type => "tga", callback => sub { 1 },
+                closecb => $fail_close),
+     "check failing close fails");
+    like($im->errstr, qr/synthetic close failure/,
+        "check error message");
+}
+
 sub write_test {
   my ($im, $filename, $wierdpack, $compress, $idstring) = @_;
   local *FH;
diff --git a/tga.c b/tga.c
index ece860d135db61ae1c29dc4315d027e012b7ef28..fcfdb8785347c37d29a981dde86eed74b95c2b57 100644 (file)
--- a/tga.c
+++ b/tga.c
@@ -949,7 +949,8 @@ i_writetga_wiol(i_img *img, io_glue *ig, int wierdpack, int compress, char *idst
     myfree(vals);
   }
 
-  i_io_close(ig);
+  if (i_io_close(ig))
+    return 0;
 
   return 1;
 }