/* Copyright 2018, UCAR/Unidata See COPYRIGHT file for copying and redistribution conditions. */ #include "config.h" #include #include #include #include #include #include /* Older versions of the hdf library may define H5PL_type_t here */ #include #include "netcdf.h" #include "netcdf_filter_hdf5_build_.h" #undef TESTODDSIZE #undef DEBUG #define FILTER_ID 32768 #define MAXERRS 8 #define MAXPARAMS 32 #define MAXDIMS 8 #define TESTFILE "testfilter_reg.nc" #define NPARAMS 1 #define PARAMVAL 17 #define NDIMS 4 static size_t dimsize[NDIMS] = {4,4,4,4}; static size_t chunksize[NDIMS] = {4,4,4,4}; static size_t ndims = NDIMS; static size_t totalproduct = 1; /* x-product over max dims */ static size_t actualproduct = 1; /* x-product over actualdims */ static size_t chunkproduct = 1; /* x-product over actual chunks */ static int nerrs = 0; static int ncid, varid; static int dimids[MAXDIMS]; static size_t odom[MAXDIMS]; static float* array = NULL; static float* expected = NULL; static unsigned int filterid = 0; static size_t nparams = 0; static unsigned int params[MAXPARAMS]; static unsigned int baseline[NPARAMS] = {PARAMVAL}; static struct Base { unsigned int id; H5Z_class2_t* info; } baseinfo; static const H5Z_class2_t H5Z_REG[1]; /* Forward */ static int filter_test1(void); static void init(int argc, char** argv); static void reset(void); static void odom_reset(void); static int odom_more(void); static int odom_next(void); static int odom_offset(void); static float expectedvalue(void); static void verifyparams(void); #define ERRR do { \ fflush(stdout); /* Make sure our stdout is synced with stderr. */ \ fprintf(stderr, "Sorry! Unexpected result, %s, line: %d\n", \ __FILE__, __LINE__); \ nerrs++;\ } while (0) static int check(int err,int line) { if(err != NC_NOERR) { fprintf(stderr,"fail (%d): %s\n",line,nc_strerror(err)); nerrs++; } return NC_NOERR; } static void report(const char* msg, int lineno) { fprintf(stderr,"fail: line=%d %s\n",lineno,msg); exit(1); } #define CHECK(x) check(x,__LINE__) #define REPORT(x) report(x,__LINE__) static int verifychunks(void) { int i; int store = -1; size_t localchunks[MAXDIMS]; memset(localchunks,0,sizeof(localchunks)); CHECK(nc_inq_var_chunking(ncid, varid, &store, localchunks)); if(store != NC_CHUNKED) { fprintf(stderr,"bad chunk store\n"); return 0; } for(i=0;iid != base->id) {stat = NC_EINVAL; fprintf(stderr,"verifyfilterinfo: id mismatch\n");} #ifdef USE_HDF5 H5Z_class2_t* h5info = (H5Z_class2_t*)info->info; H5Z_class2_t* h5base = (H5Z_class2_t*)base->info; if(h5info->id != h5base->id) {stat = NC_EINVAL; fprintf(stderr,"verifyfilterinfo: H5Z_class_t: id mismatch\n");} if(h5info->encoder_present != h5base->encoder_present) {stat = NC_EINVAL; fprintf(stderr,"verifyfilterinfo: H5Z_class_t: encoder_present mismatch\n");} if(h5info->decoder_present != h5base->decoder_present) {stat = NC_EINVAL; fprintf(stderr,"verifyfilterinfo: H5Z_class_t: decoder_present mismatch\n");} if(h5info->decoder_present != h5base->decoder_present) {stat = NC_EINVAL; fprintf(stderr,"verifyfilterinfo: H5Z_class_t: decoder_present mismatch\n");} if(strcmp(h5info->name,h5base->name) != 0) {stat = NC_EINVAL; fprintf(stderr,"verifyfilterinfo: H5Z_class_t: name mismatch\n");} if(h5info->can_apply != h5base->can_apply) {stat = NC_EINVAL; fprintf(stderr,"verifyfilterinfo: H5Z_class_t: can_apply mismatch\n");} if(h5info->set_local != h5base->set_local) {stat = NC_EINVAL; fprintf(stderr,"verifyfilterinfo: H5Z_class_t: set_local mismatch\n");} if(h5info->filter != h5base->filter) {stat = NC_EINVAL; fprintf(stderr,"verifyfilterinfo: H5Z_class_t: filter mismatch\n");} #else stat = NC_ENOTBUILT; fprintf(stderr,"Unknown format\n")} #endif return stat; } static void registerfilter(void) { int stat; struct Base inqinfo; baseinfo.id = FILTER_ID; baseinfo.info = (H5Z_class2_t*)&H5Z_REG[0]; stat = nc_filter_client_register(baseinfo.id,baseinfo.info); if(stat == NC_ENOTBUILT) { fprintf(stderr,"client side filters not implemented: test skipped\n"); exit(0); } CHECK(stat); /* Verify by inquiry */ memset(&inqinfo,0,sizeof(struct Base)); inqinfo.id = FILTER_ID; inqinfo.info = calloc(1,sizeof(H5Z_class2_t)); if(inqinfo.info == NULL) CHECK(NC_ENOMEM); CHECK((nc_filter_client_inq(inqinfo.id,(void*)inqinfo.info))); CHECK((verifyfilterinfo(&inqinfo,&baseinfo))); nullfree(inqinfo.info); } static void unregisterfilter(void) { int stat = NC_NOERR; struct Base inqinfo; /* Verify that the filter info is still good */ memset(&inqinfo,0,sizeof(struct Base)); inqinfo.id = FILTER_ID; inqinfo.info = calloc(1,sizeof(H5Z_class2_t)); if(inqinfo.info == NULL) CHECK(NC_ENOMEM); CHECK((stat=nc_filter_client_inq(inqinfo.id,(void*)inqinfo.info))); CHECK((verifyfilterinfo(&inqinfo,&baseinfo))); /* Unregister */ inqinfo.id = FILTER_ID; CHECK((stat = nc_filter_client_unregister(inqinfo.id))); /* Inq again to verify unregistered */ inqinfo.id = FILTER_ID; stat=nc_filter_client_inq(inqinfo.id,(void*)inqinfo.info); if(stat != NC_ENOFILTER) { fprintf(stderr,"unregister: failed\n"); CHECK(NC_EFILTER); } nullfree(inqinfo.info); } static void setvarfilter(void) { /* NOOP the params */ CHECK(nc_def_var_filter(ncid,varid,FILTER_ID,NPARAMS,baseline)); verifyparams(); } static void verifyparams(void) { int i; CHECK(nc_inq_var_filter(ncid,varid,&filterid,&nparams,params)); if(filterid != FILTER_ID) REPORT("id mismatch"); if(nparams != NPARAMS) REPORT("nparams mismatch"); for(i=0;i 0) { params = (unsigned int*)malloc(sizeof(unsigned int)*nparams); if(params == NULL) return NC_ENOMEM; CHECK(nc_inq_var_filter(ncid,varid,&filterid,&nparams,params)); } if(filterid != FILTER_ID) { fprintf(stderr,"open: test id mismatch: %d\n",filterid); return NC_EFILTER; } if(nparams != NPARAMS) { size_t i; unsigned int inqparams[MAXPARAMS]; fprintf(stderr,"nparams mismatch\n"); for(nerrs=0,i=0;i 0) return NC_EFILTER; if(params) free(params); /* Verify chunking */ if(!verifychunks()) return 0; fflush(stderr); return 1; } static int setchunking(void) { int store; store = NC_CHUNKED; CHECK(nc_def_var_chunking(ncid,varid,store,chunksize)); if(!verifychunks()) return NC_EINVAL; return NC_NOERR; } static void fill(void) { odom_reset(); if(1) { int i; if(actualproduct <= 1) abort(); for(i=0;i= MAXERRS) break; } } } else { odom_reset(); while(odom_more()) { int offset = odom_offset(); float expect = expectedvalue(); if(array[offset] != expect) { fprintf(stderr,"data mismatch: array[%d]=%f expected=%f\n", offset,array[offset],expect); errs++; if(errs >= MAXERRS) break; } odom_next(); } } if(errs == 0) fprintf(stderr,"no data errors\n"); return (errs == 0); } static void showparameters(void) { int i; fprintf(stderr,"test: nparams=%ld: params=",(unsigned long)nparams); for(i=0;i=0;i--) { odom[i] += 1; if(odom[i] < dimsize[i]) break; if(i == 0) return 0; /* leave the 0th entry if it overflows*/ odom[i] = 0; /* reset this position*/ } return 1; } static int odom_offset(void) { int i; int offset = 0; for(i=0;i 0?1:0); } /**************************************************/ /* In-line filter code */ #define H5Z_FILTER_REG FILTER_ID #ifndef DLL_EXPORT #define DLL_EXPORT #endif static int paramcheck(size_t nparams, const unsigned int* params); /* Forward */ static int paramcheck(size_t nparams, const unsigned int* params); /* Make this explicit */ /* * The "can_apply" callback returns positive a valid combination, zero for an * invalid combination and negative for an error. */ static htri_t H5Z_reg_can_apply(hid_t dcpl_id, hid_t type_id, hid_t space_id) { return 1; /* Assume it can always apply */ } /* As a filter, it is the identity function, passing input to output unchanged. */ size_t H5Z_filter_reg(unsigned int flags, size_t cd_nelmts, const unsigned int cd_values[], size_t nbytes, size_t *buf_size, void **buf) { void* newbuf; if(cd_nelmts == 0) goto fail; if(!paramcheck(cd_nelmts,cd_values)) goto fail; fprintf(stderr,"nbytes=%ld\n",(long)nbytes); if (flags & H5Z_FLAG_REVERSE) { /* Replace buffer */ newbuf = H5allocate_memory(*buf_size,0); if(newbuf == NULL) abort(); if(*buf != NULL) { memcpy(newbuf,*buf,*buf_size); /* reclaim old buffer */ H5free_memory(*buf); } *buf = newbuf; } else { /* Replace buffer */ newbuf = H5allocate_memory(*buf_size,0); if(newbuf == NULL) abort(); if(*buf != NULL) { memcpy(newbuf,*buf,*buf_size); /* reclaim old buffer */ H5free_memory(*buf); } *buf = newbuf; } return *buf_size; fail: return 0; } static int paramcheck(size_t nparams, const unsigned int* params) { if(nparams != 1) { fprintf(stderr,"Incorrect parameter count: need=1 sent=%ld\n",(unsigned long)nparams); goto fail; } return 1; fail: return 0; } static const H5Z_class2_t H5Z_REG[1] = {{ H5Z_CLASS_T_VERS, /* H5Z_class_t version */ (H5Z_filter_t)(H5Z_FILTER_REG), /* Filter id number */ 1, /* encoder_present flag (set to true) */ 1, /* decoder_present flag (set to true) */ "registered", /* Filter name for debugging */ (H5Z_can_apply_func_t)H5Z_reg_can_apply, /* The "can apply" callback */ NULL, /* The "set local" callback */ (H5Z_func_t)H5Z_filter_reg, /* The actual filter function */ }};