#include<stdio.h>
#include<hdf5.h>
#include<HE5_HdfEosDef.h>
#include "ruby.h"
#include "narray.h"
#include<string.h>

/* for compatibility with ruby 1.6 */
#ifndef RARRAY_PTR
#define RARRAY_PTR(a) (RARRAY(a)->ptr)
#endif
#ifndef RARRAY_LEN
#define RARRAY_LEN(a) (RARRAY(a)->len)
#endif
#ifndef RSTRING_PTR
#define RSTRING_PTR(s) (RSTRING(s)->ptr)
#endif
#ifndef SafeStringValue
#define SafeStringValue(s) Check_SafeStr(s)
#endif

extern int   check_numbertype(char *);
extern int   change_numbertype(char *);
extern int   change_entrycode(char *);
extern int   change_compmethod(char *);
extern int   change_groupcode(char *);
extern void  HE5Wrap_make_NArray1D_or_str(int, size_t, VALUE *, void **);
extern void  HE5Wrap_store_NArray1D_or_str(int,  VALUE , void **);
extern void  change_chartype(hid_t, char *);
extern void  change_comptype(hid_t, char *);

extern int     *hdfeos5_obj2cintary(VALUE);
extern long    *hdfeos5_obj2clongary(VALUE);
extern float   *hdfeos5_obj2cfloatary(VALUE);
extern signed long long   *hdfeos5_obj2csint64ary(VALUE);
extern unsigned long long *hdfeos5_obj2cunsint64ary(VALUE);

extern VALUE hdfeos5_ccharary2obj(char *, int, int);
extern VALUE hdfeos5_cintary2obj(int *, int, int, int *);
extern VALUE hdfeos5_clongary2obj(long *, int, int, int *);
extern VALUE hdfeos5_cunsint64ary2obj(unsigned long long *, int, int, int *);

extern void hdfeos5_freecintary(int *);
extern void hdfeos5_freeclongary(long *);
extern void hdfeos5_freecfloatary(float *);
extern void hdfeos5_freecsint64ary(signed long long *);
extern void hdfeos5_freecunsint64ary(unsigned long long *);

VALUE hdfeos5_zawrite_char(VALUE, VALUE, VALUE, VALUE, VALUE);
VALUE hdfeos5_zawrite_short(VALUE, VALUE, VALUE, VALUE, VALUE);
VALUE hdfeos5_zawrite_int(VALUE, VALUE, VALUE, VALUE, VALUE);
VALUE hdfeos5_zawrite_long(VALUE, VALUE, VALUE, VALUE, VALUE);
VALUE hdfeos5_zawrite_float(VALUE, VALUE, VALUE, VALUE, VALUE);
VALUE hdfeos5_zawrite_double(VALUE, VALUE, VALUE, VALUE, VALUE);

VALUE hdfeos5_zaread_char(VALUE, VALUE, VALUE, VALUE);
VALUE hdfeos5_zaread_short(VALUE, VALUE, VALUE, VALUE);
VALUE hdfeos5_zaread_int(VALUE, VALUE, VALUE, VALUE);
VALUE hdfeos5_zaread_long(VALUE, VALUE, VALUE, VALUE);
VALUE hdfeos5_zaread_float(VALUE, VALUE, VALUE, VALUE);
VALUE hdfeos5_zaread_double(VALUE, VALUE, VALUE, VALUE);

#define Cbyte_to_NArray(v, rank, shape, up) \
{ \
    struct NARRAY *ary; \
    v = na_make_object(NA_BYTE, rank, shape, cNArray); \
    GetNArray(v,ary); \
    up = (unsigned char *)ary->ptr; \
}
#define Cshort_to_NArray(v, rank, shape, lp) \
{ \
    struct NARRAY *ary; \
    v = na_make_object(NA_SINT, rank, shape, cNArray); \
    GetNArray(v, ary); \
    lp = (short *)ary->ptr; \
}
#define Cint_to_NArray(v, rank, shape, lp) \
{ \
    struct NARRAY *ary; \
    v = na_make_object(NA_LINT, rank, shape, cNArray); \
    GetNArray(v, ary); \
    lp = (int *)ary->ptr; \
}
#define Clong_to_NArray(v, rank, shape, lp) \
{ \
    struct NARRAY *ary; \
    v = na_make_object(NA_LINT, rank, shape, cNArray); \
    GetNArray(v, ary); \
    lp = (long *)ary->ptr; \
}
#define Cfloat_to_NArray(v, rank, shape, fp) \
{ \
    struct NARRAY *ary; \
    v = na_make_object(NA_SFLOAT, rank, shape, cNArray); \
    GetNArray(v, ary); \
    fp = (float *)ary->ptr; \
}
#define Cdouble_to_NArray(v, rank, shape, dp); \
{ \
    struct NARRAY *ary; \
    v = na_make_object(NA_DFLOAT, rank, shape, cNArray); \
    GetNArray(v, ary); \
    dp = (double *)ary->ptr; \
}

/* Array or NArray to pointer and length (with no new allocation) */
#define Array_to_Cfloat_len_shape(obj, ptr, len, shape) \
{ \
    struct NARRAY *na; \
    obj = na_cast_object(obj, NA_SFLOAT); \
    GetNArray(obj, na); \
    ptr = (float *) NA_PTR(na,0); \
    len = na->total; \
    shape = na->shape; \
}
#define Array_to_Cdouble_len_shape(obj, ptr, len, shape) \
{ \
    struct NARRAY *na; \
    obj = na_cast_object(obj, NA_DFLOAT); \
    GetNArray(obj, na); \
    ptr = (double *) NA_PTR(na,0); \
    len = na->total; \
    shape = na->shape; \
}
#define Array_to_Cbyte_len_shape(obj, ptr, len, shape) \
{ \
    struct NARRAY *na; \
    obj = na_cast_object(obj, NA_BYTE); \
    GetNArray(obj, na); \
    ptr = (u_int8_t *) NA_PTR(na,0); \
    len = na->total; \
    shape = na->shape; \
}
#define Array_to_Cshort_len_shape(obj, ptr, len, shape) \
{ \
    struct NARRAY *na; \
    obj = na_cast_object(obj, NA_SINT); \
    GetNArray(obj, na); \
    ptr = (int16_t *) NA_PTR(na,0); \
    len = na->total; \
    shape = na->shape; \
}
#define Array_to_Cint_len_shape(obj, ptr, len, shape) \
{ \
    struct NARRAY *na; \
    obj = na_cast_object(obj, NA_LINT); \
    GetNArray(obj, na); \
    ptr = (int32_t *) NA_PTR(na,0); \
    len = na->total; \
    shape = na->shape; \
}
#define Array_to_Clong_len_shape(obj, ptr, len, shape) \
{ \
    struct NARRAY *na; \
    obj = na_cast_object(obj, NA_LINT); \
    GetNArray(obj, na); \
    ptr = (long *) NA_PTR(na,0); \
    len = na->total; \
    shape = na->shape; \
}

#define maxcharsize  3000

static VALUE rb_eHE5Error;
static VALUE mNumRu = 0;
static VALUE cHE5;
static VALUE cHE5Za;
static VALUE cHE5ZaField;

struct HE5{
  hid_t fid;
  char *name;
  int closed;
};

struct HE5Za{
  hid_t zaid;
  char *name;
  char *fname;
  hid_t fid;
  VALUE file;
};

struct HE5ZaField{
  char *name;
  hid_t zaid;
  VALUE za;
};

static struct HE5Za *
HE5Za_init(hid_t zaid, char *name, hid_t fid, VALUE file)
{
  struct HE5Za *HE5ZA;
  HE5ZA=xmalloc(sizeof(struct HE5Za));
  HE5ZA->zaid=zaid;
  HE5ZA->fid=fid;
  HE5ZA->name=xmalloc((strlen(name)+1)*sizeof(char));
  strcpy(HE5ZA->name,name);
  HE5ZA->file=file;
  return(HE5ZA);
}

static struct HE5ZaField *
HE5ZaField_init(char *name,hid_t zaid,VALUE za)
{
  struct HE5ZaField *HE5Za_Field;
  HE5Za_Field=xmalloc(sizeof(struct HE5ZaField));
  HE5Za_Field->zaid=zaid;
  HE5Za_Field->za=za;
  HE5Za_Field->name=xmalloc((strlen(name)+1)*sizeof(char));
  strcpy(HE5Za_Field->name,name);
  return(HE5Za_Field);
}

void
HE5Za_free(struct HE5Za *HE5_ZA)
{
  free(HE5_ZA->name);
  free(HE5_ZA);
}

void
HE5ZaField_free(struct HE5ZaField *HE5Za_Field)
{
  free(HE5Za_Field->name);
  free(HE5Za_Field);
}

static void
he5zafield_mark_obj(struct HE5ZaField *he5fld)
{
    VALUE ptr;

    ptr = he5fld->za;
    rb_gc_mark(ptr);
}

static void
he5za_mark_obj(struct HE5Za *he5za)
{
    VALUE ptr;

    ptr = he5za->file;
    rb_gc_mark(ptr);
}

VALUE
HE5Za_clone(VALUE za)
{
    VALUE clone;
    struct HE5Za *he5za1, *he5za2;

    Data_Get_Struct(za, struct HE5Za, he5za1);
    he5za2 = HE5Za_init(he5za1->zaid, he5za1->name, he5za1->fid, he5za1->file);
    clone = Data_Wrap_Struct(cHE5Za, he5za_mark_obj, HE5Za_free, he5za2);
    CLONESETUP(clone, za);
    return clone;
}

VALUE
HE5ZaField_clone(VALUE field)
{
    VALUE clone;
    struct HE5ZaField *he5fld1, *he5fld2;

    Data_Get_Struct(field, struct HE5ZaField, he5fld1);
    he5fld2 = HE5ZaField_init(he5fld1->name, he5fld1->zaid, he5fld1->za);
    clone = Data_Wrap_Struct(cHE5ZaField, he5zafield_mark_obj, HE5ZaField_free, he5fld2);
    CLONESETUP(clone, field);
    return clone;
}

long
zanentries_count(hid_t i_zaid, VALUE entrycode)
{
    char *c_entrycode;
    long o_strbufsize;
    long o_count;

    Check_Type(entrycode,T_STRING);
    SafeStringValue(entrycode);
    c_entrycode = RSTRING_PTR(entrycode);

    o_count = HE5_ZAnentries(i_zaid, change_entrycode(c_entrycode), &o_strbufsize);
    if (o_count < 0 ) return  Qfalse ;
    return(o_count);
}

long
zanentries_strbuf(hid_t i_zaid, VALUE entrycode)
{
    char *c_entrycode;
    long o_strbufsize;
    long o_count;

    Check_Type(entrycode,T_STRING);
    SafeStringValue(entrycode);
    c_entrycode = RSTRING_PTR(entrycode);

    o_count = HE5_ZAnentries(i_zaid, change_entrycode(c_entrycode), &o_strbufsize);
    if (o_count < 0 ) return  Qfalse ;
    return(o_strbufsize);
}

