mirror of
https://github.com/Unidata/netcdf-c.git
synced 2025-03-25 17:40:27 +08:00
Provide a default enum const when fill value does not match any enum const.
re: https://github.com/Unidata/netcdf-c/issues/982 It is possible to define an enum type that has no enum constant with value zero. However, HDF5 has a default fill value of zero that it used to fill all chunks. In the event that this situation occurs, ncdump, say, will fail because there is no enum const to print for the value zero. The solution is to create a special enum constant called "_UNDEFINED" that has the value zero. It is only used in the case that there is no constant in the enum that already covers zero. A test case is added in netcdf-c/ncdump to validate this solution. Note: the changes occur primarily in libsrc4, so they also work for NCZarr.
This commit is contained in:
parent
64033e367d
commit
65fd9fe1a5
@ -836,6 +836,9 @@ nc_inq_enum_member(int ncid, nc_type xtype, int idx, char *name,
|
||||
|
||||
|
||||
/* Get enum name from enum value. Name size will be <= NC_MAX_NAME. */
|
||||
/* If value is zero and there is no matching ident, then return _UNDEFINED */
|
||||
#define NC_UNDEFINED_ENUM_IDENT "_UNDEFINED"
|
||||
|
||||
EXTERNL int
|
||||
nc_inq_enum_ident(int ncid, nc_type xtype, long long value, char *identifier);
|
||||
|
||||
|
@ -492,7 +492,9 @@ setupconn(NC_HTTP_STATE* state, const char* objecturl)
|
||||
ncuriparse(objecturl,&uri);
|
||||
if(uri == NULL) goto fail;
|
||||
hostport = NC_combinehostport(uri);
|
||||
ncurifree(uri); uri = NULL;
|
||||
value = NC_rclookup("HTTP.SSL.CAINFO",hostport,NULL);
|
||||
nullfree(hostport); hostport = NULL;
|
||||
if(value == NULL)
|
||||
value = NC_rclookup("HTTP.SSL.CAINFO",NULL,NULL);
|
||||
if(value != NULL) {
|
||||
|
@ -189,6 +189,7 @@ NC_rcclear(NCRCinfo* info)
|
||||
nullfree(info->rchome);
|
||||
rcfreeentries(info->entries);
|
||||
freeprofilelist(info->s3profiles);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1143,6 +1144,8 @@ aws_load_credentials(NCglobalstate* gstate)
|
||||
nclistpush(profiles,noprof); noprof = NULL;
|
||||
}
|
||||
|
||||
if(gstate->rcinfo->s3profiles)
|
||||
freeprofilelist(gstate->rcinfo->s3profiles);
|
||||
gstate->rcinfo->s3profiles = profiles; profiles = NULL;
|
||||
|
||||
#ifdef AWSDEBUG
|
||||
|
@ -397,8 +397,9 @@ NC4_inq_compound_fieldindex(int ncid, nc_type typeid1, const char *name, int *fi
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal Get enum name from enum value. Name size will be <=
|
||||
* NC_MAX_NAME.
|
||||
* @internal Get enum name from enum value. Name size will be <= NC_MAX_NAME.
|
||||
* If the value is not a legitimate enum identifier and the value is zero
|
||||
* (the default HDF5 enum fill value), then return the identifier "_UNDEFINED".
|
||||
*
|
||||
* @param ncid File and group ID.
|
||||
* @param xtype Type ID.
|
||||
@ -408,7 +409,7 @@ NC4_inq_compound_fieldindex(int ncid, nc_type typeid1, const char *name, int *fi
|
||||
* @return ::NC_NOERR No error.
|
||||
* @return ::NC_EBADID Bad ncid.
|
||||
* @return ::NC_EBADTYPE Type not found.
|
||||
* @return ::NC_EINVAL Invalid type data.
|
||||
* @return ::NC_EINVAL Invalid type data or no matching enum value is found
|
||||
* @author Ed Hartnett
|
||||
*/
|
||||
int
|
||||
@ -479,9 +480,13 @@ NC4_inq_enum_ident(int ncid, nc_type xtype, long long value, char *identifier)
|
||||
}
|
||||
|
||||
/* If we didn't find it, life sucks for us. :-( */
|
||||
if (!found)
|
||||
return NC_EINVAL;
|
||||
|
||||
if(!found) {
|
||||
if(value == 0) /* Special case for HDF5 default Fill Value*/
|
||||
strcpy(identifier, NC_UNDEFINED_ENUM_IDENT);
|
||||
else
|
||||
return NC_EINVAL;
|
||||
}
|
||||
|
||||
return NC_NOERR;
|
||||
}
|
||||
|
||||
|
@ -418,7 +418,7 @@ main(int argc, char **argv)
|
||||
if (nc_close(ncid)) ERR;
|
||||
}
|
||||
SUMMARIZE_ERR;
|
||||
#ifdef HAVE_SZ
|
||||
#ifdef HAVE_H5Z_SZIP
|
||||
printf("**** testing simple szip filter setup...");
|
||||
{
|
||||
int ncid;
|
||||
@ -748,9 +748,9 @@ main(int argc, char **argv)
|
||||
params[1] = NC_SZIP_EC_BPP_IN; /* pixels_per_block */
|
||||
if (nc_def_var_chunking(ncid, varid, NC_CHUNKED, NULL)) ERR;
|
||||
{ int stat;
|
||||
if ((stat = nc_def_var_filter(ncid, varid, H5_FILTER_SZIP, NUM_PARAMS_IN,
|
||||
params)) != NC_ENOFILTER)
|
||||
ERR;
|
||||
stat = nc_def_var_filter(ncid, varid, H5_FILTER_SZIP, NUM_PARAMS_IN, params);
|
||||
if(stat != NC_ENOFILTER)
|
||||
ERR;
|
||||
}
|
||||
if (nc_def_var_szip(ncid, varid, NC_SZIP_NN,
|
||||
NC_SZIP_EC_BPP_IN) != NC_ENOFILTER) ERR;
|
||||
|
@ -180,10 +180,10 @@ endif()
|
||||
IF(USE_HDF5)
|
||||
build_bin_test_no_prefix(tst_h_rdc0)
|
||||
build_bin_test_no_prefix(tst_unicode)
|
||||
build_bin_test_no_prefix(tst_vlen_data)
|
||||
add_bin_test_no_prefix(tst_create_files)
|
||||
add_bin_test_no_prefix(tst_opaque_data)
|
||||
add_bin_test_no_prefix(tst_string_data)
|
||||
add_bin_test_no_prefix(tst_vlen_data)
|
||||
add_bin_test_no_prefix(tst_comp2)
|
||||
add_bin_test_no_prefix(tst_nans)
|
||||
add_bin_test_no_prefix(tst_h_scalar)
|
||||
@ -191,6 +191,7 @@ endif()
|
||||
add_bin_test_no_prefix(tst_chunking)
|
||||
add_bin_test_no_prefix(tst_group_data)
|
||||
add_bin_test_no_prefix(tst_enum_data)
|
||||
add_bin_test_no_prefix(tst_enum_undef)
|
||||
add_bin_test_no_prefix(tst_comp)
|
||||
# Add this test by hand, as it is also called from a script.
|
||||
# Editing the script would break autotools compatibility.
|
||||
|
@ -111,7 +111,8 @@ if USE_HDF5
|
||||
check_PROGRAMS += tst_fileinfo tst_create_files tst_h_rdc0 \
|
||||
tst_group_data tst_enum_data tst_opaque_data tst_string_data \
|
||||
tst_vlen_data tst_comp tst_comp2 tst_nans tst_special_atts \
|
||||
tst_unicode tst_fillbug tst_compress tst_chunking tst_h_scalar
|
||||
tst_unicode tst_fillbug tst_compress tst_chunking tst_h_scalar \
|
||||
tst_enum_undef
|
||||
|
||||
check_PROGRAMS += tst_vlen_demo
|
||||
|
||||
@ -204,7 +205,7 @@ test_keywords.sh ref_keyword1.cdl ref_keyword2.cdl ref_keyword3.cdl ref_keyword4
|
||||
ref_tst_nofilters.cdl test_scope.sh \
|
||||
test_rcmerge.sh ref_rcmerge1.txt ref_rcmerge2.txt ref_rcmerge3.txt \
|
||||
scope_ancestor_only.cdl scope_ancestor_subgroup.cdl scope_group_only.cdl scope_preorder.cdl \
|
||||
ref_rcapi.txt
|
||||
ref_rcapi.txt ref_tst_enum_undef.cdl
|
||||
|
||||
# The L512.bin file is file containing exactly 512 bytes each of value 0.
|
||||
# It is used for creating hdf5 files with varying offsets for testing.
|
||||
@ -246,7 +247,7 @@ tst_roman_szip_unlim.cdl tst_perdimpspecs.nc tmppds.* \
|
||||
keyword1.nc keyword2.nc keyword3.nc keyword4.nc \
|
||||
tmp_keyword1.cdl tmp_keyword2.cdl tmp_keyword3.cdl tmp_keyword4.cdl \
|
||||
type_*.nc copy_type_*.cdl \
|
||||
scope_*.nc copy_scope_*.cdl keyword5.nc
|
||||
scope_*.nc copy_scope_*.cdl keyword5.nc tst_enum_undef.cdl
|
||||
|
||||
# Remove directories
|
||||
clean-local:
|
||||
|
13
ncdump/ref_tst_enum_undef.cdl
Normal file
13
ncdump/ref_tst_enum_undef.cdl
Normal file
@ -0,0 +1,13 @@
|
||||
netcdf tst_enum_undef {
|
||||
types:
|
||||
ubyte enum cloud_class_t {Cumulonimbus = 1, Stratus = 2, Stratocumulus = 3,
|
||||
Cumulus = 4, Altostratus = 5, Nimbostratus = 6, Altocumulus = 7,
|
||||
Cirrostratus = 8, Cirrocumulus = 9, Cirrus = 10, Missing = 255} ;
|
||||
dimensions:
|
||||
station = 5 ;
|
||||
variables:
|
||||
cloud_class_t primary_cloud(station) ;
|
||||
data:
|
||||
|
||||
primary_cloud = _UNDEFINED, Stratus, _UNDEFINED, Cumulonimbus, Missing ;
|
||||
}
|
148
ncdump/tst_enum_undef.c
Normal file
148
ncdump/tst_enum_undef.c
Normal file
@ -0,0 +1,148 @@
|
||||
/* This is part of the netCDF package. Copyright 2018 University
|
||||
Corporation for Atmospheric Research/Unidata See COPYRIGHT file for
|
||||
conditions of use. See www.unidata.ucar.edu for more info.
|
||||
|
||||
Create a test file with an enum type and enum data for ncdump to read.
|
||||
|
||||
$Id: tst_enum_data.c,v 1.8 2008/10/20 01:48:08 ed Exp $
|
||||
*/
|
||||
|
||||
#include <nc_tests.h>
|
||||
#include "err_macros.h"
|
||||
#include <netcdf.h>
|
||||
|
||||
#undef WITHFILL
|
||||
|
||||
#define FILE2_NAME "tst_enum_undef.nc"
|
||||
#define TYPE2_NAME "cloud_class_t"
|
||||
#define DIM2_NAME "station"
|
||||
#define DIM2_LEN 5
|
||||
#define VAR2_NAME "primary_cloud"
|
||||
#define VAR2_RANK 1
|
||||
#define ATT2_NAME "_FillValue"
|
||||
#define ATT2_LEN 1
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int ncid;
|
||||
int dimid, varid;
|
||||
nc_type typeid;
|
||||
int num_members;
|
||||
char name_in[NC_MAX_NAME+1];
|
||||
nc_type base_nc_type_in;
|
||||
size_t nfields_in, base_size_in, num_members_in;
|
||||
int class_in;
|
||||
unsigned char value_in;
|
||||
#ifdef WITHFILL
|
||||
char zero = 0;
|
||||
#endif
|
||||
|
||||
int i;
|
||||
|
||||
enum clouds { /* a C enumeration */
|
||||
/* No 0 value */
|
||||
CUMULONIMBUS=1,
|
||||
STRATUS=2,
|
||||
STRATOCUMULUS=3,
|
||||
CUMULUS=4,
|
||||
ALTOSTRATUS=5,
|
||||
NIMBOSTRATUS=6,
|
||||
ALTOCUMULUS=7,
|
||||
CIRROSTRATUS=8,
|
||||
CIRROCUMULUS=9,
|
||||
CIRRUS=10,
|
||||
MISSING=255};
|
||||
|
||||
struct {
|
||||
char *name;
|
||||
unsigned char value;
|
||||
} cloud_types[] = {
|
||||
{"Cumulonimbus", CUMULONIMBUS},
|
||||
{"Stratus", STRATUS},
|
||||
{"Stratocumulus", STRATOCUMULUS},
|
||||
{"Cumulus", CUMULUS},
|
||||
{"Altostratus", ALTOSTRATUS},
|
||||
{"Nimbostratus", NIMBOSTRATUS},
|
||||
{"Altocumulus", ALTOCUMULUS},
|
||||
{"Cirrostratus", CIRROSTRATUS},
|
||||
{"Cirrocumulus", CIRROCUMULUS},
|
||||
{"Cirrus", CIRRUS},
|
||||
{"Missing", MISSING}
|
||||
};
|
||||
int var_dims[VAR2_RANK];
|
||||
unsigned char cloud_data[DIM2_LEN] = {
|
||||
0, STRATUS, 0, CUMULONIMBUS, MISSING};
|
||||
unsigned char cloud_data_in[DIM2_LEN];
|
||||
|
||||
printf("\n*** Testing enum undefined identifier.\n");
|
||||
printf("*** creating enum test file %s...", FILE2_NAME);
|
||||
/*nc_set_log_level(3);*/
|
||||
if (nc_create(FILE2_NAME, NC_CLOBBER | NC_NETCDF4, &ncid)) ERR;
|
||||
|
||||
/* Create an enum type. */
|
||||
if (nc_def_enum(ncid, NC_UBYTE, TYPE2_NAME, &typeid)) ERR;
|
||||
num_members = (sizeof cloud_types) / (sizeof cloud_types[0]);
|
||||
for (i = 0; i < num_members; i++) {
|
||||
if (nc_insert_enum(ncid, typeid, cloud_types[i].name,
|
||||
&cloud_types[i].value))
|
||||
ERR;
|
||||
}
|
||||
/* Declare a station dimension */
|
||||
if (nc_def_dim(ncid, DIM2_NAME, DIM2_LEN, &dimid)) ERR;
|
||||
/* Declare a variable of the enum type */
|
||||
var_dims[0] = dimid;
|
||||
if (nc_def_var(ncid, VAR2_NAME, typeid, VAR2_RANK, var_dims, &varid)) ERR;
|
||||
#ifdef WITHFILL
|
||||
if (nc_def_var_fill(ncid, varid, NC_FILL, &zero)) ERR;
|
||||
#endif
|
||||
if (nc_enddef(ncid)) ERR;
|
||||
/* Store some data of the enum type */
|
||||
if(nc_put_var(ncid, varid, cloud_data)) ERR;
|
||||
/* Write the file. */
|
||||
if (nc_close(ncid)) ERR;
|
||||
|
||||
/* Check it out. */
|
||||
|
||||
/* Reopen the file. */
|
||||
if (nc_open(FILE2_NAME, NC_NOWRITE, &ncid)) ERR;
|
||||
|
||||
if (nc_inq_user_type(ncid, typeid, name_in, &base_size_in, &base_nc_type_in,
|
||||
&nfields_in, &class_in)) ERR;
|
||||
if (strcmp(name_in, TYPE2_NAME) ||
|
||||
base_size_in != sizeof(unsigned char) ||
|
||||
base_nc_type_in != NC_UBYTE ||
|
||||
nfields_in != num_members ||
|
||||
class_in != NC_ENUM) ERR;
|
||||
if (nc_inq_enum(ncid, typeid, name_in,
|
||||
&base_nc_type_in, &base_size_in, &num_members_in)) ERR;
|
||||
if (strcmp(name_in, TYPE2_NAME) ||
|
||||
base_nc_type_in != NC_UBYTE ||
|
||||
num_members_in != num_members) ERR;
|
||||
for (i = 0; i < num_members; i++)
|
||||
{
|
||||
if (nc_inq_enum_member(ncid, typeid, i, name_in, &value_in)) ERR;
|
||||
if (strcmp(name_in, cloud_types[i].name) ||
|
||||
value_in != cloud_types[i].value) ERR;
|
||||
if (nc_inq_enum_ident(ncid, typeid, cloud_types[i].value,
|
||||
name_in)) ERR;
|
||||
if (strcmp(name_in, cloud_types[i].name)) ERR;
|
||||
}
|
||||
if (nc_inq_varid(ncid, VAR2_NAME, &varid)) ERR;
|
||||
|
||||
#ifdef WITHFILL
|
||||
if (nc_get_att(ncid, varid, ATT2_NAME, &value_in)) ERR;
|
||||
if (value_in != 0) ERR;
|
||||
#endif
|
||||
|
||||
if(nc_get_var(ncid, varid, cloud_data_in)) ERR;
|
||||
for (i = 0; i < DIM2_LEN; i++) {
|
||||
if (cloud_data_in[i] != cloud_data[i]) ERR;
|
||||
}
|
||||
|
||||
if (nc_close(ncid)) ERR;
|
||||
|
||||
|
||||
SUMMARIZE_ERR;
|
||||
FINAL_RESULTS;
|
||||
}
|
@ -7,10 +7,12 @@ set -e
|
||||
|
||||
# For a netCDF-4 build, test nccopy on netCDF files in this directory
|
||||
|
||||
#if 0
|
||||
if test -f tst_group_data${ext} ; then ${execdir}/tst_group_data ; fi
|
||||
if test -f tst_enum_data${ext} ; then ${execdir}/tst_enum_data ; fi
|
||||
if test -f tst_comp${ext} ; then ${execdir}/tst_comp ; fi
|
||||
if test -f tst_comp2${ext} ; then ${execdir}/tst_comp2 ; fi
|
||||
#endif
|
||||
|
||||
echo ""
|
||||
|
||||
|
@ -75,6 +75,11 @@ ${execdir}/tst_enum_data ; ERR
|
||||
${NCDUMP} tst_enum_data.nc | sed 's/e+0/e+/g' > tst_enum_data.cdl ; ERR
|
||||
diff -b tst_enum_data.cdl $srcdir/ref_tst_enum_data.cdl ; ERR
|
||||
|
||||
echo "*** Running tst_enum_undef.c to create test files."
|
||||
${execdir}/tst_enum_undef ; ERR
|
||||
${NCDUMP} tst_enum_undef.nc | sed 's/e+0/e+/g' > tst_enum_undef.cdl ; ERR
|
||||
diff -b tst_enum_undef.cdl $srcdir/ref_tst_enum_undef.cdl ; ERR
|
||||
|
||||
echo "*** Running tst_opaque_data.c to create test files."
|
||||
${execdir}/tst_opaque_data ; ERR
|
||||
${NCDUMP} tst_opaque_data.nc | sed 's/e+0/e+/g' > tst_opaque_data.cdl ; ERR
|
||||
|
Loading…
x
Reference in New Issue
Block a user