
  - q3 2004.05.30
     . Reader.open(), Writer.open()‚ð�V�Ý�Bˆø�”‚Æ‚µ‚Äƒtƒ@ƒCƒ‹–¼‚ð—^‚¦‚é�B
     . Reader.new(), Writer.new()‚ð•Ï�X�Bˆø�”‚Æ‚µ‚ÄIO, StringIO‚È‚Çread(), write()ƒ�ƒ\ƒbƒh
       ‚ðŽ�‚ÂƒIƒuƒWƒFƒNƒg‚ð—^‚¦‚é�B
     . ŽÀ�sŽž‚É"string contains \0 character"Œx��‚ª�o‚é‚Ì‚ð—}�§�B

diff -Naurw ruby-libpng-0.3.3.orig/libpng.h ruby-libpng-0.3.3/libpng.h
--- ruby-libpng-0.3.3.orig/libpng.h	2000-06-27 08:35:29.000000000 +0900
+++ ruby-libpng-0.3.3/libpng.h	2004-05-29 00:04:52.000000000 +0900
@@ -33,7 +33,7 @@
 #define PNG_BYTES_TO_CHECK 4
 
 typedef struct _png_object {
-  FILE *fp;
+    VALUE io;
   png_structp obj;
   png_infop info;
   png_infop end_info;
diff -Naurw ruby-libpng-0.3.3.orig/reader.c ruby-libpng-0.3.3/reader.c
--- ruby-libpng-0.3.3.orig/reader.c	2000-07-03 19:30:41.000000000 +0900
+++ ruby-libpng-0.3.3/reader.c	2004-05-29 22:51:23.897537192 +0900
@@ -34,18 +34,34 @@
 
 VALUE cReader;
 
+static void close_io(png_object* png_obj)
+{
+    if (png_obj->io) {
+        // rb_funcall(png_obj->io, rb_intern("close"), 0);
+        png_obj->io = NULL;
+    }
+}
+
+static void mark_obj(png_object* ptr)
+{
+    if (ptr->io) 
+        rb_gc_mark(ptr->io);
+}
 
 static void
 libpng_reader_free(png_obj)
   png_object *png_obj;
 {
-  if (png_obj->fp)
-    fclose(png_obj->fp);
+    close_io(png_obj);
   png_destroy_read_struct(&png_obj->obj, &png_obj->info, &png_obj->end_info);
   free(png_obj);
 }
 
-
+static VALUE reader_s_alloc(VALUE klass)
+{
+    png_object* png_obj;
+    return Data_Make_Struct(klass, png_object, mark_obj, libpng_reader_free, png_obj);
+}
 
 static void
 png_default_error(png_ptr, message)
@@ -106,47 +122,50 @@
 }
 */
 
+static VALUE reader_s_open(VALUE klass, VALUE filename)
+{
+    VALUE io;
+    SafeStringValue(filename);
+    io = rb_file_open(RSTRING(filename)->ptr, "rb");
+    return rb_class_new_instance(1, &io, klass);
+}
 
+static void read_data_fn(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+    png_object* png_obj = png_get_io_ptr(png_ptr);
+    VALUE result = rb_funcall(png_obj->io, rb_intern("read"), 1, INT2NUM(length));
+    memcpy(data, RSTRING(result)->ptr, RSTRING(result)->len);
+}
 
 static VALUE