VALUE
hdfeos5_zacreate(VALUE mod, VALUE zaname)
{
    hid_t i_fid;
    hid_t zaid;
    char* i_zaname;
    struct HE5 *he5file;
    struct HE5Za *he5za;
    char*  file;
    VALUE ZA;

    rb_secure(4);
    Data_Get_Struct(mod, struct HE5, he5file);
    i_fid=he5file->fid;
    file=he5file->name;

    Check_Type(zaname,T_STRING);
    SafeStringValue(zaname);
    i_zaname = RSTRING_PTR(zaname);

    zaid = HE5_ZAcreate(i_fid, i_zaname);
    if(zaid == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    he5za = HE5Za_init(zaid, i_zaname, i_fid, mod);
    ZA = Data_Wrap_Struct(cHE5Za, he5za_mark_obj, HE5Za_free, he5za);
    return(ZA);
}

VALUE
hdfeos5_zaattach(VALUE mod, VALUE zaname)
{
    hid_t i_fid;
    hid_t zaid;
    char *i_zaname, *i_fname;
    struct HE5 *he5file;
    struct HE5Za *he5za;
    VALUE ZA;

    rb_secure(4);
    Data_Get_Struct(mod, struct HE5, he5file);
    i_fid=he5file->fid;
    i_fname=he5file->name;

    Check_Type(zaname,T_STRING);
    SafeStringValue(zaname);
    i_zaname = RSTRING_PTR(zaname);

    zaid = HE5_ZAattach(i_fid, i_zaname);
    if(zaid == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);

    he5za = HE5Za_init(zaid, i_zaname, i_fid, mod);
    ZA = Data_Wrap_Struct(cHE5Za, he5za_mark_obj, HE5Za_free, he5za);
    return(ZA);
}

VALUE
hdfeos5_zadefdim(VALUE mod, VALUE dimname, VALUE dim)
{
    hid_t i_zaid;
    char *i_dimname;
    unsigned long long i_dim;
    herr_t o_rtn_val;
    VALUE rtn_val;
    struct HE5Za *he5za;

    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;
    Check_Type(dimname,T_STRING);
    SafeStringValue(dimname);
    Check_Type(dim,T_FIXNUM);
    i_dimname = RSTRING_PTR(dimname);
    i_dim = NUM2LONG(dim);
    o_rtn_val = HE5_ZAdefdim(i_zaid, i_dimname, i_dim);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    return(dimname);
}

VALUE
hdfeos5_zadiminfo(VALUE mod, VALUE dimname)
{
    hid_t i_zaid;
    char *i_dimname;
    unsigned long long o_ndim;
    VALUE ndim;
    struct HE5Za *he5za;

    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    Check_Type(dimname,T_STRING);
    SafeStringValue(dimname);
    i_dimname = RSTRING_PTR(dimname);

    o_ndim = HE5_ZAdiminfo(i_zaid, i_dimname);
    ndim = LONG2NUM(o_ndim);
    return(ndim);
}

VALUE
hdfeos5_zacompinfo(VALUE mod)
{
    hid_t i_zaid;
    char *i_fldname;
    int ncomplevel=32;  /* Set compression level: value 0,1,2,3,4,5,6,7,8,9,10,16, or 32 */
    int o_compcode;
    void *o_compparm;
    herr_t o_rtn_val;
    char str[maxcharsize];
    VALUE compcode;
    VALUE compparm;
    VALUE rtn_val;
    struct HE5ZaField *he5field;

    rb_secure(4);
    Data_Get_Struct(mod, struct HE5ZaField, he5field);
    i_fldname=he5field->name;
    i_zaid=he5field->zaid;

    HE5Wrap_make_NArray1D_or_str(HE5T_NATIVE_INT, ncomplevel, &compparm, &o_compparm); 
    o_rtn_val = HE5_ZAcompinfo(i_zaid, i_fldname, &o_compcode, o_compparm);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    change_comptype(o_compcode,str);
    compcode =rb_str_new2(str);
    return rb_ary_new3(2, compcode, compparm);
}

VALUE
hdfeos5_zainfo(VALUE mod)
{
    hid_t i_zaid;
    char *i_fldname;
    int i_rank;
    hid_t i_ntype = FAIL;
    unsigned long long hs_dims[maxcharsize];
    char o_dimlist[maxcharsize];
    char str[maxcharsize];
    herr_t o_rtn_val;
    VALUE rank;
    VALUE dims;
    VALUE ntype;
    VALUE dimlist;
    struct HE5ZaField *he5field;

    rb_secure(4);
    Data_Get_Struct(mod, struct HE5ZaField, he5field);
    i_fldname=he5field->name;
    i_zaid=he5field->zaid;

    o_rtn_val = HE5_ZAinfo(i_zaid, i_fldname, &i_rank, hs_dims, &i_ntype, o_dimlist, NULL);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    rank = INT2NUM(i_rank);
    dims = hdfeos5_cunsint64ary2obj(hs_dims, i_rank, 1, &i_rank);
    change_chartype(i_ntype, str);
    ntype =rb_str_new2(str);
    dimlist = rb_str_new2(o_dimlist);

    return rb_ary_new3(4, rank, dims, ntype, dimlist);
}

VALUE
hdfeos5_zadefchunk(VALUE mod, VALUE rank, VALUE dim)
{
    hid_t i_zaid;
    int i_rank;
    unsigned long long *i_dim;
    herr_t o_rtn_val;
    VALUE rtn_val;

    struct HE5Za *he5za;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    Check_Type(rank,T_FIXNUM);
    i_rank = NUM2INT(rank);
    if ((TYPE(dim) == T_BIGNUM) || (TYPE(dim) == T_FIXNUM)) {
      dim = rb_Array(dim);
    }
    i_dim = hdfeos5_obj2cunsint64ary(dim);

    o_rtn_val = HE5_ZAdefchunk(i_zaid, i_rank, i_dim);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    hdfeos5_freecunsint64ary(i_dim);
    return(rtn_val);
}

VALUE
hdfeos5_zadefcomp(VALUE mod, VALUE compcode, VALUE compparm)
{
    hid_t i_zaid;
    int i_compcode;
    int *i_compparm;
    herr_t o_rtn_val;
    VALUE rtn_val;

    struct HE5Za *he5za;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    Check_Type(compcode,T_STRING);
    SafeStringValue(compcode);
    if ((TYPE(compparm) == T_BIGNUM) || (TYPE(compparm) == T_FIXNUM)) {
      compparm = rb_Array(compparm);
    }
    i_compcode = change_compmethod(RSTRING_PTR(compcode));
    i_compparm = hdfeos5_obj2cintary(compparm);

    o_rtn_val = HE5_ZAdefcomp(i_zaid, i_compcode, i_compparm);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    hdfeos5_freecintary(i_compparm);
    return(rtn_val);
}

VALUE
hdfeos5_zadefcomchunk(VALUE mod, VALUE compcode, VALUE compparm, VALUE rank, VALUE dim)
{
    hid_t i_zaid;
    int i_compcode;
    int *i_compparm;
    int i_rank;
    unsigned long long *i_dim;
    herr_t o_rtn_val;
    VALUE rtn_val;

    struct HE5Za *he5za;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    Check_Type(compcode,T_STRING);
    SafeStringValue(compcode);
    if ((TYPE(compparm) == T_BIGNUM) || (TYPE(compparm) == T_FIXNUM)) {
      compparm = rb_Array(compparm);
    }
    i_compcode = change_compmethod(RSTRING_PTR(compcode));
    i_compparm = hdfeos5_obj2cintary(compparm);

    Check_Type(rank,T_FIXNUM);
    i_rank = NUM2INT(rank);
    if ((TYPE(dim) == T_BIGNUM) || (TYPE(dim) == T_FIXNUM)) {
      dim = rb_Array(dim);
    }
    i_dim = hdfeos5_obj2cunsint64ary(dim);

    o_rtn_val = HE5_ZAdefcomchunk(i_zaid, i_compcode, i_compparm, i_rank, i_dim);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    hdfeos5_freecintary(i_compparm);
    hdfeos5_freecunsint64ary(i_dim);
    return(rtn_val);
}

VALUE
hdfeos5_zadefine(VALUE file, VALUE fieldname, VALUE dimlist, VALUE maxdimlist, VALUE numbertype)
{
    hid_t i_zaid;
    char *i_fieldname;
    char *i_dimlist;
    char *i_maxdimlist;
    hid_t i_numbertype;
    herr_t o_rtn_val;
    VALUE rtn_val;

    struct HE5ZaField *he5field;
    struct HE5Za *he5za;
    rb_secure(4);
    Data_Get_Struct(file, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    Check_Type(fieldname,T_STRING);
    SafeStringValue(fieldname);
    Check_Type(dimlist,T_STRING);
    SafeStringValue(dimlist);
    Check_Type(maxdimlist,T_STRING);
    SafeStringValue(maxdimlist);
    Check_Type(numbertype,T_STRING);
    SafeStringValue(numbertype);

    i_fieldname = RSTRING_PTR(fieldname);
    i_dimlist = RSTRING_PTR(dimlist);
    i_maxdimlist = RSTRING_PTR(maxdimlist);
    i_numbertype = change_numbertype(RSTRING_PTR(numbertype));

    if(strcmp(i_maxdimlist,"NULL")==0)  i_maxdimlist = NULL;
    o_rtn_val = HE5_ZAdefine(i_zaid, i_fieldname, i_dimlist, i_maxdimlist, i_numbertype);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;

    he5field = HE5ZaField_init(i_fieldname, i_zaid, file);
    return(Data_Wrap_Struct(cHE5ZaField, he5zafield_mark_obj, HE5ZaField_free, he5field));
}

VALUE
hdfeos5_zawritedatameta(VALUE mod, VALUE dimlist, VALUE mvalue)
{
    hid_t i_zaid;
    char *i_fieldname;
    char *i_dimlist;
    hid_t i_mvalue;
    herr_t o_rtn_val;
    VALUE rtn_val;

    struct HE5ZaField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5ZaField, he5field);
    i_fieldname=he5field->name;
    i_zaid=he5field->zaid;

    Check_Type(dimlist,T_STRING);
    SafeStringValue(dimlist);
    Check_Type(mvalue,T_FIXNUM);

    i_dimlist = RSTRING_PTR(dimlist);
    i_mvalue = NUM2INT(mvalue);

    o_rtn_val = HE5_ZAwritedatameta(i_zaid, i_fieldname, i_dimlist, i_mvalue);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    return(rtn_val);

}

VALUE
hdfeos5_zawriteattr(VALUE mod, VALUE attrname, VALUE numbertype, VALUE count, VALUE datbuf)
{
    hid_t i_zaid;
    char *i_attrname;
    hid_t i_numbertype;
    hid_t i_numbertypechk;
    unsigned long long *i_count;
    void *i_datbuf;
    herr_t o_rtn_val;
    VALUE rtn_val;

    struct HE5Za *he5za;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    Check_Type(attrname,T_STRING);
    SafeStringValue(attrname);
    Check_Type(numbertype,T_STRING);
    SafeStringValue(numbertype);
    count = rb_Array(count);

    i_attrname = RSTRING_PTR(attrname);
    i_numbertype    = change_numbertype(RSTRING_PTR(numbertype));
    i_numbertypechk = check_numbertype(RSTRING_PTR(numbertype));
    i_count = hdfeos5_obj2cunsint64ary(count);

    HE5Wrap_store_NArray1D_or_str(i_numbertypechk, datbuf, &i_datbuf); 
    o_rtn_val = HE5_ZAwriteattr(i_zaid, i_attrname, i_numbertype, i_count, i_datbuf);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    hdfeos5_freecunsint64ary(i_count);
    return(rtn_val);
}

VALUE
hdfeos5_za_get_att(VALUE mod, VALUE attrname)
{
    VALUE result;
    hid_t i_zaid;
    char *i_attrname;
    hid_t o_ntype;
    void *o_datbuf;
    unsigned long long o_count;
    herr_t o_rtn_val;

    struct HE5Za *he5za;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    Check_Type(attrname,T_STRING);
    SafeStringValue(attrname);
    i_attrname = RSTRING_PTR(attrname);

    o_rtn_val = HE5_ZAattrinfo(i_zaid, i_attrname, &o_ntype, &o_count);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    HE5Wrap_make_NArray1D_or_str(o_ntype, o_count, &result, &o_datbuf); 
    o_rtn_val = HE5_ZAreadattr(i_zaid, i_attrname, o_datbuf);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    return result;
}

VALUE
hdfeos5_zainqattrs(VALUE mod)
{
    hid_t i_zaid;
    char *o_attrnames;
    long  o_strbufsize;
    long  o_number;
    VALUE nattr;
    VALUE attrnames;
    VALUE strbufsize;

    struct HE5Za *he5za;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    o_number = HE5_ZAinqattrs(i_zaid, NULL, &o_strbufsize);
    if(o_number < 0 ) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    o_attrnames = ALLOCA_N(char, (o_strbufsize + 1));

    o_number = HE5_ZAinqattrs(i_zaid, o_attrnames, &o_strbufsize);
    if(o_number < 0 ) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    nattr = LONG2NUM(o_number);
    attrnames = rb_str_new(o_attrnames,o_strbufsize);
    strbufsize = INT2NUM(o_strbufsize);

    return rb_ary_new3(3, nattr, attrnames, strbufsize);
}

VALUE
hdfeos5_zainqdims(VALUE mod, VALUE entrycode)
{
    hid_t i_zaid;
    int i_count;
    long i_strbufsize;
    char *o_dimnames;
    unsigned long long *hs_dims;
    long o_ndims;
    VALUE ndims;
    VALUE dimnames;
    VALUE dims;

    struct HE5Za *he5za;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    i_count = zanentries_count(i_zaid, entrycode);
    i_strbufsize = zanentries_strbuf(i_zaid, entrycode);

    hs_dims = ALLOCA_N(unsigned long long,  i_count);
    o_dimnames = ALLOCA_N(char, (i_strbufsize + 1));
    
    o_ndims = HE5_ZAinqdims(i_zaid, o_dimnames, hs_dims);
    if(o_ndims < 0 ) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    ndims = LONG2NUM(o_ndims);
    dimnames = rb_str_new(o_dimnames,i_strbufsize);
    dims = hdfeos5_cunsint64ary2obj(hs_dims, i_count, 1, &i_count);

    return rb_ary_new3(3, ndims, dimnames, dims);
}

VALUE
hdfeos5_zainquire(VALUE mod, VALUE entrycode)
{
    hid_t i_zaid;
    char  *o_fieldlist;
    int   *o_rank;
    hid_t *o_ntype;
    long   o_nflds;
    int  i_count;
    long i_strbufsize;
    VALUE nflds;
    VALUE fieldlist;
    VALUE rank;
    VALUE ntype;

    struct HE5Za *he5za;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    i_count = zanentries_count(i_zaid, entrycode);
    i_strbufsize = zanentries_strbuf(i_zaid, entrycode);

    o_rank = ALLOCA_N(int, i_count);
    o_fieldlist = ALLOCA_N(char, (i_strbufsize + 1));

    o_nflds = HE5_ZAinquire(i_zaid, o_fieldlist, NULL, NULL);
    if (o_nflds < 0 ) return  Qfalse ;

    o_ntype = ALLOCA_N(hid_t, (o_nflds + 1)); 
    o_nflds = HE5_ZAinquire(i_zaid, o_fieldlist, o_rank, o_ntype);
    if (o_nflds < 0 ) return  Qfalse ;
    else              nflds = LONG2NUM(o_nflds);
    fieldlist = rb_str_new(o_fieldlist,i_strbufsize);
 
    i_count = (int)o_nflds;
    rank = hdfeos5_cintary2obj(o_rank, i_count, 1, &i_count);
    ntype = hdfeos5_cintary2obj(o_ntype, i_count, 1, &i_count);

    return rb_ary_new3(4, nflds, fieldlist, rank, ntype);
}

VALUE
hdfeos5_zainqdatatype(VALUE mod, VALUE fieldname, VALUE attrname, VALUE group)
{
    hid_t i_zaid;
    char *i_fieldname;
    char *i_attrname;
    int i_group;
    hid_t i_datatype = FAIL;
    H5T_class_t o_classid;
    H5T_order_t o_order;
    size_t o_size;
    herr_t o_rtn_val;
    VALUE classid;
    VALUE order;
    VALUE size;

    struct HE5Za *he5za;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    Check_Type(fieldname,T_STRING);
    SafeStringValue(fieldname);
    Check_Type(attrname,T_STRING);
    SafeStringValue(attrname);
    Check_Type(group,T_STRING);
    SafeStringValue(group);

    i_fieldname = RSTRING_PTR(fieldname);
    i_attrname = RSTRING_PTR(attrname);
    i_group = change_groupcode(RSTRING_PTR(group));

    if(strcmp(i_attrname,"NULL")==0)  i_attrname = NULL;
    o_rtn_val = HE5_ZAinqdatatype(i_zaid, i_fieldname, i_attrname, i_group, &i_datatype, &o_classid, &o_order, &o_size);
    if(o_rtn_val == FAIL) return Qfalse;
    classid = INT2NUM(o_classid);
    order = INT2NUM(o_order);
    size = INT2NUM(o_size);

    return rb_ary_new3(3, classid, order, size);
}

VALUE
hdfeos5_zachunkinfo(VALUE mod, VALUE fldname)
{
    hid_t i_zaid;
    char *i_fldname;
    int o_chunk_rank;
    unsigned long long *o_chunk_dim;
    herr_t o_rtn_val;
    VALUE chunk_rank;
    VALUE chunk_dims;
    struct HE5Za *he5za;

    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;
    Check_Type(fldname,T_STRING);
    SafeStringValue(fldname);
    i_fldname = RSTRING_PTR(fldname);

    o_rtn_val = HE5_ZAchunkinfo(i_zaid, i_fldname, &o_chunk_rank, NULL);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    o_chunk_dim = ALLOCA_N(unsigned long long, (o_chunk_rank + 1));

    o_rtn_val = HE5_ZAchunkinfo(i_zaid, i_fldname, &o_chunk_rank, o_chunk_dim);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    chunk_rank = INT2NUM(o_chunk_rank);
    chunk_dims = hdfeos5_cunsint64ary2obj(o_chunk_dim, o_chunk_rank, 1, &o_chunk_rank);

    return rb_ary_new3(2, chunk_rank, chunk_dims);
}

VALUE
hdfeos5_zanentries(VALUE mod, VALUE entrycode)
{
    hid_t i_zaid;
    int i_entrycode;
    long o_strbufsize;
    long o_count;
    VALUE count;
    VALUE strbufsize;

    struct HE5Za *he5za;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    Check_Type(entrycode,T_STRING);
    SafeStringValue(entrycode);
    i_entrycode = change_entrycode(RSTRING_PTR(entrycode));

    o_count = HE5_ZAnentries(i_zaid, i_entrycode, &o_strbufsize);
    if (o_count < 0 ) return  Qfalse ;
    else              count = LONG2NUM(o_count);
    strbufsize = LONG2NUM(o_strbufsize);

    return rb_ary_new3(2, count, strbufsize);
}

VALUE
hdfeos5_zainqza(VALUE mod)
{
    char *i_filename;
    char *o_zalist;
    long o_strbufsize;
    long o_nZA;
    VALUE nZA;
    VALUE zalist;
    VALUE strbufsize;

    struct HE5 *he5file;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5, he5file);
    i_filename=he5file->name;

    o_nZA = HE5_ZAinqza(i_filename, NULL, &o_strbufsize);
    if (o_nZA <= 0 ) return  Qfalse ;

    o_zalist = ALLOCA_N(char, (o_strbufsize + 1));
    o_nZA = HE5_ZAinqza(i_filename, o_zalist, &o_strbufsize);
    if (o_nZA <= 0 ) return  Qfalse ;
    else               nZA = LONG2NUM(o_nZA);
    zalist = rb_str_new(o_zalist,o_strbufsize);
    strbufsize = LONG2NUM(o_strbufsize);

    return rb_ary_new3(3, nZA, zalist, strbufsize);
}

