more iolayer goodness:
authorTony Cook <tony@develop=help.com>
Thu, 16 Mar 2006 05:41:10 +0000 (05:41 +0000)
committerTony Cook <tony@develop=help.com>
Thu, 16 Mar 2006 05:41:10 +0000 (05:41 +0000)
- make write/read/seek/close on an IO object visible as methods from perl

- allow SEEK_CUR on bufchains

Imager.xs
iolayer.c
iolayer.h
t/t07iolayer.t

index c0c5e94..50fcc18 100644 (file)
--- 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:
index 9e0e06f..9d1b1af 100644 (file)
--- 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)
index e69b24f..a4ec477 100644 (file)
--- 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_ */
index ca9609e..654c6e6 100644 (file)
@@ -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");
+}