-libpng_reader_new(klass, file)
-  VALUE klass, file;
+reader_initialize(
+    VALUE self,
+    VALUE io)
 {
-  FILE *fp;
-  OpenFile *fptr;
-  VALUE new_obj;
   png_object *png_obj;
-  char buf[PNG_BYTES_TO_CHECK];
-
-
-  Check_Type(file, T_STRING);
+    VALUE buf;
 
-  if ((fp = fopen(STR2CSTR(file), "rb")) == NULL){
-    rb_raise(ePngError, "can't open %s", STR2CSTR(file));
-    return Qnil;
-  }
+    Data_Get_Struct(self, png_object, png_obj);
+    png_obj->io = io;
 
-   if (fread(buf, 1, PNG_BYTES_TO_CHECK, fp) != PNG_BYTES_TO_CHECK){
-    rb_raise(rb_eException, "can't read %s", STR2CSTR(file));
+    buf = rb_funcall(png_obj->io, rb_intern("read"), 1, INT2NUM(PNG_BYTES_TO_CHECK));
+    StringValue(buf);
+    if (RSTRING(buf)->len != PNG_BYTES_TO_CHECK) {
+        rb_raise(rb_eException, "can't read IO");
     return Qnil;
    }
 
-  if (png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK)){
-    rb_raise(ePngError, "not PNG file %s", STR2CSTR(file));
+    if (png_sig_cmp(RSTRING(buf)->ptr, (png_size_t) 0, PNG_BYTES_TO_CHECK)) {
+        rb_raise(ePngError, "not PNG file");
     return Qnil;
   }
 
   /* create PNG object */
-
-  new_obj = Data_Make_Struct(klass, png_object, NULL, libpng_reader_free, png_obj);
-
-  png_obj->fp = fp;
-
   png_obj->obj = png_create_read_struct(PNG_LIBPNG_VER_STRING,
     (png_voidp)NULL, png_default_error, png_default_warning);
 
   if (png_obj->obj == NULL){
-    fclose(fp);
+      close_io(png_obj);
     rb_raise(ePngError, "can't create PNG object (failer to create read struct)");
     return Qnil;
   }
@@ -157,20 +176,20 @@
   png_obj->end_info = png_create_info_struct(png_obj->obj);
 
   if (png_obj->info == NULL || png_obj->end_info == NULL){
-    fclose(fp);
+      close_io(png_obj);
     png_destroy_read_struct(&png_obj->obj, &png_obj->info, &png_obj->end_info);
     rb_raise(ePngError, "can't create PNG object (failer to create info struct)");
     return Qnil;
   }
 
   if (setjmp(png_jmpbuf(png_obj->obj))){
-     fclose(fp);
+      close_io(png_obj);
      png_destroy_read_struct(&png_obj->obj, &png_obj->info, &png_obj->end_info);
      rb_raise(ePngError, "PNG read error");
      return Qnil;
    }
 
-  png_init_io(png_obj->obj, png_obj->fp);
+    png_set_read_fn(png_obj->obj, png_obj, read_data_fn);
 
   png_read_info(png_obj->obj, png_obj->info);
 
@@ -180,9 +199,7 @@
   png_set_read_user_transform_fn(read_ptr, read_user_transform);
 */
 
-  rb_obj_call_init(new_obj, 1, &file);
-
-  return new_obj;
+    return Qnil;
 }
 
 
@@ -1894,13 +1911,13 @@
 Init_reader()
 {
   cReader = rb_define_class_under(mPng, "Reader", rb_cObject);
-
+    rb_define_alloc_func(cReader, reader_s_alloc);
 
   /* define class methods */
-  rb_define_singleton_method(cReader, "new", libpng_reader_new, 1);
-
+    rb_define_singleton_method(cReader, "open", reader_s_open, 1);
 
   /* define instance methods */
+    rb_define_method(cReader, "initialize", reader_initialize, 1);
   rb_define_method(cReader, "get_bit_depth", libpng_reader_get_bit_depth, 0);
 
 #if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
diff -Naurw ruby-libpng-0.3.3.orig/sample/pngcat.rb ruby-libpng-0.3.3/sample/pngcat.rb
--- ruby-libpng-0.3.3.orig/sample/pngcat.rb	2000-06-26 21:42:31.000000000 +0900
+++ ruby-libpng-0.3.3/sample/pngcat.rb	2004-05-29 22:54:34.829511120 +0900
@@ -15,13 +15,13 @@
 in_name = []
 rpng = []
 
-wpng = Writer.new out_name
+wpng = Writer.open(out_name)
 
 print "PNG image writer creater. (for #{out_name})\n"
 
 for i in 0..3
   in_name[i] = number[i].chr + ".png"
-  rpng[i] = Reader.new in_name[i]
+  rpng[i] = Reader.open(in_name[i])
   print "PNG image reader created (for #{in_name[i]}).\n"
 end
 
@@ -59,7 +59,7 @@
 
 for i in 0..3
   in_images[i] = rpng[i].read_image
-  print "Reading image data from #{in_name[i]}\n"
+  print "Reading image data from '#{in_name[i]}': #{in_images[i][0].size} bytes * #{in_images[i].size} lines.\n"
 end
 
 
diff -Naurw ruby-libpng-0.3.3.orig/writer.c ruby-libpng-0.3.3/writer.c
--- ruby-libpng-0.3.3.orig/writer.c	2000-06-30 23:56:22.000000000 +0900
+++ ruby-libpng-0.3.3/writer.c	2004-05-29 23:27:46.569720584 +0900
@@ -28,12 +28,25 @@
 
 VALUE cWriter;
 
+static void close_io(png_object* png_obj)
+{
+    if (png_obj->io) {
+        // rb_funcall(png_obj->io, rb_intern("close"), 0);   // GC‚É”C‚¹‚é
+        png_obj->io = NULL;
+    }
+}
+
+static void mark_obj(png_object* ptr)
+{
+    if (ptr->io)
+        rb_gc_mark(ptr->io);
+}
+
 static void
 writer_free(png_obj)
   png_object *png_obj;
 {
-  if (png_obj->fp)
-    fclose(png_obj->fp);
+    close_io(png_obj);
   if (png_obj->info->valid & PNG_INFO_PLTE)
     free(png_obj->info->palette);
   if (png_obj->info->valid & PNG_INFO_tRNS)
@@ -43,7 +56,11 @@
   free(png_obj);
 }
 
-
+static VALUE writer_s_alloc(VALUE klass)
+{
+    png_object* png_obj;
+    return Data_Make_Struct(klass, png_object, mark_obj, writer_free, png_obj);
+}
 
 static void
 png_default_error(png_ptr, message)
@@ -85,41 +102,49 @@
 
 
 
-static VALUE
-writer_new(klass, file)
-  VALUE klass, file;
+static VALUE writer_s_open(VALUE klass, VALUE filename)
 {
-  FILE *fp;
-  OpenFile *fptr;
-  VALUE new_obj;
-  png_object *png_obj;
-
-
-  Check_Type(file, T_STRING);
+    VALUE io;
+    SafeStringValue(filename);
+    io = rb_file_open(RSTRING(filename)->ptr, "wb");
+    return rb_class_new_instance(1, &io, klass);
+}
 
-  if ((fp = fopen(STR2CSTR(file), "wb")) == NULL){
-    rb_raise(rb_eException, "can't open: %s", STR2CSTR(file));
-    return Qnil;
+static void write_data_fn(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+    png_object* png_obj = png_get_io_ptr(png_ptr);
+    rb_funcall(png_obj->io, rb_intern("write"), 1, rb_str_new(data, length));
   }
 
-  /* create PNG object */
+static void flush_io_fn(png_structp png_ptr)
+{
+    png_object* png_obj = png_get_io_ptr(png_ptr);
+    rb_funcall(png_obj->io, rb_intern("flush"), 0);
+}
 
-  new_obj = Data_Make_Struct(klass, png_object, NULL, writer_free, png_obj);
+static VALUE
+writer_initialize(
+    VALUE self,
+    VALUE io)
+{
+  png_object *png_obj;
 
-  png_obj->fp = fp;
+    Data_Get_Struct(self, png_object, png_obj);
+    png_obj->io = io;
 
+  /* create PNG object */
   png_obj->obj = png_create_write_struct(PNG_LIBPNG_VER_STRING,
     (png_voidp)NULL, png_default_error, png_default_warning);
 
   if (png_obj->obj == NULL){
-    fclose(fp);
+      close_io(png_obj);
     rb_raise(rb_eException, "can't create PNG object (failer to create write struct)");
     return Qnil;
   }
 
   png_obj->info = png_create_info_struct(png_obj->obj);
   if (png_obj->info == NULL){
-    fclose(fp);
+      close_io(png_obj);
     png_destroy_write_struct(&png_obj->obj, (png_infopp)NULL);
     rb_raise(rb_eException, "can't create PNG object (failer to create info struct)");
     return Qnil;
@@ -127,25 +152,23 @@
 
   png_obj->end_info = png_create_info_struct(png_obj->obj);
   if (png_obj->end_info == NULL){
-    fclose(fp);
+      close_io(png_obj);
     png_destroy_write_struct(&png_obj->obj, &png_obj->info);
     rb_raise(rb_eException, "can't create PNG object (failer to create info struct)");
     return Qnil;
   }
 
   if (setjmp(png_jmpbuf(png_obj->obj))){
-     fclose(fp);
+      close_io(png_obj);
      png_destroy_info_struct(png_obj->obj, &png_obj->end_info);
      png_destroy_write_struct(&png_obj->obj, &png_obj->info);
      rb_raise(rb_eException, "can't create PNG object (failer to create write struct)");
      return Qnil;
    }
 
-  png_init_io(png_obj->obj, png_obj->fp);
+    png_set_write_fn(png_obj->obj, png_obj, write_data_fn, flush_io_fn);
 
-  rb_obj_call_init(new_obj, 1, &file);
-
-  return new_obj;
+  return Qnil;
 }
 
 
@@ -1278,7 +1301,7 @@
 
 
 
-static void
+static VALUE
 libpng_writer_set_write_status_fn(obj, proc)
   VALUE obj, proc;
 {
@@ -1321,9 +1344,11 @@
   height = RARRAY(image)->len;
 
   for (row=0; row<height; row++){
-    image_data[row] = ALLOC_N(png_byte, RSTRING(RARRAY(image)->ptr[row])->len);
-    png_memcpy(image_data[row], STR2CSTR(RARRAY(image)->ptr[row]),
-               RSTRING(RARRAY(image)->ptr[row])->len);
+      struct RString* str;
+      Check_Type(RARRAY(image)->ptr[row], T_STRING);
+      str = RSTRING(RARRAY(image)->ptr[row]);
+      image_data[row] = ALLOC_N(png_byte, str->len);
+      png_memcpy(image_data[row], str->ptr, str->len);
 /*
 for (i=0;i<RSTRING(RARRAY(image)->ptr[row])->len;i++)
   printf("%2x ", image_data[row][i]);
@@ -1368,8 +1393,13 @@
 Init_writer()
 {
   cWriter = rb_define_class_under(mPng, "Writer", rb_cObject);
+    rb_define_alloc_func(cWriter, writer_s_alloc);
+
+    /* define class methods */
+  rb_define_singleton_method(cWriter, "open", writer_s_open, 1);
 
-  rb_define_singleton_method(cWriter, "new", writer_new, 1);
+    /* define instance methods */
+    rb_define_method(cWriter, "initialize", writer_initialize, 1);
 
 #if defined(PNG_READ_BACKGROUND_SUPPORTED)
 #ifdef PNG_FLOATING_POINT_SUPPORTED