VALUE
hdfeos5_zawrite(VALUE mod, VALUE start, VALUE stride, VALUE count, VALUE data, VALUE ntype)
{
    char *chk_ntype;
    Check_Type(ntype,T_STRING);
    SafeStringValue(ntype);
    chk_ntype = RSTRING_PTR(ntype);

    switch (check_numbertype(chk_ntype)){
    case  HE5T_NATIVE_CHAR:
    case  HE5T_NATIVE_SCHAR:
    case  HE5T_NATIVE_UCHAR:
    case  HE5T_CHARSTRING:
        return hdfeos5_zawrite_char(mod,  start,  stride,  count,  data);
	break;

    case  HE5T_NATIVE_INT8:
    case  HE5T_NATIVE_UINT8:
        return hdfeos5_zawrite_char(mod,  start,  stride,  count,  data);
	break;

    case  HE5T_NATIVE_SHORT:
    case  HE5T_NATIVE_USHORT:
    case  HE5T_NATIVE_INT16:
    case  HE5T_NATIVE_UINT16:
        return hdfeos5_zawrite_short(mod,  start,  stride,  count,  data);
	break;

    case  HE5T_NATIVE_INT:
    case  HE5T_NATIVE_UINT:
    case  HE5T_NATIVE_INT32:
    case  HE5T_NATIVE_UINT32:
        return hdfeos5_zawrite_int(mod,  start,  stride,  count,  data);
	break;

    case  HE5T_NATIVE_LONG:
        return hdfeos5_zawrite_long(mod,  start,  stride,  count,  data);
	break;

    case  HE5T_NATIVE_FLOAT:
        return hdfeos5_zawrite_float(mod,  start,  stride,  count,  data);
	break;

    case  HE5T_NATIVE_DOUBLE:
        return hdfeos5_zawrite_double(mod,  start,  stride,  count,  data);
	break;
    default:
	rb_raise(rb_eHE5Error, "not match data type [%s:%d]",__FILE__,__LINE__);
    }
}

VALUE
hdfeos5_zaread(VALUE mod, VALUE start, VALUE stride, VALUE edge, VALUE ntype)
{
    char *chk_ntype;
    Check_Type(ntype,T_STRING);
    SafeStringValue(ntype);
    chk_ntype = RSTRING_PTR(ntype);

    switch (check_numbertype(chk_ntype)){
    case  HE5T_NATIVE_CHAR:
    case  HE5T_NATIVE_SCHAR:
    case  HE5T_NATIVE_UCHAR:
    case  HE5T_CHARSTRING:
        return hdfeos5_zaread_char(mod,  start,  stride,  edge);
	break;

    case  HE5T_NATIVE_INT8:
    case  HE5T_NATIVE_UINT8:
        return hdfeos5_zaread_char(mod,  start,  stride,  edge);
	break;

    case  HE5T_NATIVE_SHORT:
    case  HE5T_NATIVE_USHORT:
    case  HE5T_NATIVE_INT16:
    case  HE5T_NATIVE_UINT16:
        return hdfeos5_zaread_short(mod,  start,  stride,  edge);
	break;

    case  HE5T_NATIVE_INT:
    case  HE5T_NATIVE_UINT:
    case  HE5T_NATIVE_INT32:
    case  HE5T_NATIVE_UINT32:
        return hdfeos5_zaread_int(mod,  start,  stride,  edge);
	break;

    case  HE5T_NATIVE_LONG:
        return hdfeos5_zaread_long(mod,  start,  stride,  edge);
	break;

    case  HE5T_NATIVE_FLOAT:
        return hdfeos5_zaread_float(mod,  start,  stride,  edge);
	break;

    case  HE5T_NATIVE_DOUBLE:
        return hdfeos5_zaread_double(mod,  start,  stride,  edge);
	break;
    default:
	rb_raise(rb_eHE5Error, "not match data type [%s:%d]",__FILE__,__LINE__);
    }
}

VALUE
hdfeos5_zafldsrch(VALUE mod)
{
    hid_t i_zaid;
    char *i_fieldname;
    hid_t o_fieldid;
    int o_rank;
    unsigned long long *o_dims;
    hid_t o_typeid;
    int o_fldgroup;
    VALUE fldgroup;
    VALUE fieldid;
    VALUE rank;
    VALUE dims;
    VALUE type_id;

    struct HE5ZaField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5ZaField, he5field);
    i_zaid=he5field->zaid;
    i_fieldname=he5field->name;

    o_fldgroup = HE5_ZAfldsrch(i_zaid, i_fieldname, &o_fieldid, &o_rank, NULL, &o_typeid);
    if(o_fldgroup == -1) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);

    o_dims = ALLOCA_N(unsigned long long, (o_rank + 1));
    o_fldgroup = HE5_ZAfldsrch(i_zaid, i_fieldname, &o_fieldid, &o_rank, o_dims, &o_typeid);
    if(o_fldgroup == -1) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    fldgroup = INT2NUM(o_fldgroup);
    fieldid = INT2NUM(o_fieldid);
    rank    = INT2NUM(o_rank);
    dims    = hdfeos5_cunsint64ary2obj(o_dims, o_rank, 1, &o_rank);
    type_id = INT2NUM(o_typeid);

    return rb_ary_new3(5, fldgroup, fieldid, rank, dims, type_id);
}

VALUE
hdfeos5_zadetach(VALUE mod)
{
    hid_t i_zaid;
    herr_t o_rtn_val;
    VALUE rtn_val;

    struct HE5Za *he5za;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    o_rtn_val = HE5_ZAdetach(i_zaid);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    return(rtn_val);
}

VALUE
hdfeos5_zasetfillvalue(VALUE mod, VALUE fieldname,VALUE numbertype, VALUE fillval)
{
    hid_t i_zaid;
    char *i_fieldname;
    hid_t i_numbertype;
    void *i_fillval;
    herr_t o_rtn_val;
    VALUE rtn_val;

    struct HE5Za *he5za;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    Check_Type(fieldname,T_STRING);
    SafeStringValue(fieldname);
    Check_Type(numbertype,T_STRING);
    SafeStringValue(numbertype);
    i_fieldname = RSTRING_PTR(fieldname);
    i_numbertype = change_numbertype(RSTRING_PTR(numbertype));

    if (TYPE(fillval) == T_FLOAT) {
      fillval = rb_Array(fillval);
      i_fillval = hdfeos5_obj2cfloatary(fillval);
    }
    if (TYPE(fillval) == T_STRING) {
      Check_Type(fillval,T_STRING);
      SafeStringValue(fillval);
      i_fillval = RSTRING_PTR(fillval);
    }

    i_fillval = (void*)malloc(HE5_BLKSIZE);
    o_rtn_val = HE5_ZAsetfillvalue(i_zaid, i_fieldname, i_numbertype, i_fillval);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    hdfeos5_freecfloatary(i_fillval);
    return(rtn_val);
}

VALUE
hdfeos5_zagetfillvalue(VALUE mod,VALUE fieldname)
{
    hid_t i_zaid;
    char *i_fieldname;
    void *o_fillval;
    herr_t o_rtn_val;
    VALUE fillval;

    struct HE5Za *he5za;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    Check_Type(fieldname,T_STRING);
    SafeStringValue(fieldname);
    i_fieldname = RSTRING_PTR(fieldname);

    o_fillval = (void*)malloc(HE5_BLKSIZE);
    o_rtn_val = HE5_ZAgetfillvalue(i_zaid, i_fieldname, o_fillval);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    fillval = rb_str_new2(o_fillval);

    return(fillval);
}

