From: Tony Cook Date: Thu, 16 Mar 2006 05:41:10 +0000 (+0000) Subject: more iolayer goodness: X-Git-Tag: Imager-0.51_01~30 X-Git-Url: http://git.imager.perl.org/imager.git/commitdiff_plain/eda1622cd91bdc971fdbfa5b786c8cc7bde3d7b2 more iolayer goodness: - make write/read/seek/close on an IO object visible as methods from perl - allow SEEK_CUR on bufchains --- diff --git a/Imager.xs b/Imager.xs index c0c5e940..50fcc185 100644 --- a/Imager.xs +++ b/Imager.xs @@ -880,7 +880,7 @@ i_int_hlines_dump(i_int_hlines *hlines) { #endif /* trying to use more C style names, map them here */ -#define io_glue_DESTROY(ig) io_glue_destroy(ig) +#define i_io_DESTROY(ig) io_glue_destroy(ig) MODULE = Imager PACKAGE = Imager::Color PREFIX = ICL_ @@ -1104,10 +1104,74 @@ i_get_image_file_limits() PUSHs(sv_2mortal(newSViv(bytes))); } -MODULE = Imager PACKAGE = Imager::IO PREFIX = io_glue_ +MODULE = Imager PACKAGE = Imager::IO PREFIX = i_io_ + +int +i_io_write(ig, data_sv) + Imager::IO ig + SV *data_sv + PREINIT: + void *data; + STRLEN size; + CODE: +#ifdef SvUTF8 + if (SvUTF8(data_sv)) { + data_sv = sv_2mortal(newSVsv(data_sv)); + sv_utf8_downgrade(data_sv, FALSE); + } +#endif + data = SvPV(data_sv, size); + RETVAL = i_io_write(ig, data, size); + OUTPUT: + RETVAL + +SV * +i_io_read(ig, buffer_sv, size) + Imager::IO ig + SV *buffer_sv + int size + PREINIT: + void *buffer; + int result; + CODE: + if (size < 0) + croak("size negative in call to i_io_read()"); + /* prevent an undefined value warning if they supplied an + undef buffer. + Orginally conditional on !SvOK(), but this will prevent the + downgrade from croaking */ + sv_setpvn(buffer_sv, "", 0); +#ifdef SvUTF8 + if (SvUTF8(buffer_sv)) + sv_utf8_downgrade(buffer_sv, FALSE); +#endif + buffer = SvGROW(buffer_sv, size+1); + result = i_io_read(ig, buffer, size); + if (result < 0) { + RETVAL = &PL_sv_undef; + } + else { + SvCUR_set(buffer_sv, result); + *SvEND(buffer_sv) = '\0'; + SvPOK_only(buffer_sv); + RETVAL = newSViv(result); /* XS will mortal this */ + } + OUTPUT: + RETVAL + buffer_sv + +int +i_io_seek(ig, position, whence) + Imager::IO ig + long position + int whence void -io_glue_DESTROY(ig) +i_io_close(ig) + Imager::IO ig + +void +i_io_DESTROY(ig) Imager::IO ig @@ -1115,8 +1179,6 @@ MODULE = Imager PACKAGE = Imager PROTOTYPES: ENABLE - - void i_list_formats() PREINIT: diff --git a/iolayer.c b/iolayer.c index 9e0e06fd..9d1b1afb 100644 --- a/iolayer.c +++ b/iolayer.c @@ -60,6 +60,11 @@ typedef struct { static void io_obj_setp_buffer(io_obj *io, char *p, size_t len, closebufp closecb, void *closedata); static void io_obj_setp_cb2 (io_obj *io, void *p, readl readcb, writel writecb, seekl seekcb, closel closecb, destroyl destroycb); +/* turn current offset, file length, whence and offset into a new offset */ +#define calc_seek_offset(curr_off, length, offset, whence) \ + (((whence) == SEEK_SET) ? (offset) : \ + ((whence) == SEEK_CUR) ? (curr_off) + (offset) : \ + ((whence) == SEEK_END) ? (length) + (offset) : -1) /* =head1 NAME @@ -347,14 +352,17 @@ static off_t buffer_seek(io_glue *ig, off_t offset, int whence) { io_ex_buffer *ieb = ig->exdata; - off_t reqpos = offset - + (whence == SEEK_CUR)*ieb->cpos - + (whence == SEEK_END)*ig->source.buffer.len; + off_t reqpos = + calc_seek_offset(ieb->cpos, ig->source.buffer.len, offset, whence); if (reqpos > ig->source.buffer.len) { mm_log((1, "seeking out of readable range\n")); return (off_t)-1; } + if (reqpos < 0) { + i_push_error(0, "seek before beginning of file"); + return (off_t)-1; + } ieb->cpos = reqpos; IOL_DEB( printf("buffer_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) ); @@ -701,98 +709,58 @@ static off_t bufchain_seek(io_glue *ig, off_t offset, int whence) { io_ex_bchain *ieb = ig->exdata; - io_blink *ib = NULL; int wrlen; - off_t cof = 0; - off_t scount = offset; + off_t scount = calc_seek_offset(ieb->gpos, ieb->length, offset, whence); off_t sk; mm_log((1, "bufchain_seek(ig %p, offset %ld, whence %d)\n", ig, offset, whence)); - switch (whence) { - case SEEK_SET: /* SEEK_SET = 0, From the top */ - ieb->cp = ieb->head; - ieb->cpos = 0; - ieb->gpos = 0; - - while( scount ) { - int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len; - if (clen == ieb->cpos) { - if (ieb->cp == ieb->tail) break; /* EOF */ - ieb->cp = ieb->cp->next; - ieb->cpos = 0; - clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len; - } - - sk = clen - ieb->cpos; - sk = sk > scount ? scount : sk; - - scount -= sk; - ieb->cpos += sk; - ieb->gpos += sk; - } + if (scount < 0) { + i_push_error(0, "invalid whence supplied or seek before start of file"); + return (off_t)-1; + } - wrlen = scount; - - if (wrlen > 0) { - /* - * extending file - get ieb into consistent state and then - * call write which will get it to the correct position - */ - char TB[BBSIZ]; - memset(TB, 0, BBSIZ); - ieb->gpos = ieb->length; - ieb->cpos = ieb->tfill; - - while(wrlen > 0) { - ssize_t rc, wl = i_min(wrlen, BBSIZ); - mm_log((1, "bufchain_seek: wrlen = %d, wl = %d\n", wrlen, wl)); - rc = bufchain_write( ig, TB, wl ); - if (rc != wl) m_fatal(0, "bufchain_seek: Unable to extend file\n"); - wrlen -= rc; - } + ieb->cp = ieb->head; + ieb->cpos = 0; + ieb->gpos = 0; + + while( scount ) { + int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len; + if (clen == ieb->cpos) { + if (ieb->cp == ieb->tail) break; /* EOF */ + ieb->cp = ieb->cp->next; + ieb->cpos = 0; + clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len; } - break; - - case SEEK_CUR: - m_fatal(123, "SEEK_CUR IS NOT IMPLEMENTED\n"); - - /* - case SEEK_CUR: - ib = ieb->cp; - if (cof < 0) { - cof += ib->cpos; - cpos = 0; - while(cof < 0 && ib->prev) { - ib = ib->prev; - cof += ib->len; - } - */ + sk = clen - ieb->cpos; + sk = sk > scount ? scount : sk; - case SEEK_END: /* SEEK_END = 2 */ - if (cof>0) m_fatal(0, "bufchain_seek: SEEK_END + %d : Extending files via seek not supported!\n", cof); + scount -= sk; + ieb->cpos += sk; + ieb->gpos += sk; + } + + wrlen = scount; - ieb->cp = ieb->tail; + if (wrlen > 0) { + /* + * extending file - get ieb into consistent state and then + * call write which will get it to the correct position + */ + char TB[BBSIZ]; + memset(TB, 0, BBSIZ); + ieb->gpos = ieb->length; ieb->cpos = ieb->tfill; - if (cof<0) { - cof += ieb->cpos; - ieb->cpos = 0; - - while(cof<0 && ib->prev) { - ib = ib->prev; - cof += ib->len; - } - - if (cof<0) m_fatal(0, "bufchain_seek: Tried to seek before start of file\n"); - ieb->gpos = ieb->length+offset; - ieb->cpos = cof; + while(wrlen > 0) { + ssize_t rc, wl = i_min(wrlen, BBSIZ); + mm_log((1, "bufchain_seek: wrlen = %d, wl = %d\n", wrlen, wl)); + rc = bufchain_write( ig, TB, wl ); + if (rc != wl) m_fatal(0, "bufchain_seek: Unable to extend file\n"); + wrlen -= rc; } - break; - default: - m_fatal(0, "bufchain_seek: Unhandled seek request: whence = %d\n", whence ); } mm_log((2, "bufchain_seek: returning ieb->gpos = %d\n", ieb->gpos)); @@ -1169,7 +1137,6 @@ Might leave us with a dangling pointer issue on some buffers. void io_glue_destroy(io_glue *ig) { - io_type inn = ig->source.type; mm_log((1, "io_glue_DESTROY(ig %p)\n", ig)); if (ig->destroycb) diff --git a/iolayer.h b/iolayer.h index e69b24fe..a4ec4771 100644 --- a/iolayer.h +++ b/iolayer.h @@ -120,8 +120,8 @@ void io_glue_destroy(io_glue *ig); #define i_io_type(ig) ((ig)->source.ig_type) #define i_io_read(ig, buf, size) ((ig)->readcb((ig), (buf), (size))) -#define i_io_write(ig, data, size) ((ig)->writedb((ig), (data), (size))) -#define i_io_seek(ig, offset, whence) ((ig)->seekdb((ig), (offset), (size))) +#define i_io_write(ig, data, size) ((ig)->writecb((ig), (data), (size))) +#define i_io_seek(ig, offset, whence) ((ig)->seekcb((ig), (offset), (whence))) #define i_io_close(ig) ((ig)->closecb(ig)) #endif /* _IOLAYER_H_ */ diff --git a/t/t07iolayer.t b/t/t07iolayer.t index ca9609e6..654c6e69 100644 --- a/t/t07iolayer.t +++ b/t/t07iolayer.t @@ -1,6 +1,7 @@ #!perl -w use strict; -use Test::More tests => 20; +use Test::More tests => 43; +use Fcntl ':seek'; BEGIN { use_ok(Imager => ':all') }; @@ -117,3 +118,40 @@ $work = ''; ok(Imager::i_writeppm_wiol($im, $IO9), "write to short cb"); ok($work eq $data2, "short write image match"); +{ + my $buf_data = "Test data"; + my $io9 = Imager::io_new_buffer($buf_data); + is(ref $io9, "Imager::IO", "check class"); + my $work; + is($io9->read($work, 4), 4, "read 4 from buffer object"); + is($work, "Test", "check data read"); + is($io9->read($work, 5), 5, "read the rest"); + is($work, " data", "check data read"); + is($io9->seek(5, SEEK_SET), 5, "seek"); + is($io9->read($work, 5), 4, "short read"); + is($work, "data", "check data read"); + is($io9->seek(-1, SEEK_CUR), 8, "seek relative"); + is($io9->seek(-5, SEEK_END), 4, "seek relative to end"); + is($io9->seek(-10, SEEK_CUR), -1, "seek failure"); + undef $io9; +} +{ + my $io = Imager::io_new_bufchain(); + is(ref $io, "Imager::IO", "check class"); + is($io->write("testdata"), 8, "check write"); + is($io->seek(-8, SEEK_CUR), 0, "seek relative"); + my $work; + is($io->read($work, 8), 8, "check read"); + is($work, "testdata", "check data read"); + is($io->seek(-3, SEEK_END), 5, "seek end relative"); + is($io->read($work, 5), 3, "short read"); + is($work, "ata", "check read data"); + is($io->seek(4, SEEK_SET), 4, "absolute seek to write some"); + is($io->write("testdata"), 8, "write"); + is($io->seek(0, SEEK_CUR), 12, "check size"); + $io->close(); + + # grab the data + my $data = Imager::io_slurp($io); + is($data, "testtestdata", "check we have the right data"); +}