- 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.
- 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
result = i_writegif_low(quant, GifFile, imgs, count);
- i_io_close(ig);
+ if (i_io_close(ig))
+ return 0;
return result;
}
$|=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';
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);
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) = @_;
#!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'); }
$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");
+}
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});
# 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+");
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
jpeg_destroy_compress(&cinfo);
- i_io_close(ig);
+ if (i_io_close(ig))
+ return 0;
return(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);
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");
+}
png_destroy_write_struct(&png_ptr, &info_ptr);
- i_io_close(ig);
+ if (i_io_close(ig))
+ return 0;
return(1);
}
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";
$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);
'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");
#!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;
}
}
+
+{ # 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) = @_;
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);
TIFFSetErrorHandler(old_handler);
(void) TIFFClose(tif);
+ if (i_io_close(ig))
+ return 0;
+
return 1;
}
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);
(void) TIFFClose(tif);
TIFFSetErrorHandler(old_handler);
+ if (i_io_close(ig))
+ return 0;
+
return 1;
}
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);
(void) TIFFClose(tif);
TIFFSetErrorHandler(old_handler);
+ if (i_io_close(ig))
+ return 0;
+
return 1;
}
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);
(void) TIFFClose(tif);
TIFFSetErrorHandler(old_handler);
+ if (i_io_close(ig))
+ return 0;
+
return 1;
}
#!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);
}
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;
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;
}
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);
myfree(packed);
myfree(line);
- i_io_close(ig);
+ if (i_io_close(ig))
+ return 0;
return 1;
}
myfree(packed);
myfree(line);
- i_io_close(ig);
+ if (i_io_close(ig))
+ return 0;
return 1;
}
}
myfree(line);
- i_io_close(ig);
+ if (i_io_close(ig))
+ return 0;
return 1;
}
}
myfree(samples);
- i_io_close(ig);
+ if (i_io_close(ig))
+ return 0;
return 1;
}
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);
good = 1;
}
+ if (rc < 0 && !ig->err_code)
+ ig->err_code = 1;
+
if (good) {
ig->read_ptr = buf_start;
ig->read_end = work;
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;
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");
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"));
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) {
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);
}
}
- ig->closecb(ig);
+ if (i_io_close(ig))
+ return 0;
return(1);
}
#!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";
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");
"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}) {
#!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;
}
}
-Imager->close_log;
-
{ # image too large handling
{
ok(!Imager->new(file => "testimg/toowide.ppm", filetype => "pnm"),
}
}
+{ # 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;
#!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);
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}) {
#!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";
}
}
+{ # 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;
myfree(vals);
}
- i_io_close(ig);
+ if (i_io_close(ig))
+ return 0;
return 1;
}