/* This is part of the netCDF package. Copyright 2005-2018 University Corporation for Atmospheric Research/Unidata. See COPYRIGHT file for conditions of use. Test user-defined formats. Ed Hartnett */ #include "config.h" #include #include "err_macros.h" #include "netcdf.h" #include "nc4dispatch.h" #include "hdf5dispatch.h" #include "netcdf_dispatch.h" #define FILE_NAME "tst_udf.nc" #ifdef _MSC_VER static int NC4_no_show_metadata(int ncid) { return NC_NOERR; } #define NC4_show_metadata NC4_no_show_metadata #endif int tst_open(const char *path, int mode, int basepe, size_t *chunksizehintp, void *parameters, const NC_Dispatch *dispatch, int ncid) { return NC_NOERR; } int tst_abort(int ncid) { return TEST_VAL_42; } int tst_close(int ncid, void *v) { return NC_NOERR; } int tst_inq_format(int ncid, int *formatp) { return TEST_VAL_42; } int tst_inq_format_extended(int ncid, int *formatp, int *modep) { return TEST_VAL_42; } int tst_get_vara(int ncid, int varid, const size_t *start, const size_t *count, void *value, nc_type t) { return TEST_VAL_42; } /* This is the dispatch object that holds pointers to all the * functions that make up the test dispatch interface. */ static NC_Dispatch tst_dispatcher = { NC_FORMATX_UDF0, NC_DISPATCH_VERSION, NC_RO_create, tst_open, NC_RO_redef, NC_RO__enddef, NC_RO_sync, tst_abort, tst_close, NC_RO_set_fill, tst_inq_format, tst_inq_format_extended, NC4_inq, NC4_inq_type, NC_RO_def_dim, NC4_inq_dimid, HDF5_inq_dim, NC4_inq_unlimdim, NC_RO_rename_dim, NC4_inq_att, NC4_inq_attid, NC4_inq_attname, NC_RO_rename_att, NC_RO_del_att, NC4_get_att, NC_RO_put_att, NC_RO_def_var, NC4_inq_varid, NC_RO_rename_var, tst_get_vara, NC_RO_put_vara, NCDEFAULT_get_vars, NCDEFAULT_put_vars, NCDEFAULT_get_varm, NCDEFAULT_put_varm, NC4_inq_var_all, NC_NOTNC4_var_par_access, NC_RO_def_var_fill, NC4_show_metadata, NC4_inq_unlimdims, NC4_inq_ncid, NC4_inq_grps, NC4_inq_grpname, NC4_inq_grpname_full, NC4_inq_grp_parent, NC4_inq_grp_full_ncid, NC4_inq_varids, NC4_inq_dimids, NC4_inq_typeids, NC4_inq_type_equal, NC_NOTNC4_def_grp, NC_NOTNC4_rename_grp, NC4_inq_user_type, NC4_inq_typeid, NC_NOTNC4_def_compound, NC_NOTNC4_insert_compound, NC_NOTNC4_insert_array_compound, NC_NOTNC4_inq_compound_field, NC_NOTNC4_inq_compound_fieldindex, NC_NOTNC4_def_vlen, NC_NOTNC4_put_vlen_element, NC_NOTNC4_get_vlen_element, NC_NOTNC4_def_enum, NC_NOTNC4_insert_enum, NC_NOTNC4_inq_enum_member, NC_NOTNC4_inq_enum_ident, NC_NOTNC4_def_opaque, NC_NOTNC4_def_var_deflate, NC_NOTNC4_def_var_fletcher32, NC_NOTNC4_def_var_chunking, NC_NOTNC4_def_var_endian, NC_NOTNC4_def_var_filter, NC_NOTNC4_set_var_chunk_cache, NC_NOTNC4_get_var_chunk_cache, #if NC_DISPATCH_VERSION >= 3 NC_NOOP_inq_var_filter_ids, NC_NOOP_inq_var_filter_info, #endif #if NC_DISPATCH_VERSION >= 4 NC_NOTNC4_def_var_quantize, NC_NOTNC4_inq_var_quantize, #endif #if NC_DISPATCH_VERSION >= 5 NC_NOOP_inq_filter_avail, #endif }; /* This is the dispatch object that holds pointers to all the * functions that make up the test dispatch interface with a bad * version number. */ static NC_Dispatch tst_dispatcher_bad_version = { NC_FORMATX_UDF0, NC_DISPATCH_VERSION - 1, NC_RO_create, tst_open, NC_RO_redef, NC_RO__enddef, NC_RO_sync, tst_abort, tst_close, NC_RO_set_fill, tst_inq_format, tst_inq_format_extended, NC4_inq, NC4_inq_type, NC_RO_def_dim, NC4_inq_dimid, HDF5_inq_dim, NC4_inq_unlimdim, NC_RO_rename_dim, NC4_inq_att, NC4_inq_attid, NC4_inq_attname, NC_RO_rename_att, NC_RO_del_att, NC4_get_att, NC_RO_put_att, NC_RO_def_var, NC4_inq_varid, NC_RO_rename_var, tst_get_vara, NC_RO_put_vara, NCDEFAULT_get_vars, NCDEFAULT_put_vars, NCDEFAULT_get_varm, NCDEFAULT_put_varm, NC4_inq_var_all, NC_NOTNC4_var_par_access, NC_RO_def_var_fill, NC4_show_metadata, NC4_inq_unlimdims, NC4_inq_ncid, NC4_inq_grps, NC4_inq_grpname, NC4_inq_grpname_full, NC4_inq_grp_parent, NC4_inq_grp_full_ncid, NC4_inq_varids, NC4_inq_dimids, NC4_inq_typeids, NC4_inq_type_equal, NC_NOTNC4_def_grp, NC_NOTNC4_rename_grp, NC4_inq_user_type, NC4_inq_typeid, NC_NOTNC4_def_compound, NC_NOTNC4_insert_compound, NC_NOTNC4_insert_array_compound, NC_NOTNC4_inq_compound_field, NC_NOTNC4_inq_compound_fieldindex, NC_NOTNC4_def_vlen, NC_NOTNC4_put_vlen_element, NC_NOTNC4_get_vlen_element, NC_NOTNC4_def_enum, NC_NOTNC4_insert_enum, NC_NOTNC4_inq_enum_member, NC_NOTNC4_inq_enum_ident, NC_NOTNC4_def_opaque, NC_NOTNC4_def_var_deflate, NC_NOTNC4_def_var_fletcher32, NC_NOTNC4_def_var_chunking, NC_NOTNC4_def_var_endian, NC_NOTNC4_def_var_filter, NC_NOTNC4_set_var_chunk_cache, NC_NOTNC4_get_var_chunk_cache, #if NC_DISPATCH_VERSION >= 3 NC_NOOP_inq_var_filter_ids, NC_NOOP_inq_var_filter_info, #endif #if NC_DISPATCH_VERSION >= 4 NC_NOTNC4_def_var_quantize, NC_NOTNC4_inq_var_quantize, #endif #if NC_DISPATCH_VERSION >= 5 NC_NOOP_inq_filter_avail, #endif }; #define NUM_UDFS 2 int mode[NUM_UDFS] = {NC_UDF0, NC_UDF1}; int main(int argc, char **argv) { printf("\n*** Testing user-defined formats.\n"); printf("*** testing simple user-defined format..."); { int ncid; NC_Dispatch *disp_in; int i; /* Create an empty file to play with. */ if (nc_create(FILE_NAME, 0, &ncid)) ERR; if (nc_close(ncid)) ERR; /* Test all available user-defined format slots. */ for (i = 0; i < NUM_UDFS; i++) { /* Add our user defined format. */ if (nc_def_user_format(mode[i], &tst_dispatcher, NULL)) ERR; /* Check that our user-defined format has been added. */ if (nc_inq_user_format(mode[i], &disp_in, NULL)) ERR; if (disp_in != &tst_dispatcher) ERR; /* Open file with our defined functions. */ if (nc_open(FILE_NAME, mode[i], &ncid)) ERR; if (nc_close(ncid)) ERR; /* Open file again and abort, which is the same as closing * it. This also tests that the UDF flags are given * priority. If NC_NETCDF4 flag were given priority, then * nc_abort() will not return TEST_VAL_42, but instead will * return 0. */ if (nc_open(FILE_NAME, mode[i], &ncid)) ERR; if (nc_inq_format(ncid, NULL) != TEST_VAL_42) ERR; if (nc_inq_format_extended(ncid, NULL, NULL) != TEST_VAL_42) ERR; if (nc_abort(ncid) != TEST_VAL_42) ERR; } } SUMMARIZE_ERR; printf("*** testing user-defined format with magic number..."); { int ncid; NC_Dispatch *disp_in; char magic_number[5] = "1111"; char dummy_data[11] = "0123456789"; char magic_number_in[NC_MAX_MAGIC_NUMBER_LEN]; FILE *FP; int i; /* Create a file with magic number at start. */ if (!(FP = NCfopen(FILE_NAME, "w"))) ERR; if (fwrite(magic_number, sizeof(char), strlen(magic_number), FP) != strlen(magic_number)) ERR; if (fwrite(dummy_data, sizeof(char), strlen(dummy_data), FP) != strlen(dummy_data)) ERR; if (fclose(FP)) ERR; /* Test all available user-defined format slots. */ for (i = 0; i < NUM_UDFS; i++) { /* Add our test user defined format. */ mode[i] = mode[i]|NC_NETCDF4; if (nc_def_user_format(mode[i], &tst_dispatcher, magic_number)) ERR; /* Check that our user-defined format has been added. */ if (nc_inq_user_format(mode[i], &disp_in, magic_number_in)) ERR; if (disp_in != &tst_dispatcher) ERR; if (strncmp(magic_number, magic_number_in, strlen(magic_number))) ERR; /* Open file with our defined functions. */ if (nc_open(FILE_NAME, mode[i], &ncid)) ERR; if (nc_close(ncid)) ERR; /* Open file again and abort, which is the same as closing * it. This time we don't specify a mode, because the magic * number is used to identify the file. */ if (nc_open(FILE_NAME, 0, &ncid)) ERR; if (nc_inq_format(ncid, NULL) != TEST_VAL_42) ERR; if (nc_inq_format_extended(ncid, NULL, NULL) != TEST_VAL_42) ERR; if (nc_abort(ncid) != TEST_VAL_42) ERR; } } SUMMARIZE_ERR; printf("*** testing bad version causes dispatch table to be rejected..."); { int i; char magic_number[5] = "1111"; /* Test all available user-defined format slots. */ for (i = 0; i < NUM_UDFS; i++) { /* Make sure our bad version format is rejected. */ if (nc_def_user_format(mode[i], &tst_dispatcher_bad_version, NULL) != NC_EINVAL) ERR; /* Make sure defining a magic number with netcdf3 is rejected. */ if (nc_def_user_format(NC_CLASSIC_MODEL, &tst_dispatcher, magic_number) != NC_EINVAL) ERR; } } SUMMARIZE_ERR; FINAL_RESULTS; }