VALUE
hdfeos5_zawritegrpattr(VALUE mod, VALUE attrname, VALUE numbertype, VALUE count, VALUE datbuf)
{
    hid_t i_zaid;
    char *i_attrname;
    hid_t i_numbertype;
    hid_t i_numbertypechk;
    unsigned long long *i_count;
    void *i_datbuf;
    herr_t o_rtn_val;
    VALUE rtn_val;

    struct HE5Za *he5za;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    Check_Type(attrname,T_STRING);
    SafeStringValue(attrname);
    Check_Type(numbertype,T_STRING);
    SafeStringValue(numbertype);
    count = rb_Array(count);

    i_attrname = RSTRING_PTR(attrname);
    i_numbertype    = change_numbertype(RSTRING_PTR(numbertype));
    i_numbertypechk = check_numbertype(RSTRING_PTR(numbertype));
    i_count = hdfeos5_obj2cunsint64ary(count);

    HE5Wrap_store_NArray1D_or_str(i_numbertypechk, datbuf, &i_datbuf); 
    o_rtn_val = HE5_ZAwritegrpattr(i_zaid, i_attrname, i_numbertype, i_count, i_datbuf);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    hdfeos5_freecunsint64ary(i_count);
    return(rtn_val);
}

VALUE
hdfeos5_za_get_grpatt(VALUE mod, VALUE attrname)
{
    VALUE result;
    hid_t i_zaid;
    char *i_attrname;
    hid_t o_ntype;
    void *o_datbuf;
    unsigned long long o_count;
    herr_t o_rtn_val;

    struct HE5Za *he5za;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    Check_Type(attrname,T_STRING);
    SafeStringValue(attrname);
    i_attrname = RSTRING_PTR(attrname);

    o_rtn_val = HE5_ZAgrpattrinfo(i_zaid, i_attrname, &o_ntype, &o_count);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    HE5Wrap_make_NArray1D_or_str(o_ntype, o_count, &result, &o_datbuf);
    o_rtn_val = HE5_ZAreadgrpattr(i_zaid, i_attrname, o_datbuf);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    return result;
}

VALUE
hdfeos5_zainqgrpattrs(VALUE mod)
{
    hid_t i_zaid;
    char *o_attrname;
    long o_strbufsize;
    long o_nattr;
    VALUE nattr;
    VALUE attrname;
    VALUE strbufsize;

    struct HE5Za *he5za;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    o_nattr = HE5_ZAinqgrpattrs(i_zaid, NULL, &o_strbufsize);
    if(o_nattr < 0 ) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    o_attrname = ALLOCA_N(char, (o_strbufsize + 1));

    o_nattr = HE5_ZAinqgrpattrs(i_zaid, o_attrname, &o_strbufsize);
    if(o_nattr < 0 ) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    nattr = LONG2NUM(o_nattr);
    attrname = rb_str_new(o_attrname,o_strbufsize);
    strbufsize = INT2NUM(o_strbufsize);
    return rb_ary_new3(3, nattr, attrname, strbufsize);
}

VALUE
hdfeos5_zawritelocattr(VALUE mod, VALUE attrname, VALUE numbertype, VALUE count, VALUE datbuf)
{
    hid_t i_zaid;
    char *i_fieldname;
    char *i_attrname;
    hid_t i_numbertype;
    hid_t i_numbertypechk;
    unsigned long long *i_count;
    void *i_datbuf;
    herr_t o_rtn_val;
    VALUE rtn_val;

    struct HE5ZaField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5ZaField, he5field);
    i_fieldname=he5field->name;
    i_zaid=he5field->zaid;

    Check_Type(attrname,T_STRING);
    SafeStringValue(attrname);
    Check_Type(numbertype,T_STRING);
    SafeStringValue(numbertype);
    count = rb_Array(count);

    i_attrname = RSTRING_PTR(attrname);
    i_numbertype    = change_numbertype(RSTRING_PTR(numbertype));
    i_numbertypechk = check_numbertype(RSTRING_PTR(numbertype));
    i_count = hdfeos5_obj2cunsint64ary(count);
    i_datbuf = hdfeos5_obj2cfloatary(datbuf);

    HE5Wrap_store_NArray1D_or_str(i_numbertypechk, datbuf, &i_datbuf); 
    o_rtn_val = HE5_ZAwritelocattr(i_zaid, i_fieldname, i_attrname, i_numbertype, i_count, i_datbuf);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    hdfeos5_freecintary((int*)i_count);
    return rtn_val;
}

VALUE
hdfeos5_zafield_get_att(VALUE mod,VALUE  attrname)
{
    VALUE result;
    hid_t i_zaid;
    char *i_fieldname;
    char *i_attrname;
    void *o_datbuf;
    herr_t o_rtn_val;
    hid_t  o_ntype;
    unsigned long long o_count;

    struct HE5ZaField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5ZaField, he5field);
    i_fieldname=he5field->name;
    i_zaid=he5field->zaid;
    Check_Type(attrname,T_STRING);
    SafeStringValue(attrname);
    i_attrname = RSTRING_PTR(attrname);

    o_rtn_val = HE5_ZAlocattrinfo(i_zaid, i_fieldname, i_attrname, 
				  &o_ntype, &o_count);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",
				   __FILE__,__LINE__);

    HE5Wrap_make_NArray1D_or_str(o_ntype, o_count, &result, &o_datbuf);
    o_rtn_val = HE5_ZAreadlocattr(i_zaid, i_fieldname,i_attrname, o_datbuf);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",
				   __FILE__,__LINE__);
    return result;
}

VALUE
hdfeos5_zainqlocattrs(VALUE mod)
{
    hid_t i_zaid;
    char *i_fieldname;
    char *o_attrnames;
    long o_strbufsize;
    long o_nattr;
    VALUE nattr;
    VALUE attrname;
    VALUE strbufsize;

    struct HE5ZaField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5ZaField, he5field);
    i_fieldname=he5field->name;
    i_zaid=he5field->zaid;

    o_nattr = HE5_ZAinqlocattrs(i_zaid, i_fieldname, NULL, &o_strbufsize);
    if(o_nattr < 0 ) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
 
    o_attrnames = ALLOCA_N(char, (o_strbufsize + 1));
    o_nattr = HE5_ZAinqlocattrs(i_zaid, i_fieldname, o_attrnames, &o_strbufsize);
    if(o_nattr < 0 ) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    nattr = LONG2NUM(o_nattr);
    attrname = rb_str_new(o_attrnames,o_strbufsize);
    strbufsize = LONG2NUM(o_strbufsize);
    return rb_ary_new3(3, nattr, attrname, strbufsize);
}

VALUE
hdfeos5_zasetalias(VALUE mod, VALUE fieldname)
{
    hid_t i_zaid;
    char *i_fieldname;
    char o_aliaslist[maxcharsize]="";
    herr_t o_rtn_val;
    VALUE aliaslist;

    struct HE5Za *he5za;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    Check_Type(fieldname,T_STRING);
    SafeStringValue(fieldname);
    i_fieldname = RSTRING_PTR(fieldname);

    o_rtn_val = HE5_ZAsetalias(i_zaid, i_fieldname, o_aliaslist);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    aliaslist = rb_str_new2(o_aliaslist);
    return aliaslist;
}

VALUE
hdfeos5_zadropalias(VALUE mod, VALUE fldgroup, VALUE aliasname)
{
    hid_t i_zaid;
    int i_fldgroup;
    char *i_aliasname;
    herr_t o_rtn_val;
    VALUE rtn_val;

    struct HE5Za *he5za;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    Check_Type(fldgroup,T_STRING);
    SafeStringValue(fldgroup);
    Check_Type(aliasname,T_STRING);
    SafeStringValue(aliasname);

    i_fldgroup = change_groupcode(RSTRING_PTR(fldgroup));
    i_aliasname = RSTRING_PTR(aliasname);

    o_rtn_val = HE5_ZAdropalias(i_zaid, i_fldgroup, i_aliasname);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    return rtn_val;
}

VALUE
hdfeos5_zainqfldalias(VALUE mod)
{
    hid_t i_zaid;
    char o_fldalias[maxcharsize]="";
    long o_strbufsize;
    long o_rtn_val;
    VALUE rtn_val;
    VALUE fldalias;
    VALUE strbufsize;

    struct HE5Za *he5za;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    o_rtn_val = HE5_ZAinqfldalias(i_zaid, o_fldalias, &o_strbufsize);
    if(o_rtn_val < 0 ) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    rtn_val = LONG2NUM(o_rtn_val);
    fldalias = rb_str_new2(o_fldalias);
    strbufsize = INT2NUM(o_strbufsize);
    return rb_ary_new3(3, rtn_val, fldalias, strbufsize);
}

VALUE
hdfeos5_zaaliasinfo(VALUE mod, VALUE fldgroup, VALUE aliasname)
{
    hid_t i_zaid;
    int i_fldgroup;
    char *i_aliasname;
    int o_length;
    char o_buffer[maxcharsize]="";
    long o_rtn_val;
    VALUE rtn_val;
    VALUE length;
    VALUE buffer;

    struct HE5Za *he5za;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    Check_Type(fldgroup,T_STRING);
    SafeStringValue(fldgroup);
    Check_Type(aliasname,T_STRING);
    SafeStringValue(aliasname);

    i_fldgroup = change_groupcode(RSTRING_PTR(fldgroup));
    i_aliasname = RSTRING_PTR(aliasname);

    o_rtn_val = HE5_ZAaliasinfo(i_zaid, i_fldgroup, i_aliasname, &o_length, o_buffer);
    if(o_rtn_val == FAIL) return Qfalse;
    rtn_val = LONG2NUM(o_rtn_val);
    length = INT2NUM(o_length);
    buffer = rb_str_new2(o_buffer);
    return rb_ary_new3(3, rtn_val, length, buffer);
}

VALUE
hdfeos5_zagetaliaslist(VALUE mod, VALUE fldgroup)
{
    hid_t i_zaid;
    int i_fldgroup;
    char o_aliaslist[maxcharsize]="";
    long o_strbufsize;
    long o_rtn_val;
    VALUE rtn_val;
    VALUE aliaslist;
    VALUE strbufsize;

    struct HE5Za *he5za;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    Check_Type(fldgroup,T_STRING);
    SafeStringValue(fldgroup);
    i_fldgroup = change_groupcode(RSTRING_PTR(fldgroup));

    o_rtn_val = HE5_ZAgetaliaslist(i_zaid, i_fldgroup, o_aliaslist, &o_strbufsize);
    if(o_rtn_val < 0 ) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    rtn_val = LONG2NUM(o_rtn_val);
    aliaslist = rb_str_new2(o_aliaslist);
    strbufsize = INT2NUM(o_strbufsize);
    return rb_ary_new3(3, rtn_val, aliaslist, strbufsize);
}

VALUE
hdfeos5_zafldrename(VALUE mod, VALUE oldfieldname,VALUE newfieldname)
{
    hid_t i_zaid;
    char *i_oldfieldname;
    char *i_newfieldname;
    herr_t o_rtn_val;

    struct HE5Za *he5za;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    Check_Type(oldfieldname,T_STRING);
    SafeStringValue(oldfieldname);
    i_oldfieldname = RSTRING_PTR(oldfieldname);
    Check_Type(newfieldname,T_STRING);
    SafeStringValue(newfieldname);
    i_newfieldname = RSTRING_PTR(newfieldname);


    o_rtn_val = HE5_ZAfldrename(i_zaid, i_oldfieldname, i_newfieldname);
    if(o_rtn_val == FAIL) return Qfalse;
    return Qtrue;

}

VALUE
hdfeos5_zamountexternal(VALUE mod, VALUE fldgroup, VALUE extfilename)
{
    hid_t i_zaid;
    int i_fldgroup;
    char *i_extfilename;
    hid_t o_rtn_val;
    VALUE rtn_val;

    struct HE5Za *he5za;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    Check_Type(fldgroup,T_STRING);
    SafeStringValue(fldgroup);
    Check_Type(extfilename,T_STRING);
    SafeStringValue(extfilename);

    i_fldgroup = change_groupcode(RSTRING_PTR(fldgroup));
    i_extfilename = RSTRING_PTR(extfilename);

    o_rtn_val = HE5_ZAmountexternal(i_zaid, i_fldgroup, i_extfilename);
    rtn_val = INT2NUM(o_rtn_val);
    return rtn_val;
}

VALUE
hdfeos5_zaunmount(VALUE mod, VALUE fldgroup, VALUE fileid)
{
    hid_t i_zaid;
    int i_fldgroup;
    hid_t i_fileid;
    herr_t o_rtn_val;
    VALUE rtn_val;

    struct HE5Za *he5za;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    Check_Type(fldgroup,T_STRING);
    SafeStringValue(fldgroup);
    Check_Type(fileid,T_FIXNUM);

    i_fldgroup = change_groupcode(RSTRING_PTR(fldgroup));
    i_fileid = NUM2INT(fileid);

    o_rtn_val = HE5_ZAunmount(i_zaid, i_fldgroup, i_fileid);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    return rtn_val;
}

VALUE
hdfeos5_zareadexternal(VALUE mod, VALUE fldgroup, VALUE fieldname)
{
    hid_t i_zaid;
    int i_fldgroup;
    char *i_fieldname;
    void *o_buffer;
    herr_t o_rtn_val;
    VALUE buffer;

    struct HE5Za *he5za;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    Check_Type(fldgroup,T_STRING);
    SafeStringValue(fldgroup);
    Check_Type(fieldname,T_STRING);
    SafeStringValue(fieldname);
    i_fldgroup = change_groupcode(RSTRING_PTR(fldgroup));
    i_fieldname = RSTRING_PTR(fieldname);

    o_buffer = (void*)malloc(HE5_BLKSIZE);
    o_rtn_val = HE5_ZAreadexternal(i_zaid, i_fldgroup, i_fieldname, o_buffer);
    if(o_rtn_val == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);
    buffer = rb_str_new2(o_buffer);
    return buffer;
}

