diff --git a/docs/filters.md b/docs/filters.md index bcc4085b87..cb4bfb17a8 100644 --- a/docs/filters.md +++ b/docs/filters.md @@ -508,6 +508,85 @@ for use by client programs and by filter implementations. Examples of the use of these functions can be seen in the test program *nc_test4/tst_filterparser.c*. +Appendix B. Programmatic Filter Definition {#filters_programmatic} +========== + +HDF5 provides an API [6] to allow for the programmatic definition +of filters -- as opposed to using the HDF5_PLUGIN_PATH environment variable. +The idea is that instead of using dynamic shared libraries, the filter code +is compiled into the application and the relevant information +(namely an instance of *H5Z_class2_t*) is passed to the HDF5 library API. +Because it is anticipated that in the future, other plugin formats +will be used, this netcdf-c API is deliberately more general than +strictly required by HDF5. + +## API Concepts + +Three concepts are used in this API. + +1. Format - this is an integer defining the format of the plugin. + Currently, only *NC_FILTER_FORMAT_HDF5* is defined and corresponds + to the existing HDF5 plugin format. +2. ID - this is an integer that is a unique identifier for the filter. + This value is interpreted in the context of the format, so the same + id might be assigned to different filters if the format is different. +3. The structure *NC_FILTER_INFO* that provides generic information + to the API and has a placeholder for format-specific information. + + typedef struct NC_FILTER_INFO { + int version; /* Of this structure */ + int format; /* Controls actual type of this structure */ + int id; /* Must be unique WRT format */ + void* info; /* The filter info as defined by the format. */ + } NC_FILTER_INFO; + When the format is the value NC_FILTER_FORMAT_HDF5, + then the info field is a pointer to an instance of + H5Z_class2_t as define in H5Zpublic.h. + The use of void* is, of course, to allow for passing arbitrary objects. + +### NetCDF API + +The following function signatures are provided (see *netcdf_filter.h*). + +1. Register a filter + + int nc_filter_register(NC_FILTER_INFO* filter_info); + Register a filter whose format and ID are specified in the 'filter_info' + argument. + +2. Unregister a filter + + int nc_filter_unregister(int format, int id); + Unregister the filter specified by the id. Note that only + filters registered using 'nc_filter_register' can be unregistered. + +3. Inquire about a filter + + int nc_filter_inq(int format, int id, NC_FILTER_INFO* filter_info); + Unregister the filter specified by the id. Note that only + filters registered using 'nc_filter_register' can be inquired. + The 'filter_info' is filled with a copy of the original argument to + 'nc_filter_register'. + +### Example + + static const H5Z_class2_t H5Z_REG[1] = { + ... + }; + ... + NC_FILTER_INFO info; + ... + info.version = NC_FILTER_INFO_VERSION; + info.format = NC_FILTER_FORMAT_HDF5; + info.id = FILTER_ID; + info.info = (void*)&H5Z_REG[0]; + stat = nc_filter_register(&info); + ... + memset(&info,0,sizeof(NC_FILTER_INFO)); + stat = nc_filter_inq(NC_FILTER_FORMAT_HDF5, FILTER_ID, &info); + ... + stat = nc_filter_unregister(NC_FILTER_FORMAT_HDF5, FILTER_ID); + # References {#filters_References} 1. https://support.hdfgroup.org/HDF5/doc/Advanced/DynamicallyLoadedFilters/HDF5DynamicallyLoadedFilters.pdf @@ -515,6 +594,7 @@ Examples of the use of these functions can be seen in the test program 3. https://portal.hdfgroup.org/display/support/Contributions#Contributions-filters 4. https://support.hdfgroup.org/services/contributions.html#filters 5. https://support.hdfgroup.org/HDF5/doc/RM/RM_H5.html +6. https://confluence.hdfgroup.org/display/HDF5/Filters # Point of Contact diff --git a/include/hdf5internal.h b/include/hdf5internal.h index 073e0f3f85..80ad136acf 100644 --- a/include/hdf5internal.h +++ b/include/hdf5internal.h @@ -18,6 +18,7 @@ #include "ncdimscale.h" #include "nc4dispatch.h" #include "hdf5dispatch.h" +#include "netcdf_filter.h" #define NC_MAX_HDF5_NAME (NC_MAX_NAME + 10) @@ -51,6 +52,11 @@ /** This is the name of the name HDF5 dimension scale attribute. */ #define HDF5_DIMSCALE_NAME_ATT_NAME "NAME" +/** Define Filter API Operations */ +#define FILTER_REG 1 +#define FILTER_UNREG 2 +#define FILTER_INQ 3 + /** Struct to hold HDF5-specific info for the file. */ typedef struct NC_HDF5_FILE_INFO { hid_t hdfid; @@ -163,9 +169,13 @@ int nc4_hdf5_find_grp_h5_var(int ncid, int varid, NC_FILE_INFO_T **h5, /* Perform lazy read of the rest of the metadata for a var. */ int nc4_get_var_meta(NC_VAR_INFO_T *var); + +/* Define Filter API Function */ +int nc4_filter_action(int action, int formatx, int id, NC_FILTER_INFO* info); /* Support functions for provenance info (defined in nc4hdf.c) */ extern int NC4_hdf5get_libversion(unsigned*,unsigned*,unsigned*);/*libsrc4/nc4hdf.c*/ extern int NC4_hdf5get_superblock(struct NC_FILE_INFO*, int*);/*libsrc4/nc4hdf.c*/ extern int NC4_isnetcdf4(struct NC_FILE_INFO*); /*libsrc4/nc4hdf.c*/ + #endif /* _HDF5INTERNAL_ */ diff --git a/include/netcdf_filter.h b/include/netcdf_filter.h index 13f811925b..ca33e4bfaf 100644 --- a/include/netcdf_filter.h +++ b/include/netcdf_filter.h @@ -11,6 +11,25 @@ #define H5Z_FILTER_SZIP 4 #endif +/* Define the known filter formats */ +#define NC_FILTER_FORMAT_HDF5 1 /* Use the H5Z_class2_t format */ + +/* Note that this structure can be extended + in the usual C way if the first field of the extended + struct is of type NC_FILTER_INFO +*/ +typedef struct NC_FILTER_INFO { + int version; /* Of this structure */ +# define NC_FILTER_INFO_VERSION 1 + int format; /* Controls actual type of this structure */ + int id; /* Must be unique WRT format */ + void* info; /* The filter info as defined by the format. + For format == NC_FILTER_FORMAT_HDF5, + this must conform to H5Z_class2_t in H5Zpublic.h; + Defined as void* to avoid specifics. + */ +} NC_FILTER_INFO; + #if defined(__cplusplus) extern "C" { #endif @@ -20,6 +39,11 @@ EXTERNL int NC_parsefilterspec(const char* spec, unsigned int* idp, size_t* npar EXTERNL void NC_filterfix8(unsigned char* mem, int decode); +/* Support direct user defined filters */ +EXTERNL int nc_filter_register(NC_FILTER_INFO* filter_info); +EXTERNL int nc_filter_unregister(int format, int id); +EXTERNL int nc_filter_inq(int format, int id, NC_FILTER_INFO* filter_info); + #if defined(__cplusplus) } #endif diff --git a/libdispatch/dfilter.c b/libdispatch/dfilter.c index aae6ce6b92..26b2903bfc 100644 --- a/libdispatch/dfilter.c +++ b/libdispatch/dfilter.c @@ -14,6 +14,10 @@ #include "netcdf.h" #include "netcdf_filter.h" +#ifdef USE_NETCDF4 +#include "hdf5internal.h" +#endif + /* Common utilities related to filters. */ @@ -262,3 +266,62 @@ NC_filterfix8(unsigned char* mem, int decode) /* No action is necessary */ #endif } + +/**************************************************/ +/* Support direct user defined filters */ + +EXTERNL int +nc_filter_register(NC_FILTER_INFO* filter) +{ + int stat = NC_NOERR; + if(filter == NULL) + return NC_EINVAL; + switch (filter->format) { + case NC_FILTER_FORMAT_HDF5: +#ifdef USE_NETCDF4 + stat = nc4_filter_action(FILTER_REG, filter->format, filter->id, filter); +#else + stat = NC_ENOTBUILT; +#endif + break; + default: + stat = NC_EINVAL; + } + return stat; +} + +EXTERNL int +nc_filter_unregister(int fformat, int id) +{ + int stat = NC_NOERR; + switch (fformat) { + case NC_FILTER_FORMAT_HDF5: +#ifdef USE_NETCDF4 + stat = nc4_filter_action(FILTER_UNREG, fformat, id, NULL); +#else + stat = NC_ENOTBUILT; +#endif + break; + default: + stat = NC_EINVAL; + } + return stat; +} + +EXTERNL int +nc_filter_inq(int fformat, int id, NC_FILTER_INFO* filter_info) +{ + int stat = NC_NOERR; + switch (fformat) { + case NC_FILTER_FORMAT_HDF5: +#ifdef USE_NETCDF4 + stat = nc4_filter_action(FILTER_INQ, fformat, id, filter_info); +#else + stat = NC_ENOTBUILT; +#endif + break; + default: + stat = NC_EINVAL; + } + return stat; +} diff --git a/libhdf5/nc4hdf.c b/libhdf5/nc4hdf.c index 6b496094c6..62cdb00660 100644 --- a/libhdf5/nc4hdf.c +++ b/libhdf5/nc4hdf.c @@ -25,6 +25,11 @@ #define NC_HDF5_MAX_NAME 1024 /**< @internal Max size of HDF5 name. */ +/* WARNING: GLOBAL VARIABLE */ + +/* Define list of registered filters */ +static NClist* filters = NULL; + /** * @internal Flag attributes in a linked list as dirty. * @@ -2638,3 +2643,122 @@ NC4_walk(hid_t gid, int* countp) } return ncstat; } + + +/**************************************************/ +/* Filter registration support */ + +static int +filterlookup(int id) +{ + int i; + if(filters == NULL) + filters = nclistnew(); + for(i=0;iid == id) return i; /* return position */ + } + return -1; +} + +static void +reclaiminfo(NC_FILTER_INFO* info) +{ + if(info != NULL) + nullfree(info->info); + nullfree(info); +} + +static int +filterremove(int pos) +{ + NC_FILTER_INFO* info = NULL; + if(filters == NULL) + filters = nclistnew(); + if(pos < 0 || pos >= nclistlength(filters)) + return NC_EINVAL; + info = nclistget(filters,pos); + reclaiminfo(info); + nclistremove(filters,pos); + return NC_NOERR; +} + +static NC_FILTER_INFO* +dupfilterinfo(NC_FILTER_INFO* info) +{ + NC_FILTER_INFO* dup = NULL; + if(info == NULL) goto fail; + if(info->info == NULL) goto fail; + if((dup = calloc(1,sizeof(NC_FILTER_INFO))) == NULL) goto fail; + *dup = *info; + if((dup->info = calloc(1,sizeof(H5Z_class2_t))) == NULL) goto fail; + { + H5Z_class2_t* h5dup = (H5Z_class2_t*)dup->info; + H5Z_class2_t* h5info = (H5Z_class2_t*)info->info; + *h5dup = *h5info; + } + return dup; +fail: + reclaiminfo(dup); + return NULL; +} + +int +nc4_filter_action(int op, int format, int id, NC_FILTER_INFO* info) +{ + int stat = NC_NOERR; + H5Z_class2_t* h5filterinfo = NULL; + herr_t herr; + int pos = -1; + NC_FILTER_INFO* dup = NULL; + + if(format != NC_FILTER_FORMAT_HDF5) + {stat = NC_ENOTNC4; goto done;} + + switch (op) { + case FILTER_REG: /* Ignore id argument */ + if(info == NULL || info->info == NULL) + {stat = NC_EINVAL; goto done;} + if(info->version != NC_FILTER_INFO_VERSION + || info->format != NC_FILTER_FORMAT_HDF5) + {stat = NC_ENOTNC4; goto done;} + h5filterinfo = info->info; + /* Another sanity check */ + if(info->id != h5filterinfo->id) + {stat = NC_EINVAL; goto done;} + /* See if this filter is already defined */ + if((pos = filterlookup(id)) >= 0) + {stat = NC_ENAMEINUSE; goto done;} /* Already defined */ + if((herr = H5Zregister(h5filterinfo)) < 0) + {stat = NC_EFILTER; goto done;} + /* Save a copy of the passed in info */ + if((dup = dupfilterinfo(info)) == NULL) + {stat = NC_ENOMEM; goto done;} + nclistpush(filters,dup); + break; + case FILTER_UNREG: + if(id <= 0) + {stat = NC_ENOTNC4; goto done;} + /* See if this filter is already defined */ + if((pos = filterlookup(id)) < 0) + {stat = NC_EFILTER; goto done;} /* Not defined */ + if((herr = H5Zunregister(id)) < 0) + {stat = NC_EFILTER; goto done;} + if((stat=filterremove(pos))) goto done; + break; + case FILTER_INQ: + if(id <= 0) + {stat = NC_ENOTNC4; goto done;} + /* Look up the id in our local table */ + if((pos = filterlookup(id)) < 0) + {stat = NC_EFILTER; goto done;} /* Not defined */ + if(info != NULL) { + *info = *((NC_FILTER_INFO*)nclistget(filters,pos)); + } + break; + default: + {stat = NC_EINTERNAL; goto done;} + } +done: + return stat; +} diff --git a/nc_test4/CMakeLists.txt b/nc_test4/CMakeLists.txt index f562b3aa12..d6dc7a97d9 100644 --- a/nc_test4/CMakeLists.txt +++ b/nc_test4/CMakeLists.txt @@ -32,8 +32,9 @@ IF(BUILD_UTILITIES) IF(ENABLE_FILTER_TESTING) build_bin_test(test_filter) build_bin_test(test_filter_misc) + build_bin_test(test_filter_reg) ADD_SH_TEST(nc_test4 tst_filter) - SET(NC4_TESTS ${NC4_TESTS} tst_filterparser) + SET(NC4_TESTS ${NC4_TESTS} tst_filterparser test_filter_reg) ENDIF(ENABLE_FILTER_TESTING) ENDIF(BUILD_UTILITIES) diff --git a/nc_test4/Makefile.am b/nc_test4/Makefile.am index 1eaf018c86..67668bed51 100644 --- a/nc_test4/Makefile.am +++ b/nc_test4/Makefile.am @@ -71,7 +71,8 @@ endif if ENABLE_FILTER_TESTING extradir = extra_PROGRAMS = test_filter test_filter_misc -TESTS += tst_filter.sh +check_PROGRAMS += test_filter_reg +TESTS += tst_filter.sh test_filter_reg endif endif # BUILD_UTILITIES @@ -95,10 +96,13 @@ ref_filteredvv.cdl CLEANFILES = tst_mpi_parallel.bin cdm_sea_soundings.nc bm_chunking.nc \ tst_floats_1D.cdl floats_1D_3.nc floats_1D.cdl tst_*.nc \ -tst_elena_*.cdl tst_simple*.cdl tst_chunks.cdl pr_A1.* tauu_A1.* \ -usi_01.* thetau_01.* tst_*.h5 tst_grp_rename.cdl tst_grp_rename.dmp \ -ref_grp_rename.cdl foo1.nc tst_*.h4 test.nc testszip.nc test.h5 \ -szip_dump.cdl *.gz MSGCPP_*.nc +tst_floats2_*.cdl tst_ints2_*.cdl tst_shorts2_*.cdl tst_elena_*.cdl \ +tst_simple*.cdl tst_chunks.cdl pr_A1.* tauu_A1.* usi_01.* thetau_01.* \ +tst_*.h5 tst_grp_rename.cdl tst_grp_rename.dmp ref_grp_rename.cdl \ +foo1.nc tst_*.h4 test.nc testszip.nc test.h5 szip_dump.cdl \ +perftest.txt bigmeta.nc bigvars.nc *.gz MSGCPP_*.nc \ +floats*.nc floats*.cdl shorts*.nc shorts*.cdl ints*.nc ints*.cdl \ +testfilter_reg.nc DISTCLEANFILES = findplugin.sh run_par_test.sh diff --git a/nc_test4/test_filter_misc.c b/nc_test4/test_filter_misc.c index 465e896680..4eeb7bd589 100644 --- a/nc_test4/test_filter_misc.c +++ b/nc_test4/test_filter_misc.c @@ -12,6 +12,8 @@ #include "netcdf.h" #include "netcdf_filter.h" +#undef TESTODDSIZE + #undef DEBUG /* The C standard apparently defines all floating point constants as double; @@ -31,25 +33,27 @@ static unsigned int baseline[NPARAMS]; #define MAXDIMS 8 -#define DEFAULTACTUALDIMS 4 -#define DEFAULTDIMSIZE 4 -#define DEFAULTCHUNKSIZE 4 - #define TESTFILE "testmisc.nc" #define spec "32768, -17b, 23ub, -25S, 27US, 77, 93U, 789f, 12345678.12345678d, -9223372036854775807L, 18446744073709551615UL" -static size_t dimsize = DEFAULTDIMSIZE; -static size_t chunksize = DEFAULTCHUNKSIZE; -static size_t actualdims = DEFAULTACTUALDIMS; -static size_t pattern[MAXDIMS]; +#ifdef TESTODDSIZE +#define NDIMS 1 +static size_t dimsize[NDIMS] = {4}; +static size_t chunksize[NDIMS] = {3}; +#else +#define NDIMS 4 +static size_t dimsize[NDIMS] = {4,4,4,4}; +static size_t chunksize[NDIMS] = {4,4,4,4}; +#endif + +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 size_t dims[MAXDIMS]; -static size_t chunks[MAXDIMS]; +static size_t pattern[MAXDIMS]; static int nerrs = 0; @@ -105,15 +109,15 @@ verifychunks(void) { int i; int store = -1; - size_t chunksizes[MAXDIMS]; - memset(chunksizes,0,sizeof(chunksizes)); - CHECK(nc_inq_var_chunking(ncid, varid, &store, chunksizes)); + 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;i=0;i--) { + for(i=ndims-1;i>=0;i--) { odom[i] += 1; - if(odom[i] < dims[i]) break; + if(odom[i] < dimsize[i]) break; if(i == 0) return 0; /* leave the 0th entry if it overflows*/ odom[i] = 0; /* reset this position*/ } @@ -408,8 +456,8 @@ odom_offset(void) { int i; int offset = 0; - for(i=0;i 0?1:0); } diff --git a/nc_test4/test_filter_reg.c b/nc_test4/test_filter_reg.c new file mode 100644 index 0000000000..a16d1989aa --- /dev/null +++ b/nc_test4/test_filter_reg.c @@ -0,0 +1,613 @@ +/* + 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.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 NC_FILTER_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)); + } + 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;iversion != base->version) + {stat = NC_EINVAL; fprintf(stderr,"verifyfilterinfo: version mismatch\n");} + if(info->format != base->format) + {stat = NC_EINVAL; fprintf(stderr,"verifyfilterinfo: format mismatch\n");} + if(info->id != base->id) + {stat = NC_EINVAL; fprintf(stderr,"verifyfilterinfo: id mismatch\n");} + if(info->format == NC_FILTER_FORMAT_HDF5) { +#ifdef USE_HDF5 + H5Z_class2_t* h5info = (H5Z_class2_t*)info->info; + H5Z_class2_t* h5base = (H5Z_class2_t*)base->info; + if(h5info->version != h5base->version) + {stat = NC_EINVAL; fprintf(stderr,"verifyfilterinfo: H5Z_class_t: version mismatch\n");} + 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 + } else + {stat = NC_EINVAL; fprintf(stderr,"Unknown format\n");} + + return stat; +} + +static void +registerfilter(void) +{ + NC_FILTER_INFO inqinfo; + + baseinfo.version = NC_FILTER_INFO_VERSION; + baseinfo.format = NC_FILTER_FORMAT_HDF5; + baseinfo.id = FILTER_ID; + baseinfo.info = (void*)&H5Z_REG[0]; + CHECK(nc_filter_register(&baseinfo)); + /* Verify by inquiry */ + memset(&inqinfo,0,sizeof(NC_FILTER_INFO)); + CHECK((nc_filter_inq(NC_FILTER_FORMAT_HDF5, FILTER_ID, &inqinfo))); + CHECK((verifyfilterinfo(&inqinfo,&baseinfo))); +} + +static void +unregisterfilter(void) +{ + int stat = NC_NOERR; + NC_FILTER_INFO inqinfo; + + /* Verify that the filter info is still good */ + memset(&inqinfo,0,sizeof(NC_FILTER_INFO)); + CHECK((stat = nc_filter_inq(NC_FILTER_FORMAT_HDF5, FILTER_ID, &inqinfo))); + CHECK((verifyfilterinfo(&inqinfo,&baseinfo))); + /* Unregister */ + CHECK((stat = nc_filter_unregister(NC_FILTER_FORMAT_HDF5, FILTER_ID))); + /* Inq again to verify unregistered */ + stat = nc_filter_inq(NC_FILTER_FORMAT_HDF5, FILTER_ID, NULL); + if(stat != NC_EFILTER) { + fprintf(stderr,"unregister: failed\n"); + CHECK(NC_EFILTER); + } +} + +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 */ +#ifdef HDF5_HAS_ALLOCATE_MEMORY + newbuf = H5allocate_memory(*buf_size,0); +#else + newbuf = malloc(*buf_size * sizeof(void)); +#endif + if(newbuf == NULL) abort(); + memcpy(newbuf,*buf,*buf_size); + /* reclaim old buffer */ +#ifdef HDF5_HAS_H5FREE + H5free_memory(*buf); +#else + free(*buf); +#endif + *buf = newbuf; + + } else { + + /* Replace buffer */ +#ifdef HDF5_HAS_ALLOCATE_MEMORY + newbuf = H5allocate_memory(*buf_size,0); +#else + newbuf = malloc(*buf_size * sizeof(void)); +#endif + if(newbuf == NULL) abort(); + memcpy(newbuf,*buf,*buf_size); + /* reclaim old buffer */ +#ifdef HDF5_HAS_H5FREE + H5free_memory(*buf); +#else + free(*buf); +#endif + *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 */ +}}; diff --git a/nc_test4/tst_filter.sh b/nc_test4/tst_filter.sh index a9ebd29a04..548c0bb95a 100755 --- a/nc_test4/tst_filter.sh +++ b/nc_test4/tst_filter.sh @@ -77,7 +77,7 @@ rm -f ./tst_filter.txt trimleft ./tst_filter2.txt ./tst_filter.txt rm -f ./tst_filter2.txt cat >./tst_filter2.txt <