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

Add support for HDF5 transient types #2655

Merged
merged 10 commits into from
Jul 18, 2023
22 changes: 18 additions & 4 deletions libhdf5/hdf5open.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "hdf5internal.h"
#include "hdf5err.h"
#include "hdf5debug.h"
#include "nc4internal.h"
#include "ncrc.h"
#include "ncauth.h"
#include "ncmodel.h"
Expand Down Expand Up @@ -63,6 +64,7 @@ extern int NC4_open_image_file(NC_FILE_INFO_T* h5);

/* Defined later in this file. */
static int rec_read_metadata(NC_GRP_INFO_T *grp);
static int read_type(NC_GRP_INFO_T *grp, hid_t hdf_typeid, char *type_name);

/**
* @internal Struct to track HDF5 object info, for
Expand Down Expand Up @@ -103,7 +105,7 @@ typedef struct {
* struct, either an existing one (for user-defined types) or a newly
* created one.
*
* @param h5 Pointer to HDF5 file info struct.
* @param h5_grp Pointer to group info struct.
* @param datasetid HDF5 dataset ID.
* @param type_info Pointer to pointer that gets type info struct.
*
Expand All @@ -114,7 +116,7 @@ typedef struct {
* @author Ed Hartnett
*/
static int
get_type_info2(NC_FILE_INFO_T *h5, hid_t datasetid, NC_TYPE_INFO_T **type_info)
get_type_info2(NC_GRP_INFO_T *h5_grp, hid_t datasetid, NC_TYPE_INFO_T **type_info)
{
NC_HDF5_TYPE_INFO_T *hdf5_type;
htri_t is_str, equal = 0;
Expand All @@ -123,7 +125,7 @@ get_type_info2(NC_FILE_INFO_T *h5, hid_t datasetid, NC_TYPE_INFO_T **type_info)
H5T_order_t order;
int t;

assert(h5 && type_info);
assert(h5_grp && type_info);

/* Because these N5T_NATIVE_* constants are actually function calls
* (!) in H5Tpublic.h, I can't initialize this array in the usual
Expand Down Expand Up @@ -231,11 +233,23 @@ get_type_info2(NC_FILE_INFO_T *h5, hid_t datasetid, NC_TYPE_INFO_T **type_info)
else
{
NC_TYPE_INFO_T *type;
NC_FILE_INFO_T *h5 = h5_grp->nc4_info;

/* This is a user-defined type. */
if((type = nc4_rec_find_hdf_type(h5, native_typeid)))
*type_info = type;

/* If we didn't find the type, then it's probably a transient
* type, stored in the dataset itself, so let's read it now */
if (type == NULL) {
int retval;
if ((retval = read_type(h5_grp, native_typeid, "")))
return retval;

if((type = nc4_rec_find_hdf_type(h5, native_typeid)))
*type_info = type;
}

/* The type entry in the array of user-defined types already has
* an open data typeid (and native typeid), so close the ones we
* opened above. */
Expand Down Expand Up @@ -1585,7 +1599,7 @@ read_var(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name,
/* Learn all about the type of this variable. This will fail for
* HDF5 reference types, and then the var we just created will be
* deleted, thus ignoring HDF5 reference type objects. */
if ((retval = get_type_info2(var->container->nc4_info, hdf5_var->hdf_datasetid,
if ((retval = get_type_info2(var->container, hdf5_var->hdf_datasetid,
&var->type_info)))
BAIL(retval);

Expand Down
2 changes: 1 addition & 1 deletion nc_test4/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ SET(NC4_TESTS tst_dims tst_dims2 tst_dims3 tst_files tst_files4
tst_rename2 tst_rename3 tst_h5_endians tst_atts_string_rewrite tst_put_vars_two_unlim_dim
tst_hdf5_file_compat tst_fill_attr_vanish tst_rehash tst_types tst_bug324
tst_atts3 tst_put_vars tst_elatefill tst_udf tst_bug1442 tst_broken_files
tst_quantize)
tst_quantize tst_h_transient_types)

IF(HAS_PAR_FILTERS)
SET(NC4_tests $NC4_TESTS tst_alignment)
Expand Down
78 changes: 78 additions & 0 deletions nc_test4/tst_h_transient_types.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/* This is part of the netCDF package. Copyright 2018 University
Corporation for Atmospheric Research/Unidata See COPYRIGHT file for
conditions of use.

This program tests fixes for reading netCDF-4 files that contain
datasets with reference datatypes. The netCDF-4 library should ignore
the datasets & attributes that have reference datatypes and allow the
rest of the file to be accessed.
*/

#include "netcdf.h"
#include <config.h>
#include <nc_tests.h>
#include <err_macros.h>
#include <hdf5.h>
#include <complex.h>

#define FILE_NAME "tst_h_transient.h5"
#define VAR_NAME "var"
#define INT_ATT_NAME "intatt"
#define INT_VAR_NAME "intvar"

int
main()
{
double complex expected_z = 1 + 2*I;

printf("\n*** Creating file with datasets that have transient datatypes.\n");
{
hid_t fileid, scalar_spaceid;
hid_t dsetid, complex_dtype;

/* Create new file, using default properties. */
if ((fileid = H5Fcreate(FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) ERR;

/* Create compound datatype, but don't commit to file */
if ((complex_dtype = H5Tcreate(H5T_COMPOUND, sizeof(double complex))) < 0) ERR;
if (H5Tinsert(complex_dtype, "r", 0, H5T_NATIVE_DOUBLE) < 0) ERR;
if (H5Tinsert(complex_dtype, "i", sizeof(double), H5T_NATIVE_DOUBLE) < 0) ERR;

/* Create dataset with transient datatype */
if ((scalar_spaceid = H5Screate(H5S_SCALAR)) < 0) ERR;
if ((dsetid = H5Dcreate2(fileid, VAR_NAME, complex_dtype, scalar_spaceid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) ERR;

/* Write complex number to file */
if ((H5Dwrite(dsetid, complex_dtype, H5S_ALL, H5S_ALL, H5P_DEFAULT, &expected_z)) <0) ERR;

/* Close dataset */
if (H5Dclose(dsetid) < 0) ERR;

/* Close rest */
if (H5Sclose(scalar_spaceid) < 0) ERR;
if (H5Fclose(fileid) < 0) ERR;
}

printf("*** Checking accessing file through netCDF-4 API...");
{
int ncid, varid;
double complex read_z;

nc_set_log_level(4);
if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR;

/* Verify that the dataset is present */
if (nc_inq_varid(ncid, VAR_NAME, &varid)) ERR;

/* Read complex variable */
if (nc_get_var(ncid, varid, &read_z)) ERR;

if (read_z != expected_z) ERR;

if (nc_close(ncid)) ERR;
}
SUMMARIZE_ERR;

FINAL_RESULTS;
}