VALUE
hdfeos5_zasetextdata(VALUE mod, VALUE filelist, VALUE offset, VALUE size)
{
    hid_t i_zaid;
    char  *i_filelist;
    off_t *i_offset;
    unsigned long long *i_size;
    herr_t o_rtn_val;
    VALUE rtn_val;

    struct HE5Za *he5za;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    Check_Type(filelist,T_STRING);
    SafeStringValue(filelist);
    if ((TYPE(offset) == T_BIGNUM) || (TYPE(offset) == T_FIXNUM)) {
      offset = rb_Array(offset);
    }
    if ((TYPE(size) == T_BIGNUM) || (TYPE(size) == T_FIXNUM)) {
      size = rb_Array(size);
    }
    i_filelist = RSTRING_PTR(filelist);
    i_offset = hdfeos5_obj2clongary(offset);
    i_size = hdfeos5_obj2cunsint64ary(size);

    o_rtn_val = HE5_ZAsetextdata(i_zaid, i_filelist, i_offset, i_size);
    rtn_val = (o_rtn_val == FAIL) ? Qfalse : Qtrue;
    hdfeos5_freeclongary(i_offset);
    hdfeos5_freecunsint64ary(i_size);
    return rtn_val;
}

VALUE
hdfeos5_zagetextdata(VALUE mod, VALUE fieldname)
{
    hid_t i_zaid;
    char *i_fieldname;
    size_t o_namelength=0;
    char  o_filelist[maxcharsize];
    off_t o_offset[maxcharsize];
    unsigned long long o_size[maxcharsize];
    int o_rtn_val;
    VALUE rtn_val;
    VALUE namelength;
    VALUE filelist;
    VALUE offset;
    VALUE size;

    struct HE5Za *he5za;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    Check_Type(fieldname,T_STRING);
    SafeStringValue(fieldname);

    i_fieldname = RSTRING_PTR(fieldname);

    o_rtn_val = HE5_ZAgetextdata(i_zaid, i_fieldname, o_namelength, o_filelist, o_offset, o_size);
    rtn_val = INT2NUM(o_rtn_val);
    
    namelength = hdfeos5_cintary2obj((int*)o_namelength,o_rtn_val,1,&o_rtn_val);
    filelist = hdfeos5_ccharary2obj(o_filelist,o_rtn_val,o_rtn_val);
    offset = hdfeos5_clongary2obj(o_offset,o_rtn_val,1,&o_rtn_val);
    size = hdfeos5_cunsint64ary2obj(o_size,o_rtn_val,1,&o_rtn_val);

    return rb_ary_new3(5,rtn_val, namelength, filelist, offset, size);
}

VALUE
hdfeos5_zachkza(VALUE mod)
{
    char *i_filename;
    long o_strbufsize;
    long o_rtn_val;

    struct HE5 *he5file;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5, he5file);
    i_filename=he5file->name;

    o_rtn_val = HE5_ZAinqza(i_filename, NULL, &o_strbufsize);
    if( o_rtn_val <= 0) return Qfalse;
    return Qtrue;
}

VALUE
hdfeos5_zachkzaname(VALUE mod)
{
    char *i_filename;
    char *o_zalist;
    long o_strbufsize;
    long o_rtn_val;
    VALUE rstr;

    struct HE5 *he5file;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5, he5file);
    i_filename=he5file->name;

    o_rtn_val = HE5_ZAinqza(i_filename, NULL, &o_strbufsize);
    if( o_rtn_val <= 0) return Qfalse;
    o_zalist = ALLOCA_N(char, (o_strbufsize + 1));

    o_rtn_val = HE5_ZAinqza(i_filename, o_zalist, &o_strbufsize);
    if( o_rtn_val <= 0) return Qfalse;
    rstr = rb_str_new(o_zalist, o_strbufsize);
    return rstr;
}

VALUE
hdfeos5_zasetfield(VALUE mod,VALUE fieldname)
{
    int i_zaid;
    char *i_fieldname;
    struct HE5Za *he5za;
    struct HE5ZaField *he5field;

    rb_secure(4);
    Data_Get_Struct(mod, struct HE5Za, he5za);
    i_zaid=he5za->zaid;

    Check_Type(fieldname,T_STRING);
    SafeStringValue(fieldname);
    i_fieldname = RSTRING_PTR(fieldname);
    
    he5field = HE5ZaField_init(i_fieldname, i_zaid, mod);
    return(Data_Wrap_Struct(cHE5ZaField, he5zafield_mark_obj, HE5ZaField_free, he5field));
}

VALUE
hdfeos5_zagetfield(VALUE mod)
{
    char *i_fieldname;
    struct HE5ZaField *he5field;

    rb_secure(4);
    Data_Get_Struct(mod, struct HE5ZaField, he5field);
    i_fieldname=he5field->name;

    return rb_str_new2(i_fieldname);
}

VALUE 
hdfeos5_za_whether_in_define_mode(VALUE za)
{
    int fid;
    hid_t HDFfid = FAIL;
    hid_t gid = FAIL;
    uintn access = 0;
    int status;
    struct HE5Za *he5za;
  
    Data_Get_Struct(za, struct HE5Za, he5za);
    fid=he5za->fid;

    status = HE5_EHchkfid(fid, "HE5_ZAcreate", &HDFfid,  &gid, &access);
    if(status != FAIL){
      return Qtrue;
    }else {
      status = HE5_EHchkfid(fid, "HE5_ZAattach", &HDFfid,  &gid, &access);
      if(status != FAIL){
        return Qtrue;
      } else {
        return Qnil;
      }
    }
}

VALUE
hdfeos5_za_path(VALUE za)
{
    char *i_name;
    struct HE5Za *he5za;
  
    Data_Get_Struct(za, struct HE5Za, he5za);

    i_name=he5za->name;
    return rb_str_new2(i_name);
}

VALUE
hdfeos5_za_inqname(VALUE za)
{
    char *i_name;
    struct HE5Za *he5za;
  
    Data_Get_Struct(za, struct HE5Za, he5za);

    i_name=he5za->name;
    return rb_str_new2(i_name);
}

VALUE
hdfeos5_za_file(VALUE za)
{
    struct HE5Za *he5za;
  
    rb_secure(4);
    Data_Get_Struct(za, struct HE5Za, he5za);
    return(he5za->file);
}

VALUE
hdfeos5_zafld_za(VALUE field)
{
    struct HE5ZaField *he5field;

    rb_secure(4);
    Data_Get_Struct(field, struct HE5ZaField, he5field);
    return(he5field->za);
}

VALUE
hdfeos5_zafld_inqname(VALUE field)
{
    char *i_name;
    struct HE5ZaField *he5field;

    rb_secure(4);
    Data_Get_Struct(field, struct HE5ZaField, he5field);

    i_name=he5field->name;
    return rb_str_new2(i_name);
}

VALUE
hdfeos5_zawrite_char(VALUE mod, VALUE start, VALUE stride, VALUE count, VALUE data)
{
    hid_t i_zaid;
    char *i_fldname;
    signed long long *c_start;
    unsigned long long *c_stride;
    unsigned long long *c_count;

    int i_rank;
    hid_t i_ntype = FAIL;
    unsigned long long hs_dims[maxcharsize];
    char o_dimlist[maxcharsize];
    int  len,i;
    int  c_count_all=1;
    long l_start, l_count;
    int  *shape;    /* NArray uses int instead of size_t */
    herr_t status;
    unsigned char  scalar,*i_data;

    struct HE5ZaField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5ZaField, he5field);
    i_fldname=he5field->name;
    i_zaid=he5field->zaid;

    status = HE5_ZAinfo(i_zaid, i_fldname, &i_rank, hs_dims, &i_ntype, o_dimlist, NULL);

    Check_Type(start,T_ARRAY);
    if(RARRAY_LEN(start) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'start' is too short [%s:%d]",__FILE__,__LINE__);
    }
    c_start=ALLOCA_N(signed long long,i_rank);
    for(i=0; i<i_rank; i++){
      l_start=NUM2INT(RARRAY_PTR(start)[i]);    
      if(l_start < 0) {
	l_start += hs_dims[i];
      }
      c_start[i]=l_start;
    }
    c_stride=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(stride)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
	  c_stride[i]=1;
      }
      break;
    default:
      Check_Type(stride,T_ARRAY);
      if(RARRAY_LEN(stride) < i_rank) {
	  rb_raise(rb_eHE5Error, "Length of 'stride' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
	c_stride[i]=NUM2INT(RARRAY_PTR(stride)[i]);
	if(c_stride[i]==0) {
	  rb_raise(rb_eHE5Error, "stride cannot be zero [%s:%d]",__FILE__,__LINE__);
	}
      }
    }

    Array_to_Cbyte_len_shape(data,i_data,len,shape);
    c_count=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(count)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
        c_count[i]=shape[i];
      }
      c_count_all=len;
      break;
    default:
      Check_Type(count,T_ARRAY);
      if(RARRAY_LEN(count) < i_rank) {
        rb_raise(rb_eHE5Error, "Length of 'end' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
        l_count= NUM2INT(RARRAY_PTR(count)[i]);
        if(l_count < 0) {
	  l_count +=hs_dims[i];
        }
        c_count[i]=(l_count-c_start[i])/c_stride[i]+1;
        c_count_all=c_count[i]*c_count_all;
      }
      if(len == 1 && len != c_count_all){
	scalar = *i_data;
	i_data = ALLOCA_N(unsigned char,c_count_all);
	for(i=0;i<c_count_all;i++){i_data[i]=scalar;}
      } else if(len != c_count_all) {
          rb_raise(rb_eHE5Error, "lengh of the array does not agree with that of the subset [%s:%d]",__FILE__,__LINE__); 
      }
    }

    status = HE5_ZAwrite(i_zaid, i_fldname, c_start, c_stride, c_count, i_data);
    if(status != FAIL) return status;
    return Qnil;
}

VALUE
hdfeos5_zawrite_short(VALUE mod, VALUE start, VALUE stride, VALUE count, VALUE data)
{
    hid_t i_zaid;
    char *i_fldname;
    signed long long *c_start;
    unsigned long long *c_stride;
    unsigned long long *c_count;

    int i_rank;
    hid_t i_ntype = FAIL;
    unsigned long long hs_dims[maxcharsize];
    char o_dimlist[maxcharsize];
    int  len,i;
    int  c_count_all=1;
    long l_start, l_count;
    int  *shape;    /* NArray uses int instead of size_t */
    herr_t status;
    short scalar,*i_data;

    struct HE5ZaField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5ZaField, he5field);
    i_fldname=he5field->name;
    i_zaid=he5field->zaid;

    status = HE5_ZAinfo(i_zaid, i_fldname, &i_rank, hs_dims, &i_ntype, o_dimlist, NULL);

    Check_Type(start,T_ARRAY);
    if(RARRAY_LEN(start) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'start' is too short [%s:%d]",__FILE__,__LINE__);
    }
    c_start=ALLOCA_N(signed long long,i_rank);
    for(i=0; i<i_rank; i++){
      l_start=NUM2INT(RARRAY_PTR(start)[i]);    
      if(l_start < 0) {
	l_start += hs_dims[i];
      }
      c_start[i]=l_start;
    }
    c_stride=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(stride)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
	  c_stride[i]=1;
      }
      break;
    default:
      Check_Type(stride,T_ARRAY);
      if(RARRAY_LEN(stride) < i_rank) {
	  rb_raise(rb_eHE5Error, "Length of 'stride' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
	c_stride[i]=NUM2INT(RARRAY_PTR(stride)[i]);
	if(c_stride[i]==0) {
	  rb_raise(rb_eHE5Error, "stride cannot be zero [%s:%d]",__FILE__,__LINE__);
	}
      }
    }

    Array_to_Cshort_len_shape(data,i_data,len,shape);
    c_count=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(count)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
        c_count[i]=shape[i];
      }
      c_count_all=len;
      break;
    default:
      Check_Type(count,T_ARRAY);
      if(RARRAY_LEN(count) < i_rank) {
        rb_raise(rb_eHE5Error, "Length of 'end' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
        l_count= NUM2INT(RARRAY_PTR(count)[i]);
        if(l_count < 0) {
	  l_count +=hs_dims[i];
        }
        c_count[i]=(l_count-c_start[i])/c_stride[i]+1;
        c_count_all=c_count[i]*c_count_all;
      }
      if(len == 1 && len != c_count_all){
	scalar = *i_data;
	i_data = ALLOCA_N(short,c_count_all);
	for(i=0;i<c_count_all;i++){i_data[i]=scalar;}
      } else if(len != c_count_all) {
          rb_raise(rb_eHE5Error, "lengh of the array does not agree with that of the subset [%s:%d]",__FILE__,__LINE__); 
      }
    }

    status = HE5_ZAwrite(i_zaid, i_fldname, c_start, c_stride, c_count, i_data);
    if(status != FAIL) return status;
    return Qnil;
}

