diff --git a/include/hdf5internal.h b/include/hdf5internal.h index 80ad136..7b4fb6d 100644 --- a/include/hdf5internal.h +++ b/include/hdf5internal.h @@ -45,6 +45,7 @@ /* If this attribute is present on a dimscale variable, use the value * as the netCDF dimid. */ #define NC_DIMID_ATT_NAME "_Netcdf4Dimid" +#define NC_DIMSIZE_ATT_NAME "_Netcdf4DimSize" /** This is the name of the class HDF5 dimension scale attribute. */ #define HDF5_DIMSCALE_CLASS_ATT_NAME "CLASS" diff --git a/libhdf5/hdf5file.c b/libhdf5/hdf5file.c index 65fd033..da59ce8 100644 --- a/libhdf5/hdf5file.c +++ b/libhdf5/hdf5file.c @@ -26,7 +26,7 @@ static void dumpopenobjects(NC_FILE_INFO_T* h5); /** @internal Number of reserved attributes. These attributes are * hidden from the netcdf user, but exist in the HDF5 file to help * netcdf read the file. */ -#define NRESERVED 11 /*|NC_reservedatt|*/ +#define NRESERVED 12 /*|NC_reservedatt|*/ /** @internal List of reserved attributes. This list must be in sorted * order for binary search. */ @@ -40,6 +40,7 @@ static const NC_reservedatt NC_reserved[NRESERVED] = { {NCPROPS, READONLYFLAG|NAMEONLYFLAG|MATERIALIZEDFLAG},/*_NCProperties*/ {NC_ATT_COORDINATES, READONLYFLAG|DIMSCALEFLAG|MATERIALIZEDFLAG},/*_Netcdf4Coordinates*/ {NC_DIMID_ATT_NAME, READONLYFLAG|DIMSCALEFLAG|MATERIALIZEDFLAG},/*_Netcdf4Dimid*/ + {NC_DIMSIZE_ATT_NAME, READONLYFLAG|DIMSCALEFLAG|MATERIALIZEDFLAG},/*_Netcdf4DimSize*/ {SUPERBLOCKATT, READONLYFLAG|NAMEONLYFLAG},/*_SuperblockVersion*/ {NC3_STRICT_ATT_NAME, READONLYFLAG|MATERIALIZEDFLAG}, /*_nc3_strict*/ }; diff --git a/libhdf5/hdf5open.c b/libhdf5/hdf5open.c index 06d97a6..5692ac6 100644 --- a/libhdf5/hdf5open.c +++ b/libhdf5/hdf5open.c @@ -2176,6 +2176,7 @@ read_scale(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, char dimscale_name_att[NC_MAX_NAME + 1] = ""; /* Dimscale name, for checking if dim without var */ htri_t attr_exists = -1; /* Flag indicating hidden attribute exists */ hid_t attid = -1; /* ID of hidden attribute (to store dim ID) */ + hid_t sizid = -1; /* ID of hidden attribute (to store dim size) */ int dimscale_created = 0; /* Remember if a dimension was created (for error recovery) */ short initial_next_dimid = grp->nc4_info->next_dimid;/* Retain for error recovery */ size_t len = 0; @@ -2209,8 +2210,26 @@ read_scale(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, len = NC_MAX_UINT; too_long = NC_TRUE; } - else + else { + /* Does this dataset have a hidden attribute that tells us its + * size? If so, read it. */ + if ((attr_exists = H5Aexists(datasetid, NC_DIMSIZE_ATT_NAME)) < 0) + BAIL(NC_EHDFERR); + if (attr_exists) + { + size_t size = 0; + if ((sizid = H5Aopen_name(datasetid, NC_DIMSIZE_ATT_NAME)) < 0) + BAIL(NC_EHDFERR); + + if (H5Aread(sizid, H5T_NATIVE_ULLONG, &size) < 0) + BAIL(NC_EHDFERR); + len = size; + H5Aclose(sizid); + } + else { len = scale_size; + } + } /* Create the dimension for this scale. */ if ((retval = nc4_dim_list_add(grp, obj_name, len, assigned_id, &new_dim))) diff --git a/libhdf5/nc4hdf.c b/libhdf5/nc4hdf.c index 62cdb00..edd7d93 100644 --- a/libhdf5/nc4hdf.c +++ b/libhdf5/nc4hdf.c @@ -787,6 +787,55 @@ exit: } /** + * @internal Write a special attribute for the netCDF-4 dimension size. + * + * @param datasetid HDF5 datasset ID. + * @param size NetCDF dimension size. + * + * @returns NC_NOERR No error. + * @returns NC_EHDFERR HDF5 returned an error. + */ +static int +write_netcdf4_dim_size(hid_t datasetid, size_t size) +{ + hid_t dimid_spaceid = -1, dimid_attid = -1; + htri_t attr_exists; + int retval = NC_NOERR; + + /* Create the space. */ + if ((dimid_spaceid = H5Screate(H5S_SCALAR)) < 0) + BAIL(NC_EHDFERR); + + /* Does the attribute already exist? If so, don't try to create it. */ + if ((attr_exists = H5Aexists(datasetid, NC_DIMSIZE_ATT_NAME)) < 0) + BAIL(NC_EHDFERR); + if (attr_exists) + dimid_attid = H5Aopen_by_name(datasetid, ".", NC_DIMSIZE_ATT_NAME, + H5P_DEFAULT, H5P_DEFAULT); + else + /* Create the attribute if needed. */ + dimid_attid = H5Acreate(datasetid, NC_DIMSIZE_ATT_NAME, + H5T_NATIVE_ULLONG, dimid_spaceid, H5P_DEFAULT); + if (dimid_attid < 0) + BAIL(NC_EHDFERR); + + + /* Write it. */ + LOG((4, "%s: writing secret dim size %ld", __func__, size)); + if (H5Awrite(dimid_attid, H5T_NATIVE_ULLONG, &size) < 0) + BAIL(NC_EHDFERR); + +exit: + /* Close stuff*/ + if (dimid_spaceid >= 0 && H5Sclose(dimid_spaceid) < 0) + BAIL2(NC_EHDFERR); + if (dimid_attid >= 0 && H5Aclose(dimid_attid) < 0) + BAIL2(NC_EHDFERR); + + return retval; +} + +/** * @internal This function creates the HDF5 dataset for a variable. * * @param grp Pointer to group info struct. @@ -1753,17 +1808,23 @@ nc4_create_dim_wo_var(NC_DIM_INFO_T *dim) BAIL(NC_EHDFERR); /* Set size of dataset to size of dimension. */ +#define USE_COMPACT 0 +#if USE_COMPACT + dims[0] = 1; + max_dims[0] = 1; +#else dims[0] = dim->len; max_dims[0] = dim->len; - +#endif /* If this dimension scale is unlimited (i.e. it's an unlimited * dimension), then set up chunking, with a chunksize of 1. */ if (dim->unlimited) { + dims[0] = dim->len; max_dims[0] = H5S_UNLIMITED; if (H5Pset_chunk(create_propid, 1, chunk_dims) < 0) BAIL(NC_EHDFERR); } /* Set up space. */ if ((spaceid = H5Screate_simple(1, dims, max_dims)) < 0) @@ -1796,6 +1863,11 @@ nc4_create_dim_wo_var(NC_DIM_INFO_T *dim) if ((retval = write_netcdf4_dimid(hdf5_dim->hdf_dimscaleid, dim->hdr.id))) BAIL(retval); + if (!dim->unlimited) { + if ((retval = write_netcdf4_dim_size(hdf5_dim->hdf_dimscaleid, dim->len))) + BAIL(retval); + } + exit: if (spaceid > 0 && H5Sclose(spaceid) < 0) BAIL2(NC_EHDFERR); diff --git a/nc_test4/tst_atts.c b/nc_test4/tst_atts.c index 0ebb015..61fce4e 100644 --- a/nc_test4/tst_atts.c +++ b/nc_test4/tst_atts.c @@ -42,6 +42,7 @@ static const char* NC_RESERVED_VARATT_LIST[] = { NC_ATT_NAME, NC_ATT_COORDINATES, NC_DIMID_ATT_NAME, + NC_DIMSIZE_ATT_NAME, NULL };