#include "hdf5.h" #include "api.h" #include "buffer.h" #include #include #include #ifdef _WIN32 #pragma warning(disable: 4018) #pragma warning(disable: 4244) #endif #define HDF_TYPE 'H5' #define BUFF_SIZE 1024 ///////////////////////////////////////////////////////////////////// class zsAttID { public: zsAttID(hid_t id, const char*name); ~zsAttID(); hid_t aid, // attribute ID tid, // type ID sid; // space ID int ndim; // number of dimensions of a attribute hsize_t dims[H5S_MAX_RANK]; // dimensions }; zsAttID::zsAttID(hid_t id, const char*name) : aid(-1), tid(-1), sid(-1), ndim(0) { if (id >= 0 && name) { aid = H5Aopen_name(id, name); if (aid >= 0) { tid = H5Aget_type(aid); if (tid >= 0) { sid = H5Aget_space(aid); if (sid < 0) { H5Tclose(tid); H5Aclose(aid); } else { ndim = H5Sget_simple_extent_ndims(sid); if (ndim > 0) H5Sget_simple_extent_dims(sid, dims, NULL); } } else { H5Aclose(aid); aid = -1; } } } } zsAttID::~zsAttID() { if (sid >= 0) H5Sclose(sid); if (tid >= 0) H5Tclose(tid); if (aid >= 0) H5Aclose(aid); } class zsHDF { public: zsHDF() : fid(-1), gid(-1), did(-1), tid(-1), sid(-1), mid(-1), endian(0), flag(false), ndim(0), size(0), ptr(0), np(0), ns(0) { } ~zsHDF(); void checksize(); void checkindex(void *ctx, int nargs, void** args); void checkdataset(void *ctx); void hyperslab(void *ctx); hid_t fid, // file ID gid, // group ID did, // dataset ID tid, // dataset type ID sid, // dataset space ID mid; // memory space ID hsize_t np, // number of data points ns, // number of delected points size, // ptr bytes dims[H5S_MAX_RANK], // dimensions mstart[H5S_MAX_RANK], // memory start mcount[H5S_MAX_RANK], // memory count dstart[H5S_MAX_RANK], // dataset start dcount[H5S_MAX_RANK]; // dataset count size_t ndim, // number of dimensions tsize; // bytes of datum type bool flag; // true if dataset is the target; otherwise group is the target. int type; // zs type int endian; // -1: little endian; 0: native; 1: bigendian void *ptr; // pointer to extracted data }; zsHDF::~zsHDF() { if (mid >= 0) H5Sclose(mid); if (sid >= 0) H5Sclose(sid); if (tid >= 0) H5Tclose(tid); if (did >= 0) H5Dclose(did); if (gid >= 0) H5Gclose(gid); if (fid >= 0) H5Fclose(fid); if (ptr) free(ptr); } void zsHDF::checksize() { size_t n = ns*tsize; if (size < n || size > 2*n) { if (ptr) free(ptr); ptr = malloc(n); size = n; } } void zsHDF::hyperslab(void *ctx) { if (mid >= 0) H5Sclose(mid); mid = H5Screate_simple(1, mcount, NULL); if (sid >= 0) H5Sclose(sid); sid = H5Dget_space(did); if (H5Sselect_hyperslab(sid, H5S_SELECT_SET, dstart, NULL, dcount, NULL) < 0 || H5Sselect_hyperslab(mid, H5S_SELECT_SET, mstart, NULL, mcount, NULL) > 0) api_runtime_error(ctx, "failed in H5Select_hyperslab"); } void zsHDF::checkdataset(void *ctx) { if (!flag) api_runtime_error(ctx, "dataset not specified"); } void zsHDF::checkindex(void *ctx, int nargs, void** args) { if (nargs-1 > ndim) api_runtime_error(ctx, "too many dimension specifiers"); checkdataset(ctx); int i, k; ns = 1; for (k = 0; k < ndim; k++) { dstart[k] = 0; dcount[k] = dims[k]; ns *= dims[k]; } for (i = 1; i < nargs; i++) { k = i - 1; if (k >= ndim) api_runtime_error(ctx, "index number exceeds dataset dimension number"); if (!api_is_null(args[i])) { ns /= dims[k]; if (api_is_integer(args[i])) { // e.g., hfd[3] dstart[k] = api_get_integer(ctx, args[i]); dcount[k] = 1; } else { // e.g. hfd[3:?] dstart[k] = api_get_integer(ctx, api_get_array_object(ctx, args[i], "0")); if (dstart[k] < 0 || dstart[k] >= dims[k]) api_runtime_error(ctx, "invalid start index"); void *a1 = api_get_array_object(ctx, args[i], "1"); if (api_is_null(a1)) { // e.g. hdf[3:*] dcount[k] = dims[k] - dstart[k]; } else { // e.g. hdf[3:5] dcount[k] = api_get_integer(ctx, a1); dcount[k] = dcount[k] - dstart[k] + 1; } if (dcount[k] <= 0 || dcount[k] >= dims[k]) api_runtime_error(ctx, "invalid end index"); ns *= dcount[k]; } } } mstart[0] = 0; mcount[0] = ns; } enum { HDF_CHAR, HDF_UCHAR, HDF_SHORT, HDF_USHORT, HDF_INT, HDF_UINT, HDF_FLOAT, HDF_DOUBLE, HDF_STRING}; ///////////////////////////////////////////////////////////////////// void type_error(void* ctx, const char* msg) { api_runtime_error2(ctx, "unsupported variable/attibute type: ", msg); } void hdf_destroy(void *ptr) { delete (zsHDF*)ptr; ptr = 0; } herr_t hdf_error(void *data) { H5Eclear(); return 1; } ///////////////////////////////////////////////////////////////////// void* hdf_open(void *ctx, int nargs, void** args) { if (nargs < 1) api_input_error(ctx); const char *fname = api_get_string(ctx, args[0]); zsHDF *o = new zsHDF; H5Eset_auto(hdf_error, o); if (nargs > 1) { const char *s = api_get_string(ctx, args[1]); if (s[0] == 'w' || s[0] == 'W') { o->fid = H5Fopen(fname, H5F_ACC_RDWR, H5P_DEFAULT); if (o->fid < 0) { o->fid = H5Fcreate(fname, H5F_ACC_EXCL, H5P_DEFAULT, H5P_DEFAULT); } } else if (s[0] == 'c' || s[0] == 'C') { o->fid = H5Fcreate(fname, H5F_ACC_EXCL, H5P_DEFAULT, H5P_DEFAULT); } else { o->fid = H5Fopen(fname, H5F_ACC_RDONLY, H5P_DEFAULT); } } else { o->fid = H5Fopen(fname, H5F_ACC_RDONLY, H5P_DEFAULT); } if (o->fid < 0) { return 0; } o->gid = H5Gopen(o->fid, "/"); if (o->gid < 0) o->gid = H5Gcreate(o->fid, "/", 1); if (o->gid < 0) api_runtime_error(ctx, "failed to open or create group"); return api_create_user(ctx, o, 0, hdf_destroy, HDF_TYPE); } void* hdf_version(void *ctx, int nargs, void** args) { unsigned v1, v2, v3; H5get_libversion(&v1, &v2, &v3); static char buf[64]; sprintf(buf, "version-%d.%d.%d", v1, v2, v3); return api_create_string(ctx, buf); } void* hdf_group(void *ctx, int nargs, void** args) { if (nargs < 1) api_input_error(ctx); zsHDF *o = (zsHDF*)api_get_user(ctx, args[0], HDF_TYPE); if (nargs == 1) { // get sub-group names hsize_t k, n; zsBuffer buf(BUFF_SIZE); H5Gget_num_objs(o->gid, &n); void *arr = api_create_array(ctx, n+1); int count = 0; for (k = 0; k < n; k++) { hid_t type = H5Gget_objtype_by_idx(o->gid, k); if (type == H5G_GROUP) { H5Gget_objname_by_idx(o->gid, k, buf.u.pchar, BUFF_SIZE-1); buf.u.pchar[BUFF_SIZE-1] = 0; api_set_array_object2(ctx, arr, count++, api_create_string(0, buf.u.pchar)); } H5Tclose(type); } return arr; } // get or create group const char *name = api_get_string(ctx, args[1]); if (o->gid >= 0) H5Gclose(o->gid); o->gid = H5Gopen(o->fid, name); if (o->gid < 0) o->gid = H5Gcreate(o->fid, name, strlen(name)); if (o->gid < 0) api_runtime_error(ctx, "failed to open/create group"); o->flag = false; return 0; } void* hdf_dataset(void *ctx, int nargs, void** args) { if (nargs < 1) api_input_error(ctx); zsHDF *o = (zsHDF*)api_get_user(ctx, args[0], HDF_TYPE); if (nargs == 1) { // get dataset names hsize_t k, n; zsBuffer buf(BUFF_SIZE); H5Gget_num_objs(o->gid, &n); void *arr = api_create_array(ctx, n+1); int count = 0; for (k = 0; k < n; k++) { hid_t type = H5Gget_objtype_by_idx(o->gid, k); if (type == H5G_DATASET) { H5Gget_objname_by_idx(o->gid, k, buf.u.pchar, BUFF_SIZE-1); buf.u.pchar[BUFF_SIZE-1] = 0; api_set_array_object2(ctx, arr, count++, api_create_string(0, buf.u.pchar)); } H5Tclose(type); } return arr; } const char *name = api_get_string(ctx, args[1]); if (nargs == 2) { // set dataset target if (o->did >= 0) H5Dclose(o->did); o->did = H5Dopen(o->gid, name); if (o->did < 0) return api_create_integer(ctx, 0); if (o->tid >= 0) H5Tclose(o->tid); o->tid = H5Dget_type(o->did); o->tsize = H5Tget_size(o->tid); switch (H5Tget_class(o->tid)) { case H5T_INTEGER: if (H5Tequal(o->tid, H5T_NATIVE_SCHAR)) { o->type = HDF_CHAR; o->endian = 0; } else if (H5Tequal(o->tid, H5T_STD_I8BE)) { o->type = HDF_CHAR; o->endian = 1; } else if (H5Tequal(o->tid, H5T_STD_I8LE)) { o->type = HDF_CHAR; o->endian = -1; } else if (H5Tequal(o->tid, H5T_NATIVE_UCHAR)) { o->type = HDF_UCHAR; o->endian = 0; } else if (H5Tequal(o->tid, H5T_STD_U8BE)) { o->type = HDF_UCHAR; o->endian = 1; } else if (H5Tequal(o->tid, H5T_STD_U8LE)) { o->type = HDF_UCHAR; o->endian = -1; } else if (H5Tequal(o->tid, H5T_NATIVE_SHORT)) { o->type = HDF_SHORT; o->endian = 0; } else if (H5Tequal(o->tid, H5T_STD_I16BE)) { o->type = HDF_SHORT; o->endian = 1; } else if (H5Tequal(o->tid, H5T_STD_I16LE)) { o->type = HDF_SHORT; o->endian = -1; } else if (H5Tequal(o->tid, H5T_NATIVE_USHORT)) { o->type = HDF_USHORT; o->endian = 0; } else if (H5Tequal(o->tid, H5T_STD_U16BE)) { o->type = HDF_USHORT; o->endian = 1; } else if (H5Tequal(o->tid, H5T_STD_U16LE)) { o->type = HDF_USHORT; o->endian = -1; } else if (H5Tequal(o->tid, H5T_NATIVE_INT)) { o->type = HDF_INT; o->endian = 0; } else if (H5Tequal(o->tid, H5T_STD_I32BE)) { o->type = HDF_INT; o->endian = 1; } else if (H5Tequal(o->tid, H5T_STD_I32LE)) { o->type = HDF_INT; o->endian = -1; } else if (H5Tequal(o->tid, H5T_NATIVE_UINT)) { o->type = HDF_UINT; o->endian = 0; } else if (H5Tequal(o->tid, H5T_STD_U32BE)) { o->type = HDF_UINT; o->endian = 1; } else if (H5Tequal(o->tid, H5T_STD_U32LE)) { o->type = HDF_UINT; o->endian = -1; } else { type_error(ctx, " --H5T_INTEGER_?-- "); } break; case H5T_FLOAT: if (H5Tequal(o->tid, H5T_NATIVE_FLOAT)) { o->type = HDF_FLOAT; o->endian = 0; } else if (H5Tequal(o->tid, H5T_IEEE_F32BE)) { o->type = HDF_FLOAT; o->endian = 1; } else if (H5Tequal(o->tid, H5T_IEEE_F32LE)) { o->type = HDF_FLOAT; o->endian = -1; } else if (H5Tequal(o->tid, H5T_NATIVE_DOUBLE)) { o->type = HDF_DOUBLE; o->endian = 0; } else if (H5Tequal(o->tid, H5T_IEEE_F64BE)) { o->type = HDF_DOUBLE; o->endian = 1; } else if (H5Tequal(o->tid, H5T_IEEE_F64LE)) { o->type = HDF_DOUBLE; o->endian = -1; } else { type_error(ctx, " --H5T_FLOAT_?-- "); } break; case H5T_STRING: o->type = HDF_STRING; o->endian = 0; break; case H5T_TIME: type_error(ctx, " --H5T_TIME-- "); break; case H5T_BITFIELD: type_error(ctx, " --H5T_BITFIELD-- "); break; case H5T_OPAQUE: type_error(ctx, " --H5T_OPAQUE-- "); break; case H5T_COMPOUND: type_error(ctx, " --H5T_COMPOUND-- "); break; case H5T_REFERENCE: type_error(ctx, " --H5T_REFERENCE-- "); break; case H5T_ENUM: type_error(ctx, " --H5T_ENUM-- "); break; case H5T_VLEN: type_error(ctx, " --H5T_VLEN-- "); break; case H5T_ARRAY: type_error(ctx, " --H5T_ARRAY-- "); break; default: type_error(ctx, " --H5T_?-- "); break; } if (o->sid >= 0) H5Sclose(o->sid); o->sid = H5Dget_space(o->did); if (o->sid < 0) api_runtime_error(ctx, "failed to get dataset space"); if (H5Sis_simple(o->sid) > 0) { o->ndim = H5Sget_simple_extent_dims(o->sid, o->dims, 0); if (o->ndim < 0) api_runtime_error(ctx, "failed to get dataset space dimensions"); o->np = H5Sget_simple_extent_npoints(o->sid); } else { api_runtime_error(ctx, "complex data space not supported"); } o->flag = true; return api_create_integer(ctx, 1); } // define dataset if (nargs < 4) api_input_error(ctx); const char *type = api_get_string(ctx, args[2]); if (o->tid >= 0) H5Tclose(o->tid); if (!strcmp(type, "char")) { o->tid = H5Tcopy(H5T_NATIVE_CHAR); o->tsize = sizeof(char); o->type = HDF_CHAR; } else if (!strcmp(type, "uchar")) { o->tid = H5Tcopy(H5T_NATIVE_UCHAR); o->tsize = sizeof(unsigned char); o->type = HDF_UCHAR; } else if (!strcmp(type, "short")) { o->tid = H5Tcopy(H5T_NATIVE_SHORT); o->tsize = sizeof(short); o->type = HDF_SHORT; } else if (!strcmp(type, "ushort")) { o->tid = H5Tcopy(H5T_NATIVE_USHORT); o->tsize = sizeof(unsigned short); o->type = HDF_USHORT; } else if (!strcmp(type, "int")) { o->tid = H5Tcopy(H5T_NATIVE_INT); o->tsize = sizeof(int); o->type = HDF_INT; } else if (!strcmp(type, "uint")) { o->tid = H5Tcopy(H5T_NATIVE_UINT); o->tsize = sizeof(unsigned int); o->type = HDF_UINT; } else if (!strcmp(type, "float")) { o->tid = H5Tcopy(H5T_NATIVE_FLOAT); o->tsize = sizeof(float); o->type = HDF_FLOAT; } else if (!strcmp(type, "double")) { o->tid = H5Tcopy(H5T_NATIVE_DOUBLE); o->tsize = sizeof(double); o->type = HDF_DOUBLE; } else if (!strcmp(type, "string")) { o->tid = H5Tcopy(H5T_C_S1); o->tsize = 1; o->type = HDF_STRING; } else { api_input_error(ctx); } o->ndim = 0; o->np = 1; for (int i = 3; i < nargs && o->ndim < H5S_MAX_RANK; i++) { integer_t n = api_get_integer(ctx, args[i]); if (n <= 0) api_input_error(ctx); o->dims[o->ndim] = n; o->np *= n; o->ndim++; } if (o->type == HDF_STRING) { if (o->ndim < 2) api_input_error(ctx); o->ndim--; // for string array, the last number is the string length. o->tsize = o->dims[o->ndim]; H5Tset_size(o->tid, o->tsize); } if (o->sid >= 0) H5Sclose(o->sid); o->sid = H5Screate_simple(o->ndim, o->dims, 0); if (o->sid < 0) api_runtime_error(ctx, "failed to create data space"); if (o->did >= 0) H5Dclose(o->did); o->did = H5Dcreate(o->gid, name, o->tid, o->sid, H5P_DEFAULT); if (o->did < 0) api_runtime_error(ctx, "failed to create dataset"); o->flag = true; return 0; } void* hdf_size(void *ctx, int nargs, void** args) { if (nargs < 1) api_input_error(ctx); zsHDF *o = (zsHDF*)api_get_user(ctx, args[0], HDF_TYPE); o->checkdataset(ctx); void *arr = api_create_array(ctx, 3); api_set_array_object(ctx, arr, "0", api_create_integer(0, o->np)); api_set_array_object(ctx, arr, "1", api_create_integer(0, o->tsize)); switch (o->type) { case HDF_CHAR: api_set_array_object(ctx, arr, "2", api_create_string(0, "char")); break; case HDF_UCHAR: api_set_array_object(ctx, arr, "2", api_create_string(0, "uchar")); break; case HDF_SHORT: api_set_array_object(ctx, arr, "2", api_create_string(0, "short")); break; case HDF_USHORT: api_set_array_object(ctx, arr, "2", api_create_string(0, "ushort")); break; case HDF_INT: api_set_array_object(ctx, arr, "2", api_create_string(0, "int")); break; case HDF_UINT: api_set_array_object(ctx, arr, "2", api_create_string(0, "uint")); break; case HDF_FLOAT: api_set_array_object(ctx, arr, "2", api_create_string(0, "float")); break; case HDF_DOUBLE: api_set_array_object(ctx, arr, "2", api_create_string(0, "double")); break; case HDF_STRING: api_set_array_object(ctx, arr, "2", api_create_string(0, "string")); break; default: type_error(ctx, " --HDF_?-- "); } return arr; } void* hdf_dims(void *ctx, int nargs, void** args) { if (nargs < 1) api_input_error(ctx); zsHDF *o = (zsHDF*)api_get_user(ctx, args[0], HDF_TYPE); o->checkdataset(ctx); void *arr = api_create_array(ctx, o->ndim); for (int i = 0; i < o->ndim; i++) api_set_array_object2(ctx, arr, i, api_create_integer(0, o->dims[i])); return arr; } void* hdf_getatt(void *ctx, int nargs, void** args) { if (nargs < 2) api_input_error(ctx); zsHDF *o = (zsHDF*)api_get_user(ctx, args[0], HDF_TYPE); const char *name = api_get_string(ctx, args[1]); hid_t id = o->did; if (!o->flag) id = o->gid; zsAttID ids(id, name); if (ids.aid < 0) return 0; void *ret = 0; if (ids.ndim == 0) { switch (H5Tget_class(ids.tid)) { case H5T_INTEGER: if (H5Tequal(ids.aid, H5T_NATIVE_SCHAR) || H5Tequal(ids.aid, H5T_STD_I8BE) || H5Tequal(ids.aid, H5T_STD_I8LE) ) { char value; if (H5Aread(ids.aid, H5T_NATIVE_SCHAR, &value) >= 0) ret = api_create_integer(ctx, value); } else if (H5Tequal(ids.aid, H5T_NATIVE_UCHAR) || H5Tequal(ids.aid, H5T_STD_U8BE) || H5Tequal(ids.aid, H5T_STD_U8LE) ) { unsigned char value; if (H5Aread(ids.aid, H5T_NATIVE_UCHAR, &value) >= 0) ret = api_create_integer(ctx, value); } else if (H5Tequal(ids.aid, H5T_NATIVE_SHORT) || H5Tequal(ids.aid, H5T_STD_I16BE) || H5Tequal(ids.aid, H5T_STD_I16LE) ) { short value; if (H5Aread(ids.aid, H5T_NATIVE_SHORT, &value) >= 0) ret = api_create_integer(ctx, value); } else if (H5Tequal(ids.aid, H5T_NATIVE_USHORT) || H5Tequal(ids.aid, H5T_STD_U16BE) || H5Tequal(ids.aid, H5T_STD_U16LE) ) { unsigned short value; if (H5Aread(ids.aid, H5T_NATIVE_USHORT, &value) >= 0) ret = api_create_integer(ctx, value); } else if (H5Tequal(ids.aid, H5T_NATIVE_INT) || H5Tequal(ids.aid, H5T_STD_I32BE) || H5Tequal(ids.aid, H5T_STD_I32LE) ) { int value; if (H5Aread(ids.aid, H5T_NATIVE_INT, &value) >= 0) ret = api_create_integer(ctx, value); } else if (H5Tequal(ids.aid, H5T_NATIVE_UINT) || H5Tequal(ids.aid, H5T_STD_U32BE) || H5Tequal(ids.aid, H5T_STD_U32LE) ) { unsigned int value; if (H5Aread(ids.aid, H5T_NATIVE_INT, &value) >= 0) ret = api_create_integer(ctx, value); } else { type_error(ctx, " --H5T_INTEGER_?-- "); } break; case H5T_FLOAT: if (H5Tequal(ids.aid, H5T_NATIVE_FLOAT) || H5Tequal(ids.aid, H5T_IEEE_F32BE) || H5Tequal(ids.aid, H5T_IEEE_F32LE) ) { float value; if (H5Aread(ids.aid, H5T_NATIVE_FLOAT, &value) >= 0) ret = api_create_real(ctx, value); } else if (H5Tequal(ids.aid, H5T_NATIVE_DOUBLE) || H5Tequal(ids.aid, H5T_IEEE_F64BE) || H5Tequal(ids.aid, H5T_IEEE_F64LE) ) { double value; if (H5Aread(ids.aid, H5T_NATIVE_DOUBLE, &value) >= 0) ret = api_create_real(ctx, value); } else { type_error(ctx, " --H5T_FLOAT_?-- "); } break; case H5T_STRING: { zsBuffer buf(1024); hid_t atype = H5Tcopy(H5T_C_S1); H5Tset_size(atype, 1023); if (H5Aread(ids.aid, atype, buf.u.pchar) >= 0) { buf.u.pchar[1023] = 0; ret = api_create_string(ctx, buf.u.pchar); } H5Tclose(atype); } break; default: type_error(ctx, " --NON INTEGER/FLOAT/STRING ATTRIBUTE-- "); break; } } else if (ids.ndim == 1) { zsBuffer buf(ids.dims[0]*sizeof(double)); switch (H5Tget_class(ids.tid)) { case H5T_INTEGER: if (H5Tequal(ids.aid, H5T_NATIVE_SCHAR) || H5Tequal(ids.aid, H5T_STD_I8BE) || H5Tequal(ids.aid, H5T_STD_I8LE) ) { if (H5Aread(ids.aid, H5T_NATIVE_SCHAR, buf.u.ptr) >= 0) { ret = api_create_array(ctx, ids.dims[0]); for (int i = 0; i < ids.dims[0]; i++) { api_set_array_object2(ctx, ret, i, api_create_integer(0, buf.u.pchar[i])); } } } else if (H5Tequal(ids.aid, H5T_NATIVE_UCHAR) || H5Tequal(ids.aid, H5T_STD_U8BE) || H5Tequal(ids.aid, H5T_STD_U8LE) ) { if (H5Aread(ids.aid, H5T_NATIVE_UCHAR, buf.u.ptr) >= 0) { ret = api_create_array(ctx, ids.dims[0]); for (int i = 0; i < ids.dims[0]; i++) { api_set_array_object2(ctx, ret, i, api_create_integer(0, buf.u.puchar[i])); } } } else if (H5Tequal(ids.aid, H5T_NATIVE_SHORT) || H5Tequal(ids.aid, H5T_STD_I16BE) || H5Tequal(ids.aid, H5T_STD_I16LE) ) { if (H5Aread(ids.aid, H5T_NATIVE_SHORT, buf.u.ptr) >= 0) { ret = api_create_array(ctx, ids.dims[0]); for (int i = 0; i < ids.dims[0]; i++) { api_set_array_object2(ctx, ret, i, api_create_integer(0, buf.u.pshort[i])); } } } else if (H5Tequal(ids.aid, H5T_NATIVE_USHORT) || H5Tequal(ids.aid, H5T_STD_U16BE) || H5Tequal(ids.aid, H5T_STD_U16LE) ) { if (H5Aread(ids.aid, H5T_NATIVE_USHORT, buf.u.ptr) >= 0) { ret = api_create_array(ctx, ids.dims[0]); for (int i = 0; i < ids.dims[0]; i++) { api_set_array_object2(ctx, ret, i, api_create_integer(0, buf.u.pushort[i])); } } } else if (H5Tequal(ids.aid, H5T_NATIVE_INT) || H5Tequal(ids.aid, H5T_STD_I32BE) || H5Tequal(ids.aid, H5T_STD_I32LE) ) { if (H5Aread(ids.aid, H5T_NATIVE_INT, buf.u.ptr) >= 0) { ret = api_create_array(ctx, ids.dims[0]); for (int i = 0; i < ids.dims[0]; i++) { api_set_array_object2(ctx, ret, i, api_create_integer(0, buf.u.pint[i])); } } } else if (H5Tequal(ids.aid, H5T_NATIVE_UINT) || H5Tequal(ids.aid, H5T_STD_U32BE) || H5Tequal(ids.aid, H5T_STD_U32LE) ) { if (H5Aread(ids.aid, H5T_NATIVE_UINT, buf.u.ptr) >= 0) { ret = api_create_array(ctx, ids.dims[0]); for (int i = 0; i < ids.dims[0]; i++) { api_set_array_object2(ctx, ret, i, api_create_integer(0, buf.u.puint[i])); } } } else { type_error(ctx, " --H5T_INTEGER_?-- "); } break; case H5T_FLOAT: if (H5Tequal(ids.aid, H5T_NATIVE_FLOAT) || H5Tequal(ids.aid, H5T_IEEE_F32BE) || H5Tequal(ids.aid, H5T_IEEE_F32LE) ) { if (H5Aread(ids.aid, H5T_NATIVE_FLOAT, buf.u.ptr) >= 0) { ret = api_create_array(ctx, ids.dims[0]); for (int i = 0; i < ids.dims[0]; i++) { api_set_array_object2(ctx, ret, i, api_create_real(0, buf.u.pfloat[i])); } } } else if (H5Tequal(ids.aid, H5T_NATIVE_DOUBLE) || H5Tequal(ids.aid, H5T_IEEE_F64BE) || H5Tequal(ids.aid, H5T_IEEE_F64LE) ) { if (H5Aread(ids.aid, H5T_NATIVE_DOUBLE, buf.u.ptr) >= 0) { ret = api_create_array(ctx, ids.dims[0]); for (int i = 0; i < ids.dims[0]; i++) { api_set_array_object2(ctx, ret, i, api_create_real(0, buf.u.pdouble[i])); } } } else { type_error(ctx, " --H5T_FLOAT_?-- "); } break; default: type_error(ctx, " --NON INTEGER/FLOAT ARRAY ATTRIBUTE-- "); } } else { api_runtime_error2(ctx, name, ": number of dimensions of the attribute > 1"); } return ret; } void* hdf_putatt(void *ctx, int nargs, void** args) { if (nargs < 3) api_input_error(ctx); zsHDF *o = (zsHDF*)api_get_user(ctx, args[0], HDF_TYPE); const char *name = api_get_string(ctx, args[1]); hid_t id = o->did; if (!o->flag) id = o->gid; H5Adelete(id, name); zsAttID ids(-1, 0); hid_t status = -1; if (api_is_real(args[2])) { // e.g., hdf.name = 1.23; double value = api_get_real(ctx, args[2]); ids.sid = H5Screate(H5S_SCALAR); ids.aid = H5Acreate(id, name, H5T_NATIVE_DOUBLE, ids.sid, H5P_DEFAULT); if (ids.aid > 0) status = H5Awrite(ids.aid, H5T_NATIVE_DOUBLE, &value); } else if (api_is_integer(args[2])) { // e.g., hdf.name = 123; int value = api_get_integer(ctx, args[2]); ids.sid = H5Screate(H5S_SCALAR); ids.aid = H5Acreate(id, name, H5T_NATIVE_INT, ids.sid, H5P_DEFAULT); if (ids.aid > 0) status = H5Awrite(ids.aid, H5T_NATIVE_INT, &value); } else if (api_is_string(args[2])) { // e.g., hdf.name = "my property"; const char *ptr = api_get_string(ctx, args[2]); ids.sid = H5Screate(H5S_SCALAR); ids.tid = H5Tcopy(H5T_C_S1); H5Tset_size(ids.tid, strlen(ptr)); ids.aid = H5Acreate(id, name, ids.tid, ids.sid, H5P_DEFAULT); if (ids.aid > 0) status = H5Awrite(ids.aid, ids.tid, ptr); } else if (api_is_array(args[2])) { // e.g., hdf.name = [1, 2.0, 3.3]; ids.dims[1] = api_get_array_size(ctx, args[2]); if (ids.dims[0] == 0 || ids.dims[0] > 256) api_runtime_error(ctx, "unexpected number of attributes"); zsBuffer br(ids.dims[0]*sizeof(double)), bi(ids.dims[0]*sizeof(int)); bool real_flag = false; for (int i = 0; i < ids.dims[0]; i++) { void *o = api_get_array_object2(ctx, args[2], i); if (api_is_real(o)) { br.u.pdouble[i] = api_get_real(ctx, o); real_flag = true; } else { bi.u.pint[i] = api_get_integer(ctx, o); br.u.pdouble[i] = bi.u.pint[i]; } } ids.sid = H5Screate_simple(1, ids.dims, NULL); if (real_flag) { ids.aid = H5Acreate(id, name, H5T_NATIVE_DOUBLE, ids.sid, 0); if (ids.aid > 0) status = H5Awrite(ids.aid, H5T_NATIVE_DOUBLE, br.u.pdouble); } else { ids.aid = H5Acreate(id, name, H5T_NATIVE_INT, ids.sid, 0); if (ids.aid > 0) status = H5Awrite(ids.aid, H5T_NATIVE_INT, bi.u.pint); } } if (status < 0) api_runtime_error(ctx, "failed to write attribute"); return 0; } void* hdf_get(void *ctx, int nargs, void** args) { if (nargs < 2) api_input_error(ctx); if (api_is_string(args[1])) { // hdf.name return hdf_getatt(ctx, nargs, args); } // hdf[...] zsHDF *o = (zsHDF*)api_get_user(ctx, args[0], HDF_TYPE); o->checkindex(ctx, nargs, args); o->checksize(); o->hyperslab(ctx); if (H5Dread(o->did, o->tid, o->mid, o->sid, H5P_DEFAULT, o->ptr) < 0) api_runtime_error(ctx, "failed to read data"); if (o->ns == 1) { switch (o->type) { case HDF_CHAR: return api_create_integer(ctx, ((char*)o->ptr)[0]); case HDF_UCHAR: return api_create_integer(ctx, ((unsigned char*)o->ptr)[0]); case HDF_SHORT: return api_create_integer(ctx, ((short*)o->ptr)[0]); case HDF_USHORT: return api_create_integer(ctx, ((unsigned short*)o->ptr)[0]); case HDF_INT: return api_create_integer(ctx, ((int*)o->ptr)[0]); case HDF_UINT: return api_create_integer(ctx, ((unsigned int*)o->ptr)[0]); case HDF_FLOAT: return api_create_real(ctx, ((float*)o->ptr)[0]); case HDF_DOUBLE: return api_create_real(ctx, ((double*)o->ptr)[0]); case HDF_STRING: ((char*)o->ptr)[o->tsize] = 0; return api_create_string(ctx, (char*)o->ptr); default: type_error(ctx, " --HDF_?-- "); } } if (o->type == HDF_STRING) { void *ret = api_create_array(ctx, o->ns); char *ptr = (char*)o->ptr; zsBuffer buf(o->tsize+1); buf.u.pchar[o->tsize] = 0; for (int i=0; ins; i++) { strncpy(buf.u.pchar, ptr, o->tsize); api_set_array_object2(ctx, ret, i, api_create_string(0,buf.u.pchar)); ptr += o->tsize; } return ret; } return api_create_user(ctx, o->ptr, 0, 0, 0); } void* hdf_set(void *ctx, int nargs, void** args) { if (nargs < 3) api_input_error(ctx); if (api_is_string(args[1])) { // hdf.name = attribute return hdf_putatt(ctx, nargs, args); } // hdf[...] zsHDF *o = (zsHDF*)api_get_user(ctx, args[0], HDF_TYPE); o->checkindex(ctx, nargs-1, args); o->hyperslab(ctx); hid_t status = -1; if (api_is_user(args[nargs-1])) { // hdf[...] = ptr; void *ptr = api_get_ptr(ctx, args[nargs-1]); status = H5Dwrite(o->did, o->tid, o->mid, o->sid, H5P_DEFAULT, ptr); } else { // hdf[...] = value; zsBuffer buf(o->ns*o->tsize); real_t value; const char *str; hsize_t k, i, l; switch (o->type) { case HDF_CHAR: value = api_get_number(ctx, args[nargs-1]); for (k = 0; k < o->ns; k++) buf.u.pchar[k] = char(value); break; case HDF_UCHAR: value = api_get_number(ctx, args[nargs-1]); for (k = 0; k < o->ns; k++) buf.u.puchar[k] = unsigned char(value); break; case HDF_SHORT: value = api_get_number(ctx, args[nargs-1]); for (k = 0; k < o->ns; k++) buf.u.pshort[k] = short(value); break; case HDF_USHORT: value = api_get_number(ctx, args[nargs-1]); for (k = 0; k < o->ns; k++) buf.u.pushort[k] = unsigned short(value); break; case HDF_INT: value = api_get_number(ctx, args[nargs-1]); for (k = 0; k < o->ns; k++) buf.u.pint[k] = int(value); break; case HDF_UINT: value = api_get_number(ctx, args[nargs-1]); for (k = 0; k < o->ns; k++) buf.u.puint[k] = unsigned int(value); break; case HDF_FLOAT: value = api_get_number(ctx, args[nargs-1]); for (k = 0; k < o->ns; k++) buf.u.pfloat[k] = float(value); break; case HDF_DOUBLE: value = api_get_number(ctx, args[nargs-1]); for (k = 0; k < o->ns; k++) buf.u.pdouble[k] = double(value); break; case HDF_STRING: str = api_get_string(ctx, args[nargs-1]); l = strlen(str); i = 0; for (k = 0; k < o->ns; k++) { buf.u.pchar[k] = str[i]; i++; i %= l; } break; default: type_error(ctx, " --HDF_?-- "); } status = H5Dwrite(o->did, o->tid, o->mid, o->sid, H5P_DEFAULT, buf.u.ptr); } if (status < 0) api_runtime_error(ctx, "failed to write to dataset"); return 0; } void* hdf_cmm(void *ctx, int nargs, void** args) { if (nargs < 1) api_input_error(ctx); zsHDF *o = (zsHDF*)api_get_user(ctx, args[0], HDF_TYPE); hid_t id = o->did; if (!o->flag) id = o->gid; if (nargs == 1) { zsBuffer buf(BUFF_SIZE); if (H5Gget_comment(id, ".", BUFF_SIZE-1, buf.u.pchar) < 0) api_runtime_error(ctx, "failed to read comment"); return api_create_string(ctx, buf.u.pchar); } if (H5Gset_comment(id, ".", api_get_string(ctx, args[1])) < 0) api_runtime_error(ctx, "failed to write comment"); return 0; } void write_space(FILE *fp, int n) { for (int k = 0; k < n; k++) fputc(' ', fp); } void list_attribute(hid_t id, FILE *fp, int nc, void *ctx, void *func) { zsBuffer buf(BUFF_SIZE); zsBuffer buf2(BUFF_SIZE); unsigned int k, n = H5Aget_num_attrs(id); for (k = 0; k < n; k++) { hid_t aid = H5Aopen_idx(id, k); if (aid < 0) continue; H5Aget_name(aid, BUFF_SIZE-1, buf.u.pchar); buf.u.pchar[BUFF_SIZE-1] = 0; hid_t tid = H5Aget_type(aid); if (tid < 0) { H5Aclose(aid); continue; } bool flag = false; hid_t sid = 0, atype = 0; switch (H5Tget_class(tid)) { case H5T_INTEGER: sid = H5Aget_space(aid); if (sid > 0) { int ndim = H5Sget_simple_extent_ndims(sid); if (ndim == 0) { int value; if (H5Aread(aid, H5T_NATIVE_INT, &value) >= 0) { flag = true; if (func) { void *args[3]; args[0] = api_create_string(ctx, "attribute"); args[1] = api_create_string(ctx, buf.u.pchar); args[2] = api_create_integer(ctx, value); api_call_func(ctx, func, 3, args); } else { write_space(fp, nc); fprintf(fp, "%s=%d\n", buf.u.pchar, value); } } } } H5Sclose(sid); break; case H5T_FLOAT: sid = H5Aget_space(aid); if (sid > 0) { int ndim = H5Sget_simple_extent_ndims(sid); if (ndim == 0) { double value; if (H5Aread(aid, H5T_NATIVE_DOUBLE, &value) >= 0) flag = true; if (func) { void *args[3]; args[0] = api_create_string(ctx, "attribute"); args[1] = api_create_string(ctx, buf.u.pchar); args[2] = api_create_real(ctx, value); api_call_func(ctx, func, 3, args); } else { write_space(fp, nc); fprintf(fp, "%s=%f\n", buf.u.pchar, value); } } } H5Sclose(sid); break; case H5T_STRING: atype = H5Tcopy(H5T_C_S1); H5Tset_size(atype, BUFF_SIZE-1); if (H5Aread(aid, atype, buf2.u.pchar) >= 0) { buf2.u.pchar[BUFF_SIZE-1] = 0; flag = true; if (func) { void *args[3]; args[0] = api_create_string(ctx, "attribute"); args[1] = api_create_string(ctx, buf.u.pchar); args[2] = api_create_string(ctx, buf2.u.pchar); api_call_func(ctx, func, 3, args); } else { write_space(fp, nc); fprintf(fp, "%s=%s\n", buf.u.pchar, buf2.u.pchar); } } H5Tclose(atype); break; default: if (!func) { write_space(fp, nc); fprintf(fp, "%s=?\n", buf.u.pchar); } } H5Tclose(tid); H5Aclose(aid); } fflush(fp); } void list_dataset(hid_t gid, const char *name, FILE *fp, int nc, void *ctx, void *func) { hid_t did = H5Dopen(gid, name); if (did < 0) return; if (func) { void *args[2]; args[0] = api_create_string(ctx, "dataset"); args[1] = api_create_string(ctx, name); api_call_func(ctx, func, 2, args); } else { write_space(fp, nc); fprintf(fp, "%s(", name); hid_t sid = H5Dget_space(did); if (sid > 0) { hsize_t dims[H5S_MAX_RANK]; int k, ndim = H5Sget_simple_extent_dims(sid, dims, 0); for (k = 0; k < ndim; k++) { if (k == 0) fprintf(fp,"%d", dims[k]); else fprintf(fp,",%d", dims[k]); } } fprintf(fp, ")\n"); fflush(fp); H5Sclose(sid); } list_attribute(did, fp, nc+4, ctx, func); H5Dclose(did); } void list_group(hid_t gid, const char *name, FILE *fp, int nc, void *ctx, void *func) { hsize_t k, n; zsBuffer buf(BUFF_SIZE); hid_t id = gid; if (name) { if (func) { void *args[2]; args[0] = api_create_string(ctx, "group"); args[1] = api_create_string(ctx, name); api_call_func(ctx, func, 2, args); } else { write_space(fp, nc); fprintf(fp, "%s\n", name); } id = H5Gopen(gid, name); if (id < 0) return; nc += 4; } if (H5Gget_comment(id, ".", BUFF_SIZE-1, buf.u.pchar) > 0) { if (func) { void *args[2]; args[0] = api_create_string(ctx, "comment"); args[1] = api_create_string(ctx, buf.u.pchar); api_call_func(ctx, func, 2, args); } else { write_space(fp, nc); fprintf(fp, "comment: %s\n", buf.u.pchar); } } H5Gget_num_objs(id, &n); for (k = 0; k < n; k++) { H5Gget_objname_by_idx(id, k, buf.u.pchar, BUFF_SIZE-1); buf.u.pchar[BUFF_SIZE-1] = 0; hid_t type = H5Gget_objtype_by_idx(id, k); switch(type) { case H5G_LINK: if (!func) { write_space(fp, nc); fprintf(fp, "%s is a link\n", buf.u.pchar); } break; case H5G_GROUP: list_group(id, buf.u.pchar, fp, nc, ctx, func); break; case H5G_DATASET: list_dataset(id, buf.u.pchar, fp, nc, ctx, func); break; case H5G_TYPE: if (!func) { write_space(fp, nc); fprintf(fp, "%s is a datatype\n", buf.u.pchar); } break; default: if (!func) { write_space(fp, nc); fprintf(fp, "%s is ?\n", buf.u.pchar); } } H5Tclose(type); } list_attribute(id, fp, nc, ctx, func); if (name) H5Gclose(id); } void* hdf_list(void *ctx, int nargs, void** args) { if (nargs < 1) api_input_error(ctx); zsHDF *o = (zsHDF*)api_get_user(ctx, args[0], HDF_TYPE); void *func = 0; if (nargs > 1) func = api_get_func(ctx, api_get_string(ctx,args[1])); list_group(o->gid, 0, stdout, 0, ctx, func); return 0; } struct iter_s { void *ctx; void *func; const char *name; }; herr_t scan_group(hid_t loc_id, const char *name, void *opdata) { H5G_stat_t statbuf; H5Gget_objinfo(loc_id, name, 0, &statbuf); iter_s *iter = (iter_s*)opdata; void *p[3]; p[1] = api_create_string(iter->ctx, iter->name); p[2] = api_create_string(iter->ctx, name); switch (statbuf.type) { case H5G_GROUP: p[0] = api_create_string(iter->ctx, "GROUP"); break; case H5G_DATASET: p[0] = api_create_string(iter->ctx, "DATASET"); break; default: p[0] = api_create_string(iter->ctx, "DEFAULT"); } void *ret = api_call_func(iter->ctx, iter->func, 3, p); if (api_is_integer(ret)) { return !api_get_integer(iter->ctx, ret); } return 0; } void* hdf_scan(void *ctx, int nargs, void** args) { if (nargs < 3) api_input_error(ctx); zsHDF *o = (zsHDF*)api_get_user(ctx, args[0], HDF_TYPE); const char *fname = api_get_string(ctx,args[1]); const char *gname = api_get_string(ctx,args[2]); zsBuffer buf(strlen(gname)+2); strcpy(buf.u.pchar, gname); iter_s iter = { ctx, api_get_func(ctx,fname), buf.u.pchar }; int idx = 0; H5Giterate(o->fid, buf.u.pchar, &idx, scan_group, &iter); return 0; } ///////////////////////////////////////////////////////////////////// class zsRegPrimitive { public: zsRegPrimitive() { api_add_primitive("hdf", 0, hdf_open); api_add_primitive("version", HDF_TYPE, hdf_version); api_add_primitive("group", HDF_TYPE, hdf_group); api_add_primitive("dataset", HDF_TYPE, hdf_dataset); api_add_primitive("size", HDF_TYPE, hdf_size); api_add_primitive("dims", HDF_TYPE, hdf_dims); api_add_primitive("__get", HDF_TYPE, hdf_get); api_add_primitive("__set", HDF_TYPE, hdf_set); api_add_primitive("cmm", HDF_TYPE, hdf_cmm); api_add_primitive("list", HDF_TYPE, hdf_list); api_add_primitive("scan", HDF_TYPE, hdf_scan); } ~zsRegPrimitive() { } }; zsRegPrimitive hdf_register;