VALUE
hdfeos5_zawrite_int(VALUE mod, VALUE start, VALUE stride, VALUE count, VALUE data)
{
    hid_t i_zaid;
    char *i_fldname;
    signed long long *c_start;
    unsigned long long *c_stride;
    unsigned long long *c_count;

    int i_rank;
    hid_t i_ntype = FAIL;
    unsigned long long hs_dims[maxcharsize];
    char o_dimlist[maxcharsize];
    int  len,i;
    int  c_count_all=1;
    long l_start, l_count;
    int  *shape;    /* NArray uses int instead of size_t */
    herr_t status;
    int scalar,*i_data;

    struct HE5ZaField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5ZaField, he5field);
    i_fldname=he5field->name;
    i_zaid=he5field->zaid;

    status = HE5_ZAinfo(i_zaid, i_fldname, &i_rank, hs_dims, &i_ntype, o_dimlist, NULL);

    Check_Type(start,T_ARRAY);
    if(RARRAY_LEN(start) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'start' is too short [%s:%d]",__FILE__,__LINE__);
    }
    c_start=ALLOCA_N(signed long long,i_rank);
    for(i=0; i<i_rank; i++){
      l_start=NUM2INT(RARRAY_PTR(start)[i]);    
      if(l_start < 0) {
	l_start += hs_dims[i];
      }
      c_start[i]=l_start;
    }
    c_stride=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(stride)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
	  c_stride[i]=1;
      }
      break;
    default:
      Check_Type(stride,T_ARRAY);
      if(RARRAY_LEN(stride) < i_rank) {
	  rb_raise(rb_eHE5Error, "Length of 'stride' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
	c_stride[i]=NUM2INT(RARRAY_PTR(stride)[i]);
	if(c_stride[i]==0) {
	  rb_raise(rb_eHE5Error, "stride cannot be zero [%s:%d]",__FILE__,__LINE__);
	}
      }
    }

    Array_to_Cint_len_shape(data,i_data,len,shape);
    c_count=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(count)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
        c_count[i]=shape[i];
      }
      c_count_all=len;
      break;
    default:
      Check_Type(count,T_ARRAY);
      if(RARRAY_LEN(count) < i_rank) {
        rb_raise(rb_eHE5Error, "Length of 'end' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
        l_count= NUM2INT(RARRAY_PTR(count)[i]);
        if(l_count < 0) {
	  l_count +=hs_dims[i];
        }
        c_count[i]=(l_count-c_start[i])/c_stride[i]+1;
        c_count_all=c_count[i]*c_count_all;
      }
      if(len == 1 && len != c_count_all){
	scalar = *i_data;
	i_data = ALLOCA_N(int,c_count_all);
	for(i=0;i<c_count_all;i++){i_data[i]=scalar;}
      } else if(len != c_count_all) {
          rb_raise(rb_eHE5Error, "lengh of the array does not agree with that of the subset [%s:%d]",__FILE__,__LINE__); 
      }
    }

    status = HE5_ZAwrite(i_zaid, i_fldname, c_start, c_stride, c_count, i_data);
    if(status != FAIL) return status;
    return Qnil;
}

VALUE
hdfeos5_zawrite_long(VALUE mod, VALUE start, VALUE stride, VALUE count, VALUE data)
{
    hid_t i_zaid;
    char *i_fldname;
    signed long long *c_start;
    unsigned long long *c_stride;
    unsigned long long *c_count;

    int i_rank;
    hid_t i_ntype = FAIL;
    unsigned long long hs_dims[maxcharsize];
    char o_dimlist[maxcharsize];
    int  len,i;
    int  c_count_all=1;
    long l_start, l_count;
    int  *shape;    /* NArray uses int instead of size_t */
    herr_t status;
    long scalar,*i_data;

    struct HE5ZaField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5ZaField, he5field);
    i_fldname=he5field->name;
    i_zaid=he5field->zaid;

    status = HE5_ZAinfo(i_zaid, i_fldname, &i_rank, hs_dims, &i_ntype, o_dimlist, NULL);

    Check_Type(start,T_ARRAY);
    if(RARRAY_LEN(start) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'start' is too short [%s:%d]",__FILE__,__LINE__);
    }
    c_start=ALLOCA_N(signed long long,i_rank);
    for(i=0; i<i_rank; i++){
      l_start=NUM2INT(RARRAY_PTR(start)[i]);
      if(l_start < 0) {
	l_start += hs_dims[i];
      }
      c_start[i]=l_start;
    }
    c_stride=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(stride)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
	  c_stride[i]=1;
      }
      break;
    default:
      Check_Type(stride,T_ARRAY);
      if(RARRAY_LEN(stride) < i_rank) {
	  rb_raise(rb_eHE5Error, "Length of 'stride' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
	c_stride[i]=NUM2INT(RARRAY_PTR(stride)[i]);
	if(c_stride[i]==0) {
	  rb_raise(rb_eHE5Error, "stride cannot be zero [%s:%d]",__FILE__,__LINE__);
	}
      }
    }

    Array_to_Clong_len_shape(data,i_data,len,shape);
    c_count=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(count)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
        c_count[i]=shape[i];
      }
      c_count_all=len;
      break;
    default:
      Check_Type(count,T_ARRAY);
      if(RARRAY_LEN(count) < i_rank) {
        rb_raise(rb_eHE5Error, "Length of 'end' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
        l_count= NUM2INT(RARRAY_PTR(count)[i]);
        if(l_count < 0) {
	  l_count +=hs_dims[i];
        }
        c_count[i]=(l_count-c_start[i])/c_stride[i]+1;
        c_count_all=c_count[i]*c_count_all;
      }
      if(len == 1 && len != c_count_all){
	scalar = *i_data;
	i_data = ALLOCA_N(long,c_count_all);
	for(i=0;i<c_count_all;i++){i_data[i]=scalar;}
      } else if(len != c_count_all) {
          rb_raise(rb_eHE5Error, "lengh of the array does not agree with that of the subset [%s:%d]",__FILE__,__LINE__); 
      }
    }

    status = HE5_ZAwrite(i_zaid, i_fldname, c_start, c_stride, c_count, i_data);
    if(status != FAIL) return status;
    return Qnil;
}

VALUE
hdfeos5_zawrite_float(VALUE mod, VALUE start, VALUE stride, VALUE count, VALUE data)
{
    hid_t i_zaid;
    char *i_fldname;
    signed long long *c_start;
    unsigned long long *c_stride;
    unsigned long long *c_count;

    int i_rank;
    hid_t i_ntype = FAIL;
    unsigned long long hs_dims[maxcharsize];
    char o_dimlist[maxcharsize];
    int  len,i;
    int  c_count_all=1;
    long l_start, l_count;
    int  *shape;    /* NArray uses int instead of size_t */
    herr_t status;
    float scalar,*i_data;

    struct HE5ZaField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5ZaField, he5field);
    i_fldname=he5field->name;
    i_zaid=he5field->zaid;

    status = HE5_ZAinfo(i_zaid, i_fldname, &i_rank, hs_dims, &i_ntype, o_dimlist, NULL);

    Check_Type(start,T_ARRAY);
    if(RARRAY_LEN(start) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'start' is too short [%s:%d]",__FILE__,__LINE__);
    }
    c_start=ALLOCA_N(signed long long,i_rank);
    for(i=0; i<i_rank; i++){
      l_start=NUM2INT(RARRAY_PTR(start)[i]);    
      if(l_start < 0) {
	l_start += hs_dims[i];
      }
      c_start[i]=l_start;
    }
    c_stride=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(stride)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
	  c_stride[i]=1;
      }
      break;
    default:
      Check_Type(stride,T_ARRAY);
      if(RARRAY_LEN(stride) < i_rank) {
	  rb_raise(rb_eHE5Error, "Length of 'stride' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
	c_stride[i]=NUM2INT(RARRAY_PTR(stride)[i]);
	if(c_stride[i]==0) {
	  rb_raise(rb_eHE5Error, "stride cannot be zero [%s:%d]",__FILE__,__LINE__);
	}
      }
    }

    Array_to_Cfloat_len_shape(data,i_data,len,shape);
    c_count=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(count)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
        c_count[i]=shape[i];
      }
      c_count_all=len;
      break;
    default:
      Check_Type(count,T_ARRAY);
      if(RARRAY_LEN(count) < i_rank) {
        rb_raise(rb_eHE5Error, "Length of 'end' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
        l_count= NUM2INT(RARRAY_PTR(count)[i]);
        if(l_count < 0) {
	  l_count +=hs_dims[i];
        }
        c_count[i]=(l_count-c_start[i])/c_stride[i]+1;
        c_count_all=c_count[i]*c_count_all;
      }
      if(len == 1 && len != c_count_all){
	scalar = *i_data;
	i_data = ALLOCA_N(float,c_count_all);
	for(i=0;i<c_count_all;i++){i_data[i]=scalar;}
      } else if(len != c_count_all) {
          rb_raise(rb_eHE5Error, "lengh of the array does not agree with that of the subset [%s:%d]",__FILE__,__LINE__); 
      }
    }

    status = HE5_ZAwrite(i_zaid, i_fldname, c_start, c_stride, c_count, i_data);
    if(status != FAIL) return status;
    return Qnil;
}

VALUE
hdfeos5_zawrite_double(VALUE mod, VALUE start, VALUE stride, VALUE count, VALUE data)
{
    hid_t i_zaid;
    char *i_fldname;
    signed long long *c_start;
    unsigned long long *c_stride;
    unsigned long long *c_count;

    int i_rank;
    hid_t i_ntype = FAIL;
    unsigned long long hs_dims[maxcharsize];
    char o_dimlist[maxcharsize];
    int  len,i;
    int  c_count_all=1;
    long l_start, l_count;
    int  *shape;    /* NArray uses int instead of size_t */
    herr_t status;
    double scalar,*i_data;

    struct HE5ZaField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5ZaField, he5field);
    i_fldname=he5field->name;
    i_zaid=he5field->zaid;

    status = HE5_ZAinfo(i_zaid, i_fldname, &i_rank, hs_dims, &i_ntype, o_dimlist, NULL);

    Check_Type(start,T_ARRAY);
    if(RARRAY_LEN(start) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'start' is too short [%s:%d]",__FILE__,__LINE__);
    }
    c_start=ALLOCA_N(signed long long,i_rank);
    for(i=0; i<i_rank; i++){
      l_start=NUM2INT(RARRAY_PTR(start)[i]);    
      if(l_start < 0) {
	l_start += hs_dims[i];
      }
      c_start[i]=l_start;
    }
    c_stride=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(stride)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
	  c_stride[i]=1;
      }
      break;
    default:
      Check_Type(stride,T_ARRAY);
      if(RARRAY_LEN(stride) < i_rank) {
	  rb_raise(rb_eHE5Error, "Length of 'stride' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
	c_stride[i]=NUM2INT(RARRAY_PTR(stride)[i]);
	if(c_stride[i]==0) {
	  rb_raise(rb_eHE5Error, "stride cannot be zero [%s:%d]",__FILE__,__LINE__);
	}
      }
    }

    Array_to_Cdouble_len_shape(data,i_data,len,shape);
    c_count=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(count)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
        c_count[i]=shape[i];
      }
      c_count_all=len;
      break;
    default:
      Check_Type(count,T_ARRAY);
      if(RARRAY_LEN(count) < i_rank) {
        rb_raise(rb_eHE5Error, "Length of 'end' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
        l_count= NUM2INT(RARRAY_PTR(count)[i]);
        if(l_count < 0) {
	  l_count +=hs_dims[i];
        }
        c_count[i]=(l_count-c_start[i])/c_stride[i]+1;
        c_count_all=c_count[i]*c_count_all;
      }
      if(len == 1 && len != c_count_all){
	scalar = *i_data;
	i_data = ALLOCA_N(double,c_count_all);
	for(i=0;i<c_count_all;i++){i_data[i]=scalar;}
      } else if(len != c_count_all) {
          rb_raise(rb_eHE5Error, "lengh of the array does not agree with that of the subset [%s:%d]",__FILE__,__LINE__); 
      }
    }

    status = HE5_ZAwrite(i_zaid, i_fldname, c_start, c_stride, c_count, i_data);
    if(status != FAIL) return status;
    return Qnil;
}

