#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_
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
PROTOTYPES: ENABLE
-
-
void
i_list_formats()
PREINIT:
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
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) );
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));
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)
#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_ */
#!perl -w
use strict;
-use Test::More tests => 20;
+use Test::More tests => 43;
+use Fcntl ':seek';
BEGIN { use_ok(Imager => ':all') };
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");
+}