/**
 * Graphics::PNG is PNG library
 *
 * unkown_chunk.c defines one class:
 *  Graphics::PNG::UnknownChunk.
 * This class is wrapper objects for libpng's png_unknown_chunk struct.
 * It's for the representation of unknown chunks.
 *
 * @author DATE Ken (as Itacchi) / ge6537@i.bekkoame.ne.jp
 * @code-name Aoi
 * @see http://www.isc.meiji.ac.jp/~ee77038/ruby/
 * $Id: unknown_chunk.c,v 1.1 2000/09/27 17:19:44 date Exp date $
 */

#include "libpng.h"

VALUE cUnknownChunk;

/*
 * ---------------------------
 * Graphics::PNG::UnknownChunk
 * ---------------------------
 * is a wrapper object of the libpng's png_unknown_chunk struct.
 */
/*
=begin
= (({Graphics::PNG::UnknownChunk}))
A wrapper object of the libpng's png_unknown_chunk struct.


=== class method

--- Graphics::PNG::png_unknown_chunk.new(name, data)
    Create PNG Color object with chunk name and data.


=== instance method

--- Graphics::PNG::UnknownChunk#data
    Get chunk data (binary string).

--- Graphics::PNG::UnknownChunk#data=(str)
    Set chunk data (binary string).

--- Graphics::PNG::UnknownChunk#name
    Get chunk name.

--- Graphics::PNG::UnknownChunk#name=(str)
    Set chunk name, four characters (such as "rUBy").

--- Graphics::PNG::UnknownChunk#size
    Get chunk data size.
=end
*/


#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
/*
 * -----------------------------
 * utility function for
 *   Graphics::PNG::UnknownChunk
 * -----------------------------
 */
void
libpng_unknown_chunk_check_type(obj)
  VALUE obj;
{
  if (rb_class_of(obj) != cUnknownChunk){
    rb_raise(rb_eTypeError,
             "wrong argument type %s (expected Graphics::PNG::UnknownChunk)",
             rb_class2name(CLASS_OF(obj)));
  }
}



static void
libpng_unknown_chunk_free(chunk)
  png_unknown_chunkp chunk;
{
  free(chunk->data);
  free(chunk->name);
  free(chunk);
}




/*
 * -----------------------------
 * class method of
 *   Graphics::PNG::UnknownChunk
 * -----------------------------
 */
static VALUE
libpng_unknown_chunk_new(klass, name, data)
  VALUE klass, name, data;
{
  VALUE new_obj;
  png_unknown_chunkp chunk;

  Check_Type(name, T_STRING);
  Check_Type(data, T_STRING);

  new_obj = Data_Make_Struct(klass, png_unknown_chunk, NULL,
                             libpng_unknown_chunk_free, chunk);

  png_memcpy(chunk->name, STR2CSTR(name), 4);
  chunk->name[4] = '\0';

  chunk->size = (png_size_t)RSTRING(data)->len;
  chunk->data = ALLOC_N(png_byte, chunk->size);
  png_memcpy(chunk->data, STR2CSTR(data), chunk->size);

  return new_obj;
}



VALUE
libpng_unknown_chunk_new2(klass, source_chunk)
  VALUE klass;
  png_unknown_chunkp source_chunk;
{
  VALUE new_obj;
  png_unknown_chunkp chunk;

  new_obj = Data_Make_Struct(klass, png_unknown_chunk, NULL,
                             libpng_unknown_chunk_free, chunk);

  png_memcpy(chunk->name, source_chunk->name, 5);

  chunk->size = strlen(source_chunk->data);
  chunk->data = ALLOC_N(png_byte, chunk->size);
  png_memcpy(chunk->data, source_chunk->data, chunk->size);

  return new_obj;
}




/*
 * -----------------------------
 * instance method of
 *   Graphics::PNG::UnknownChunk
 * -----------------------------
 */
static VALUE
libpng_unknown_chunk_initialize(obj)
  VALUE obj;
{
  return Qnil;
}



static VALUE
libpng_unknown_chunk_get_data(obj)
  VALUE obj;
{
  png_unknown_chunkp chunk;

  Data_Get_Struct(obj, png_unknown_chunk, chunk);

  return rb_str_new2(chunk->data);
}



static VALUE
libpng_unknown_chunk_get_name(obj)
  VALUE obj;
{
  png_unknown_chunkp chunk;

  Data_Get_Struct(obj, png_unknown_chunk, chunk);

  return rb_str_new(chunk->name, 4);
}



static VALUE
libpng_unknown_chunk_get_size(obj)
  VALUE obj;
{
  png_unknown_chunkp chunk;

  Data_Get_Struct(obj, png_unknown_chunk, chunk);

  return INT2NUM(chunk->size);
}



static VALUE
libpng_unknown_chunk_inspect(obj)
  VALUE obj;
{
  png_unknown_chunkp chunk;
  char buf[128];
  VALUE str;

  Data_Get_Struct(obj, png_unknown_chunk, chunk);

  str = rb_str_new2("#<PNG::UnknownChunk: ");

  sprintf(buf, "@name=\"%s\">", chunk->name);
  rb_str_cat(str, buf, strlen(buf));

  return str;
}



static VALUE
libpng_unknown_chunk_set_data(obj, data)
  VALUE obj, data;
{
  png_unknown_chunkp chunk;

  Check_Type(data, T_STRING);

  Data_Get_Struct(obj, png_unknown_chunk, chunk);

  if (chunk->data) free(chunk->data);

  chunk->size = (png_size_t)RSTRING(data)->len;
  chunk->data = ALLOC_N(png_byte, chunk->size);
  png_memcpy(chunk->data, STR2CSTR(data), chunk->size);

  return Qnil;
}



static VALUE
libpng_unknown_chunk_set_name(obj, name)
  VALUE obj, name;
{
  png_unknown_chunkp chunk;

  Check_Type(name, T_STRING);

  Data_Get_Struct(obj, png_unknown_chunk, chunk);

  if (chunk->name) free(chunk->name);

  png_memcpy(chunk->name, STR2CSTR(name), 4);
  chunk->name[4] = '\0';

  return Qnil;
}
#endif /* PNG_UNKNOWN_CHUNKS_SUPPORTED */




void
Init_unknown_chunk()
{
  /*
   * ---------------------------
   * Graphics::PNG::UnknownChunk
   * ---------------------------
   */

#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
  cUnknownChunk = rb_define_class_under(mPng, "UnknownChunk", rb_cObject);


  rb_define_singleton_method(cUnknownChunk, "new", libpng_unknown_chunk_new, 2);


  rb_define_method(cUnknownChunk, "initialize", libpng_unknown_chunk_initialize, -1);

  rb_define_method(cUnknownChunk, "data", libpng_unknown_chunk_get_data, 0);
  rb_define_method(cUnknownChunk, "name", libpng_unknown_chunk_get_name, 0);
  rb_define_method(cUnknownChunk, "size", libpng_unknown_chunk_get_size, 0);

  rb_define_method(cUnknownChunk, "inspect", libpng_unknown_chunk_inspect, 0);

  rb_define_method(cUnknownChunk, "data=", libpng_unknown_chunk_set_data, 1);
  rb_define_method(cUnknownChunk, "name=", libpng_unknown_chunk_set_name, 1);
#endif /* PNG_UNKNOWN_CHUNKS_SUPPORTED */
}