VALUE
hdfeos5_zaread_char(VALUE mod, VALUE start, VALUE stride, VALUE count)
{
    hid_t i_zaid;
    char *i_fldname;
    signed long long *c_start;
    unsigned long long *c_stride;
    unsigned long long *c_count;

    int i_rank;
    hid_t i_ntype = FAIL;
    unsigned long long hs_dims[10];
    int  i;
    long l_start, l_count;
    int  *shape;    /* NArray uses int instead of size_t */
    herr_t status;
    void *o_data;
    VALUE NArray;

    struct HE5ZaField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5ZaField, he5field);
    i_fldname=he5field->name;
    i_zaid=he5field->zaid;

    status = HE5_ZAinfo(i_zaid, i_fldname, &i_rank, hs_dims, &i_ntype, NULL, NULL);

    Check_Type(start,T_ARRAY);
    if(RARRAY_LEN(start) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'start' is too short [%s:%d]",
	       __FILE__,__LINE__);
    }
    c_start=ALLOCA_N(signed long long,i_rank);
    for(i=0; i<i_rank; i++){
      l_start=NUM2INT(RARRAY_PTR(start)[i_rank-1-i]);
      if(l_start < 0) {
	l_start += hs_dims[i];
      }
      c_start[i]=l_start;
    }
    c_stride=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(stride)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
	  c_stride[i]=1;
      }
      break;
    case T_FALSE:
      for(i=0; i<i_rank; i++){
	  c_stride[i]=1;
      }
      break;
    case T_TRUE:
      for(i=0; i<i_rank; i++){
	  c_stride[i]=1;
      }
      break;
    default:
      Check_Type(stride,T_ARRAY);
      if(RARRAY_LEN(stride) < i_rank) {
	  rb_raise(rb_eHE5Error, "Length of 'stride' is too short [%s:%d]",
		   __FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
	c_stride[i]=NUM2INT(RARRAY_PTR(stride)[i_rank-1-i]);
	if(c_stride[i]==0) {
	  rb_raise(rb_eHE5Error, "stride cannot be zero [%s:%d]",__FILE__,__LINE__);
	}
      }
    }
    c_count=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(count)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
        c_count[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    case T_TRUE:
      for(i=0; i<i_rank; i++){
        c_count[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    case T_FALSE:
      for(i=0; i<i_rank; i++){
        c_count[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    default:
      Check_Type(count,T_ARRAY);
      if(RARRAY_LEN(count) < i_rank) {
        rb_raise(rb_eHE5Error, "Length of 'end' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
        l_count= NUM2INT(RARRAY_PTR(count)[i_rank-1-i]);
        if(l_count < 0) {
	  l_count +=hs_dims[i];
        }
        c_count[i]=(l_count-c_start[i])/c_stride[i]+1;
      }
    }

    shape = ALLOCA_N(int,i_rank);
    for(i=0;i<i_rank;i++){
      shape[i_rank-1-i]=c_count[i];
    }
    Cbyte_to_NArray(NArray,i_rank,shape,o_data);
    status = HE5_ZAread(i_zaid, i_fldname, c_start, c_stride, c_count, o_data);
    if(status == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);

    OBJ_TAINT(NArray);

    return(NArray);
}

VALUE
hdfeos5_zaread_short(VALUE mod, VALUE start, VALUE stride, VALUE count)
{
    hid_t i_zaid;
    char *i_fldname;
    signed long long *c_start;
    unsigned long long *c_stride;
    unsigned long long *c_count;

    int i_rank;
    hid_t i_ntype = FAIL;
    unsigned long long hs_dims[10];
    int  i;
    long l_start, l_count;
    int  *shape;    /* NArray uses int instead of size_t */
    herr_t status;
    void *o_data;
    VALUE NArray;

    struct HE5ZaField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5ZaField, he5field);
    i_fldname=he5field->name;
    i_zaid=he5field->zaid;

    status = HE5_ZAinfo(i_zaid, i_fldname, &i_rank, hs_dims, &i_ntype, NULL, NULL);

    Check_Type(start,T_ARRAY);
    if(RARRAY_LEN(start) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'start' is too short [%s:%d]",
	       __FILE__,__LINE__);
    }
    c_start=ALLOCA_N(signed long long,i_rank);
    for(i=0; i<i_rank; i++){
      l_start=NUM2INT(RARRAY_PTR(start)[i_rank-1-i]);
      if(l_start < 0) {
	l_start += hs_dims[i];
      }
      c_start[i]=l_start;
    }
    c_stride=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(stride)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
	  c_stride[i]=1;
      }
      break;
    case T_FALSE:
      for(i=0; i<i_rank; i++){
	  c_stride[i]=1;
      }
      break;
    case T_TRUE:
      for(i=0; i<i_rank; i++){
	  c_stride[i]=1;
      }
      break;
    default:
      Check_Type(stride,T_ARRAY);
      if(RARRAY_LEN(stride) < i_rank) {
	  rb_raise(rb_eHE5Error, "Length of 'stride' is too short [%s:%d]",
		   __FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
	c_stride[i]=NUM2INT(RARRAY_PTR(stride)[i_rank-1-i]);
	if(c_stride[i]==0) {
	  rb_raise(rb_eHE5Error, "stride cannot be zero [%s:%d]",__FILE__,__LINE__);
	}
      }
    }
    c_count=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(count)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
        c_count[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    case T_TRUE:
      for(i=0; i<i_rank; i++){
        c_count[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    case T_FALSE:
      for(i=0; i<i_rank; i++){
        c_count[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    default:
      Check_Type(count,T_ARRAY);
      if(RARRAY_LEN(count) < i_rank) {
        rb_raise(rb_eHE5Error, "Length of 'end' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
        l_count= NUM2INT(RARRAY_PTR(count)[i_rank-1-i]);
        if(l_count < 0) {
	  l_count +=hs_dims[i];
        }
        c_count[i]=(l_count-c_start[i])/c_stride[i]+1;
      }
    }

    shape = ALLOCA_N(int,i_rank);
    for(i=0;i<i_rank;i++){
      shape[i_rank-1-i]=c_count[i];
    }
    Cshort_to_NArray(NArray,i_rank,shape,o_data);
    status = HE5_ZAread(i_zaid, i_fldname, c_start, c_stride, c_count, o_data);
    if(status == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);

    OBJ_TAINT(NArray);

    return(NArray);
}

VALUE
hdfeos5_zaread_int(VALUE mod, VALUE start, VALUE stride, VALUE count)
{
    hid_t i_zaid;
    char *i_fldname;
    signed long long *c_start;
    unsigned long long *c_stride;
    unsigned long long *c_count;

    int i_rank;
    hid_t i_ntype = FAIL;
    unsigned long long hs_dims[10];
    int  i;
    long l_start, l_count;
    int  *shape;    /* NArray uses int instead of size_t */
    herr_t status;
    void *o_data;
    VALUE NArray;

    struct HE5ZaField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5ZaField, he5field);
    i_fldname=he5field->name;
    i_zaid=he5field->zaid;

    status = HE5_ZAinfo(i_zaid, i_fldname, &i_rank, hs_dims, &i_ntype, NULL, NULL);

    Check_Type(start,T_ARRAY);
    if(RARRAY_LEN(start) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'start' is too short [%s:%d]",
	       __FILE__,__LINE__);
    }
    c_start=ALLOCA_N(signed long long,i_rank);
    for(i=0; i<i_rank; i++){
      l_start=NUM2INT(RARRAY_PTR(start)[i_rank-1-i]);
      if(l_start < 0) {
	l_start += hs_dims[i];
      }
      c_start[i]=l_start;
    }
    c_stride=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(stride)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
	  c_stride[i]=1;
      }
      break;
    case T_FALSE:
      for(i=0; i<i_rank; i++){
	  c_stride[i]=1;
      }
      break;
    case T_TRUE:
      for(i=0; i<i_rank; i++){
	  c_stride[i]=1;
      }
      break;
    default:
      Check_Type(stride,T_ARRAY);
      if(RARRAY_LEN(stride) < i_rank) {
	  rb_raise(rb_eHE5Error, "Length of 'stride' is too short [%s:%d]",
		   __FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
	c_stride[i]=NUM2INT(RARRAY_PTR(stride)[i_rank-1-i]);
	if(c_stride[i]==0) {
	  rb_raise(rb_eHE5Error, "stride cannot be zero [%s:%d]",__FILE__,__LINE__);
	}
      }
    }
    c_count=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(count)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
        c_count[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    case T_TRUE:
      for(i=0; i<i_rank; i++){
        c_count[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    case T_FALSE:
      for(i=0; i<i_rank; i++){
        c_count[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    default:
      Check_Type(count,T_ARRAY);
      if(RARRAY_LEN(count) < i_rank) {
        rb_raise(rb_eHE5Error, "Length of 'end' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
        l_count= NUM2INT(RARRAY_PTR(count)[i_rank-1-i]);
        if(l_count < 0) {
	  l_count +=hs_dims[i];
        }
        c_count[i]=(l_count-c_start[i])/c_stride[i]+1;
      }
    }

    shape = ALLOCA_N(int,i_rank);
    for(i=0;i<i_rank;i++){
      shape[i_rank-1-i]=c_count[i];
    }
    Cint_to_NArray(NArray,i_rank,shape,o_data);
    status = HE5_ZAread(i_zaid, i_fldname, c_start, c_stride, c_count, o_data);
    if(status == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);

    OBJ_TAINT(NArray);

    return(NArray);
}

VALUE
hdfeos5_zaread_long(VALUE mod, VALUE start, VALUE stride, VALUE count)
{
    hid_t i_zaid;
    char *i_fldname;
    signed long long *c_start;
    unsigned long long *c_stride;
    unsigned long long *c_count;

    int i_rank;
    hid_t i_ntype = FAIL;
    unsigned long long hs_dims[10];
    int  i;
    long l_start, l_count;
    int  *shape;    /* NArray uses int instead of size_t */
    herr_t status;
    void *o_data;
    VALUE NArray;

    struct HE5ZaField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5ZaField, he5field);
    i_fldname=he5field->name;
    i_zaid=he5field->zaid;

    status = HE5_ZAinfo(i_zaid, i_fldname, &i_rank, hs_dims, &i_ntype, NULL, NULL);

    Check_Type(start,T_ARRAY);
    if(RARRAY_LEN(start) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'start' is too short [%s:%d]",
	       __FILE__,__LINE__);
    }
    c_start=ALLOCA_N(signed long long,i_rank);
    for(i=0; i<i_rank; i++){
      l_start=NUM2INT(RARRAY_PTR(start)[i_rank-1-i]);
      if(l_start < 0) {
	l_start += hs_dims[i];
      }
      c_start[i]=l_start;
    }
    c_stride=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(stride)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
	  c_stride[i]=1;
      }
      break;
    case T_FALSE:
      for(i=0; i<i_rank; i++){
	  c_stride[i]=1;
      }
      break;
    case T_TRUE:
      for(i=0; i<i_rank; i++){
	  c_stride[i]=1;
      }
      break;
    default:
      Check_Type(stride,T_ARRAY);
      if(RARRAY_LEN(stride) < i_rank) {
	  rb_raise(rb_eHE5Error, "Length of 'stride' is too short [%s:%d]",
		   __FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
	c_stride[i]=NUM2INT(RARRAY_PTR(stride)[i_rank-1-i]);
	if(c_stride[i]==0) {
	  rb_raise(rb_eHE5Error, "stride cannot be zero [%s:%d]",__FILE__,__LINE__);
	}
      }
    }
    c_count=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(count)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
        c_count[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    case T_TRUE:
      for(i=0; i<i_rank; i++){
        c_count[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    case T_FALSE:
      for(i=0; i<i_rank; i++){
        c_count[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    default:
      Check_Type(count,T_ARRAY);
      if(RARRAY_LEN(count) < i_rank) {
        rb_raise(rb_eHE5Error, "Length of 'end' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
        l_count= NUM2INT(RARRAY_PTR(count)[i_rank-1-i]);
        if(l_count < 0) {
	  l_count +=hs_dims[i];
        }
        c_count[i]=(l_count-c_start[i])/c_stride[i]+1;
      }
    }

    shape = ALLOCA_N(int,i_rank);
    for(i=0;i<i_rank;i++){
      shape[i_rank-1-i]=c_count[i];
    }
    Clong_to_NArray(NArray,i_rank,shape,o_data);
    status = HE5_ZAread(i_zaid, i_fldname, c_start, c_stride, c_count, o_data);
    if(status == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);

    OBJ_TAINT(NArray);

    return(NArray);
}

VALUE
hdfeos5_zaread_float(VALUE mod, VALUE start, VALUE stride, VALUE count)
{
    hid_t i_zaid;
    char *i_fldname;
    signed long long *c_start;
    unsigned long long *c_stride;
    unsigned long long *c_count;

    int i_rank;
    hid_t i_ntype = FAIL;
    unsigned long long hs_dims[10];
    int  i;
    long l_start, l_count;
    int  *shape;    /* NArray uses int instead of size_t */
    herr_t status;
    void *o_data;
    VALUE NArray;

    struct HE5ZaField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5ZaField, he5field);
    i_fldname=he5field->name;
    i_zaid=he5field->zaid;

    status = HE5_ZAinfo(i_zaid, i_fldname, &i_rank, hs_dims, &i_ntype, NULL, NULL);

    Check_Type(start,T_ARRAY);
    if(RARRAY_LEN(start) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'start' is too short [%s:%d]",
	       __FILE__,__LINE__);
    }
    c_start=ALLOCA_N(signed long long,i_rank);
    for(i=0; i<i_rank; i++){
      l_start=NUM2INT(RARRAY_PTR(start)[i_rank-1-i]);
      if(l_start < 0) {
	l_start += hs_dims[i];
      }
      c_start[i]=l_start;
    }
    c_stride=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(stride)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
	  c_stride[i]=1;
      }
      break;
    case T_FALSE:
      for(i=0; i<i_rank; i++){
	  c_stride[i]=1;
      }
      break;
    case T_TRUE:
      for(i=0; i<i_rank; i++){
	  c_stride[i]=1;
      }
      break;
    default:
      Check_Type(stride,T_ARRAY);
      if(RARRAY_LEN(stride) < i_rank) {
	  rb_raise(rb_eHE5Error, "Length of 'stride' is too short [%s:%d]",
		   __FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
	c_stride[i]=NUM2INT(RARRAY_PTR(stride)[i_rank-1-i]);
	if(c_stride[i]==0) {
	  rb_raise(rb_eHE5Error, "stride cannot be zero [%s:%d]",__FILE__,__LINE__);
	}
      }
    }
    c_count=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(count)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
        c_count[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    case T_TRUE:
      for(i=0; i<i_rank; i++){
        c_count[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    case T_FALSE:
      for(i=0; i<i_rank; i++){
        c_count[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    default:
      Check_Type(count,T_ARRAY);
      if(RARRAY_LEN(count) < i_rank) {
        rb_raise(rb_eHE5Error, "Length of 'end' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
        l_count= NUM2INT(RARRAY_PTR(count)[i_rank-1-i]);
        if(l_count < 0) {
	  l_count +=hs_dims[i];
        }
        c_count[i]=(l_count-c_start[i])/c_stride[i]+1;
      }
    }

    shape = ALLOCA_N(int,i_rank);
    for(i=0;i<i_rank;i++){
      shape[i_rank-1-i]=c_count[i];
    }
    Cfloat_to_NArray(NArray,i_rank,shape,o_data);
    status = HE5_ZAread(i_zaid, i_fldname, c_start, c_stride, c_count, o_data);
    if(status == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);

    OBJ_TAINT(NArray);

    return(NArray);
}

VALUE
hdfeos5_zaread_double(VALUE mod, VALUE start, VALUE stride, VALUE count)
{
    hid_t i_zaid;
    char *i_fldname;
    signed long long *c_start;
    unsigned long long *c_stride;
    unsigned long long *c_count;

    int i_rank;
    hid_t i_ntype = FAIL;
    unsigned long long hs_dims[10];
    int  i;
    long l_start, l_count;
    int  *shape;    /* NArray uses int instead of size_t */
    herr_t status;
    void *o_data;
    VALUE NArray;

    struct HE5ZaField *he5field;
    rb_secure(4);
    Data_Get_Struct(mod, struct HE5ZaField, he5field);
    i_fldname=he5field->name;
    i_zaid=he5field->zaid;

    status = HE5_ZAinfo(i_zaid, i_fldname, &i_rank, hs_dims, &i_ntype, NULL, NULL);

    Check_Type(start,T_ARRAY);
    if(RARRAY_LEN(start) < i_rank) {
      rb_raise(rb_eHE5Error, "Length of 'start' is too short [%s:%d]",
	       __FILE__,__LINE__);
    }
    c_start=ALLOCA_N(signed long long,i_rank);
    for(i=0; i<i_rank; i++){
      l_start=NUM2INT(RARRAY_PTR(start)[i_rank-1-i]);
      if(l_start < 0) {
	l_start += hs_dims[i];
      }
      c_start[i]=l_start;
    }
    c_stride=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(stride)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
	  c_stride[i]=1;
      }
      break;
    case T_FALSE:
      for(i=0; i<i_rank; i++){
	  c_stride[i]=1;
      }
      break;
    case T_TRUE:
      for(i=0; i<i_rank; i++){
	  c_stride[i]=1;
      }
      break;
    default:
      Check_Type(stride,T_ARRAY);
      if(RARRAY_LEN(stride) < i_rank) {
	  rb_raise(rb_eHE5Error, "Length of 'stride' is too short [%s:%d]",
		   __FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
	c_stride[i]=NUM2INT(RARRAY_PTR(stride)[i_rank-1-i]);
	if(c_stride[i]==0) {
	  rb_raise(rb_eHE5Error, "stride cannot be zero [%s:%d]",__FILE__,__LINE__);
	}
      }
    }
    c_count=ALLOCA_N(unsigned long long,i_rank);
    switch(TYPE(count)){
    case T_NIL:
      for(i=0; i<i_rank; i++){
        c_count[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    case T_TRUE:
      for(i=0; i<i_rank; i++){
        c_count[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    case T_FALSE:
      for(i=0; i<i_rank; i++){
        c_count[i]=(hs_dims[i]-c_start[i]-1)/c_stride[i]+1;
      }
      break;
    default:
      Check_Type(count,T_ARRAY);
      if(RARRAY_LEN(count) < i_rank) {
        rb_raise(rb_eHE5Error, "Length of 'end' is too short [%s:%d]",__FILE__,__LINE__);
      }
      for(i=0; i<i_rank; i++){
        l_count= NUM2INT(RARRAY_PTR(count)[i_rank-1-i]);
        if(l_count < 0) {
	  l_count +=hs_dims[i];
        }
        c_count[i]=(l_count-c_start[i])/c_stride[i]+1;
      }
    }

    shape = ALLOCA_N(int,i_rank);
    for(i=0;i<i_rank;i++){
      shape[i_rank-1-i]=c_count[i];
    }
    Cdouble_to_NArray(NArray,i_rank,shape,o_data);
    status = HE5_ZAread(i_zaid, i_fldname, c_start, c_stride, c_count, o_data);
    if(status == FAIL) rb_raise(rb_eHE5Error, "ERROR [%s:%d]",__FILE__,__LINE__);

    OBJ_TAINT(NArray);

    return(NArray);
}

void
init_hdfeos5za_wrap(void)
{
    mNumRu = rb_define_module("NumRu");

    /* Difinitions of the classes */;
    cHE5 = rb_define_class_under(mNumRu, "HE5",rb_cObject);
    cHE5Za = rb_define_class_under(mNumRu, "HE5Za",rb_cObject);
    cHE5ZaField = rb_define_class_under(mNumRu, "HE5ZaField",rb_cObject);
    rb_eHE5Error = rb_define_class("HE5Error",rb_eStandardError);

    /* Class Constants Definition */
    /* Difinitions of the HE5 Class */;
    rb_define_method(cHE5, "zacreate", hdfeos5_zacreate, 1);
    rb_define_method(cHE5, "zaattach", hdfeos5_zaattach, 1);
    rb_define_method(cHE5, "inqza", hdfeos5_zainqza, 0);
    rb_define_method(cHE5, "chkza", hdfeos5_zachkza, 0);
    rb_define_method(cHE5, "chkzaname", hdfeos5_zachkzaname, 0);
    /* Difinitions of the HE5 ZA Class */
    rb_define_method(cHE5Za, "defdim", hdfeos5_zadefdim, 2);
    rb_define_method(cHE5Za, "diminfo", hdfeos5_zadiminfo, 1);
    rb_define_method(cHE5Za, "chunkinfo", hdfeos5_zachunkinfo, 1);
    rb_define_method(cHE5Za, "defchunk", hdfeos5_zadefchunk, 2);
    rb_define_method(cHE5Za, "defcomp", hdfeos5_zadefcomp, 2);
    rb_define_method(cHE5Za, "defcomchunk", hdfeos5_zadefcomchunk, 4);
    rb_define_method(cHE5Za, "define", hdfeos5_zadefine, 4);
    rb_define_method(cHE5Za, "writedatameta", hdfeos5_zawritedatameta, 2);
    rb_define_method(cHE5Za, "writeattr", hdfeos5_zawriteattr, 4);
    rb_define_method(cHE5Za, "get_att_", hdfeos5_za_get_att, 1);
    rb_define_method(cHE5Za, "inqattrs", hdfeos5_zainqattrs, 0);
    rb_define_method(cHE5Za, "inqdims", hdfeos5_zainqdims, 1);
    rb_define_method(cHE5Za, "inquire", hdfeos5_zainquire, 1);
    rb_define_method(cHE5Za, "inqdatatype", hdfeos5_zainqdatatype, 3);
    rb_define_method(cHE5Za, "nentries", hdfeos5_zanentries, 1);
    rb_define_method(cHE5Za, "zadetach", hdfeos5_zadetach, 0);
    rb_define_method(cHE5Za, "setfillvalue", hdfeos5_zasetfillvalue, 3);
    rb_define_method(cHE5Za, "getfillvalue", hdfeos5_zagetfillvalue, 1);
    rb_define_method(cHE5Za, "writegrpattr", hdfeos5_zawritegrpattr, 4);
    rb_define_method(cHE5Za, "get_grpatt_", hdfeos5_za_get_grpatt, 1);
    rb_define_method(cHE5Za, "inqgrpattrs", hdfeos5_zainqgrpattrs, 0);
    rb_define_method(cHE5Za, "setalias", hdfeos5_zasetalias, 1);
    rb_define_method(cHE5Za, "dropalias", hdfeos5_zadropalias, 2);
    rb_define_method(cHE5Za, "inqfldalias", hdfeos5_zainqfldalias, 0);
    rb_define_method(cHE5Za, "aliasinfo", hdfeos5_zaaliasinfo, 2);
    rb_define_method(cHE5Za, "getaliaslist", hdfeos5_zagetaliaslist, 1);
    rb_define_method(cHE5Za, "fldrename", hdfeos5_zafldrename, 2);
    rb_define_method(cHE5Za, "mountexternal", hdfeos5_zamountexternal, 2);
    rb_define_method(cHE5Za, "unmount", hdfeos5_zaunmount, 2);
    rb_define_method(cHE5Za, "readexternal", hdfeos5_zareadexternal, 2);
    rb_define_method(cHE5Za, "setextdata", hdfeos5_zasetextdata, 3);
    rb_define_method(cHE5Za, "getextdata", hdfeos5_zagetextdata, 1);
    rb_define_method(cHE5Za, "setfield", hdfeos5_zasetfield, 1);
    rb_define_method(cHE5Za, "getfield", hdfeos5_zagetfield, 0);

    /* Original of the HE5 ZA Class */;
    rb_define_method(cHE5Za, "file", hdfeos5_za_file, 0);
    rb_define_method(cHE5Za, "path", hdfeos5_za_path, 0);
    rb_define_method(cHE5Za, "name", hdfeos5_za_inqname, 0);
    rb_define_method(cHE5Za, "define_mode?", hdfeos5_za_whether_in_define_mode, 0);

    /* Difinitions of the HE5 ZA Field Class */;
    rb_define_method(cHE5ZaField, "compinfo", hdfeos5_zacompinfo, 0);
    rb_define_method(cHE5ZaField, "fieldinfo", hdfeos5_zainfo, 0);
    rb_define_method(cHE5ZaField, "writefield", hdfeos5_zawrite, 5);
    rb_define_method(cHE5ZaField, "readfield", hdfeos5_zaread, 4);
    rb_define_method(cHE5ZaField, "writelocattr", hdfeos5_zawritelocattr, 4);
    rb_define_method(cHE5ZaField, "get_att_", hdfeos5_zafield_get_att, 1);
    rb_define_method(cHE5ZaField, "inqlocattrs", hdfeos5_zainqlocattrs, 0);
    rb_define_method(cHE5ZaField, "fldsrch", hdfeos5_zafldsrch, 0);

    rb_define_method(cHE5ZaField, "put_vars_char", hdfeos5_zawrite_char, 4);
    rb_define_method(cHE5ZaField, "put_vars_int", hdfeos5_zawrite_int, 4);
    rb_define_method(cHE5ZaField, "put_vars_long", hdfeos5_zawrite_long, 4);
    rb_define_method(cHE5ZaField, "put_vars_float", hdfeos5_zawrite_float, 4);
    rb_define_method(cHE5ZaField, "put_vars_double", hdfeos5_zawrite_double, 4);
    rb_define_method(cHE5ZaField, "put_vars_short", hdfeos5_zawrite_short, 4);
    
    rb_define_method(cHE5ZaField, "get_vars_char", hdfeos5_zaread_char, 3);
    rb_define_method(cHE5ZaField, "get_vars_int", hdfeos5_zaread_int, 3);
    rb_define_method(cHE5ZaField, "get_vars_long", hdfeos5_zaread_long, 3);
    rb_define_method(cHE5ZaField, "get_vars_float", hdfeos5_zaread_float, 3);
    rb_define_method(cHE5ZaField, "get_vars_double", hdfeos5_zaread_double, 3);
    rb_define_method(cHE5ZaField, "get_vars_short", hdfeos5_zaread_short, 3);

    /* Original of the HE5 ZA Field Class */;
    rb_define_method(cHE5ZaField, "za", hdfeos5_zafld_za, 0);
    rb_define_method(cHE5ZaField, "name", hdfeos5_zafld_inqname, 0);
    rb_define_method(cHE5ZaField, "setfield", hdfeos5_zasetfield, 1);
    rb_define_method(cHE5ZaField, "getfield", hdfeos5_zagetfield, 0);

}
