Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide a default enum const when fill value does not match any enum constant #2462

Merged
merged 4 commits into from
Jul 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ This file contains a high-level description of this package's evolution. Release

## 4.9.1 - T.B.D.

* [Bug Fix] Provide a default enum const when fill value does not match any enum constant for the value zero. See [Github #2462](https://github.com/Unidata/netcdf-c/pull/2462).
* [Bug Fi] Fix the json submodule symbol conflicts between libnetcdf and the plugin specific netcdf_json.h. See [Github #2448](https://github.com/Unidata/netcdf-c/pull/2448).
* [Bug Fix] Fix quantize with CLASSIC_MODEL files. See [Github #2405](https://github.com/Unidata/netcdf-c/pull/2445).
* [Enhancement] Add `--disable-quantize` option to `configure`.
Expand Down
3 changes: 3 additions & 0 deletions include/netcdf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
17 changes: 11 additions & 6 deletions libsrc4/nc4type.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand Down Expand Up @@ -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;
}

Expand Down
3 changes: 2 additions & 1 deletion ncdump/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -180,17 +180,18 @@ 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)
add_bin_test_no_prefix(tst_compress)
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.
Expand Down
7 changes: 4 additions & 3 deletions ncdump/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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:
Expand Down
13 changes: 13 additions & 0 deletions ncdump/ref_tst_enum_undef.cdl
Original file line number Diff line number Diff line change
@@ -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 changes: 148 additions & 0 deletions ncdump/tst_enum_undef.c
Original file line number Diff line number Diff line change
@@ -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;
}
2 changes: 2 additions & 0 deletions ncdump/tst_nccopy4.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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 ""

Expand Down
5 changes: 5 additions & 0 deletions ncdump/tst_netcdf4.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions nczarr_test/run_newformat.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
if test "x$srcdir" = x ; then srcdir=`pwd`; fi
. ../test_common.sh

set -x
. "$srcdir/test_nczarr.sh"

set -e
Expand Down