mirror of
https://github.com/Unidata/netcdf-c.git
synced 2025-04-12 18:10:24 +08:00
re: github issue https://github.com/Unidata/netcdf-c/issues/265
Charlie Zender noted that we forgot to define what happens for various netcdf API attribute operations, notably nc_inq_att() and nc_get_att(). So, I added a list of legal and illegal api calls for the provenance attributes in docs/attribute_conventions.md. I also added more test cases to ncdump/tst_fileinfo.c to verify and fixed resultant errors.
This commit is contained in:
parent
f8117f150f
commit
4fa1470241
@ -131,17 +131,34 @@ It is strongly recommended that applicable conventions be followed unless there
|
||||
|
||||
These attributes can occur in netCDF enhanced (netcdf-4) files beginning
|
||||
with version 4.4.1. They all are associated with the root group as
|
||||
global attributes. They are hidden in the sense that they can only be
|
||||
accessed thru the netcdf-C api calls via the name. They have no
|
||||
attribute number and will not be counted in the number of global
|
||||
attributes in the root group. The simplest way to view these attributes
|
||||
is to use the -s flag to the ncdump command.
|
||||
global attributes. They are hidden in the sense that they have no
|
||||
attribute number, so they can only be accessed thru the netcdf-C api
|
||||
calls via the name. Additionally, these attributes will not be counted
|
||||
in the number of global attributes in the root group.
|
||||
|
||||
The simplest way to view these attributes is to use the -s flag to the
|
||||
ncdump command. Alternatively, one can use the following API calls to
|
||||
obtain information.
|
||||
- nc_inq_att
|
||||
- nc_inq_atttype
|
||||
- nc_inq_attlen
|
||||
- nc_get_att (and derivatives)
|
||||
|
||||
Using the following API calls will fail.
|
||||
- nc_inq_attid
|
||||
- nc_inq_attname
|
||||
- nc_copy_att
|
||||
- nc_rename_att
|
||||
- nc_del_att
|
||||
- nc_put_att (and derivatives)
|
||||
|
||||
|
||||
`_NCProperties`
|
||||
|
||||
> This attribute is persistent in the file, but hidden. It is inserted in the file at creation time and is never modified after that point. It specifies the following.
|
||||
> - The version for the netcdf library used at creation time.
|
||||
> - The version for the HDF5 library used at creation time.
|
||||
> - The type of this attribute is NC_CHAR.
|
||||
|
||||
> Its format is: `name=value|name=value ...`<br>
|
||||
> Occurrences of '|' in the name or value are disallowed.
|
||||
@ -155,6 +172,7 @@ is to use the -s flag to the ncdump command.
|
||||
|
||||
> This attribute is ephemeral in that it is computed by looking at the file's HDF5 superblock.
|
||||
> It has this form: `_SuperBlockVersion = 0|1|2|3|...`
|
||||
> The type of this attribute is NC_INT.
|
||||
|
||||
`_IsNetcdf4`
|
||||
|
||||
@ -162,6 +180,7 @@ is to use the -s flag to the ncdump command.
|
||||
|
||||
> The _IsNetcdf4 attribute has the form: `_IsNetcdf4 = 0|1`
|
||||
> where 1 means the file has various tags indicating it was produced thru the netcdf-4 API.
|
||||
> The type of this attribute is NC_INT.
|
||||
|
||||
> This attribute is computed by using the HDF5 API to walk the file to look for attributes specific to netcdf-4. False negatives are possible for a small subset of netcdf-4 files, especially those not containing dimensions. False positives are only possible by deliberate modifications to an existing HDF5 file thru the HDF5 API. For files with the _NCProperties attribute, this attribute is redundant. For files created prior to the introduction of the _NCProperties attribute, this may be a useful indicator of the provenance of the file.
|
||||
|
||||
|
@ -22,7 +22,8 @@ conditions.
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_FILEINFO
|
||||
static int nc4_get_att_special(NC_HDF5_FILE_INFO_T*, const char*, nc_type, int, void*, size_t*, int*);
|
||||
static int nc4_get_att_special(NC_HDF5_FILE_INFO_T*, const char*,
|
||||
nc_type*, nc_type, size_t*, int*, int, void*);
|
||||
#endif
|
||||
|
||||
int nc4typelen(nc_type type);
|
||||
@ -70,7 +71,7 @@ nc4_get_att(int ncid, NC *nc, int varid, const char *name,
|
||||
const char** sp;
|
||||
for(sp = NC_RESERVED_SPECIAL_LIST;*sp;sp++) {
|
||||
if(strcmp(name,*sp)==0) {
|
||||
return nc4_get_att_special(h5, norm_name, mem_type, is_long, data, lenp, attnum);
|
||||
return nc4_get_att_special(h5, norm_name, xtype, mem_type, lenp, attnum, is_long, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -546,8 +547,8 @@ nc4_put_att(int ncid, NC *nc, int varid, const char *name,
|
||||
return NC_NOERR;
|
||||
}
|
||||
|
||||
/* Learn about an att. All the nc4 nc_inq_ functions just call
|
||||
* add_meta_get to get the metadata on an attribute. */
|
||||
/* Learn about an att. All the nc4 nc_inq_ functions just call
|
||||
* nc4_get_att to get the metadata on an attribute. */
|
||||
int
|
||||
NC4_inq_att(int ncid, int varid, const char *name, nc_type *xtypep, size_t *lenp)
|
||||
{
|
||||
@ -578,7 +579,7 @@ NC4_inq_att(int ncid, int varid, const char *name, nc_type *xtypep, size_t *lenp
|
||||
#endif /* USE_PNETCDF */
|
||||
|
||||
/* Handle netcdf-4 files. */
|
||||
return nc4_get_att(ncid, nc, varid, name, xtypep, NC_UBYTE, lenp, NULL, 0, NULL);
|
||||
return nc4_get_att(ncid, nc, varid, name, xtypep, NC_NAT, lenp, NULL, 0, NULL);
|
||||
}
|
||||
|
||||
/* Learn an attnum, given a name. */
|
||||
@ -587,6 +588,7 @@ NC4_inq_attid(int ncid, int varid, const char *name, int *attnump)
|
||||
{
|
||||
NC *nc;
|
||||
NC_HDF5_FILE_INFO_T *h5;
|
||||
int stat;
|
||||
|
||||
LOG((2, "nc_inq_attid: ncid 0x%x varid %d name %s", ncid, varid, name));
|
||||
|
||||
@ -605,8 +607,9 @@ NC4_inq_attid(int ncid, int varid, const char *name, int *attnump)
|
||||
#endif /* USE_PNETCDF */
|
||||
|
||||
/* Handle netcdf-4 files. */
|
||||
return nc4_get_att(ncid, nc, varid, name, NULL, NC_UBYTE,
|
||||
stat = nc4_get_att(ncid, nc, varid, name, NULL, NC_NAT,
|
||||
NULL, attnump, 0, NULL);
|
||||
return stat;
|
||||
}
|
||||
|
||||
|
||||
@ -950,24 +953,33 @@ nc4_put_att_tc(int ncid, int varid, const char *name, nc_type file_type,
|
||||
|
||||
#ifdef ENABLE_FILEINFO
|
||||
static int
|
||||
nc4_get_att_special(NC_HDF5_FILE_INFO_T *h5, const char* name, nc_type mem_type, int islong, void* data, size_t* lenp, int* idp)
|
||||
nc4_get_att_special(NC_HDF5_FILE_INFO_T* h5, const char* name,
|
||||
nc_type* filetypep, nc_type mem_type, size_t* lenp,
|
||||
int* attnump, int is_long, void* data)
|
||||
{
|
||||
/* Always make the attr id be -1 */
|
||||
if(idp) *idp = -1;
|
||||
/* Fail if asking for att id */
|
||||
if(attnump)
|
||||
return NC_EATTMETA;
|
||||
|
||||
if(strcmp(name,NCPROPS)==0) {
|
||||
if(h5->fileinfo->propattr.version == 0)
|
||||
return NC_ENOTATT;
|
||||
if(mem_type == NC_NAT) mem_type = NC_CHAR;
|
||||
if(mem_type != NC_CHAR)
|
||||
return NC_ECHAR;
|
||||
if(filetypep) *filetypep = NC_CHAR;
|
||||
if(lenp) *lenp = strlen(h5->fileinfo->propattr.text);
|
||||
if(data) strcpy((char*)data,h5->fileinfo->propattr.text);
|
||||
} else if(strcmp(name,ISNETCDF4ATT)==0
|
||||
|| strcmp(name,SUPERBLOCKATT)==0) {
|
||||
unsigned long long iv = 0;
|
||||
if(filetypep) *filetypep = NC_INT;
|
||||
if(lenp) *lenp = 1;
|
||||
if(strcmp(name,SUPERBLOCKATT)==0)
|
||||
iv = (unsigned long long)h5->fileinfo->superblockversion;
|
||||
else /* strcmp(name,ISNETCDF4ATT)==0 */
|
||||
iv = NC4_isnetcdf4(h5);
|
||||
if(lenp) *lenp = 1;
|
||||
if(mem_type == NC_NAT) mem_type = NC_INT;
|
||||
if(data)
|
||||
switch (mem_type) {
|
||||
case NC_BYTE: *((char*)data) = (char)iv; break;
|
||||
|
@ -71,14 +71,16 @@ main(int argc, char **argv)
|
||||
}
|
||||
|
||||
{
|
||||
int root, grpid, varid, stat, natts;
|
||||
int root, grpid, varid, stat, natts, id;
|
||||
int data = 17;
|
||||
const char* sdata = "text";
|
||||
char ncprops[8192];
|
||||
size_t len;
|
||||
int dimid;
|
||||
nc_type xtype;
|
||||
char name[NC_MAX_NAME];
|
||||
|
||||
printf("*** creating netcdf-4 test file using netCDF %s...", NC4FILE);
|
||||
printf("\n*** creating netcdf-4 test file using netCDF %s...", NC4FILE);
|
||||
|
||||
if(nc_create(NC4FILE,NC_WRITE|NC_CLOBBER|NC_NETCDF4,&root)!=0) ERR;
|
||||
/* Create global attribute */
|
||||
@ -107,9 +109,24 @@ main(int argc, char **argv)
|
||||
|
||||
/* Now, fiddle with the NCPROPS attribute */
|
||||
|
||||
/* Get its value */
|
||||
if(nc_inq_att(root,NC_GLOBAL,NCPROPS,NULL,&len)!=0) ERR;
|
||||
/* Get its metadata */
|
||||
if(nc_inq_att(root,NC_GLOBAL,NCPROPS,&xtype,&len)!=0) ERR;
|
||||
if(xtype != NC_CHAR) ERR;
|
||||
|
||||
/* Read in two ways */
|
||||
if(nc_get_att_text(root,NC_GLOBAL,NCPROPS,ncprops)!=0) ERR;
|
||||
if(strlen(ncprops) != len) ERR;
|
||||
|
||||
/* Attempt to get attribute metadata piecemeal; some will fail */
|
||||
id = -1;
|
||||
stat = nc_inq_attid(root,NC_GLOBAL,NCPROPS,&id);
|
||||
if(stat == NC_NOERR) ERR;
|
||||
stat = nc_inq_attname(root,NC_GLOBAL,id,name);
|
||||
if(stat == NC_NOERR) ERR;
|
||||
if(nc_inq_atttype(root,NC_GLOBAL,NCPROPS,&xtype)!=0) ERR;
|
||||
if(xtype != NC_CHAR) ERR;
|
||||
if(nc_inq_attlen(root,NC_GLOBAL,NCPROPS,&len)!=0) ERR;
|
||||
if(len != strlen(ncprops)) ERR;
|
||||
|
||||
/*Overwrite _NCProperties root attribute; should fail */
|
||||
stat = nc_put_att_text(root,NC_GLOBAL,NCPROPS,strlen(sdata),sdata);
|
||||
@ -121,11 +138,23 @@ main(int argc, char **argv)
|
||||
|
||||
/* Ditto _SuperblockVersion */
|
||||
|
||||
/* Get its value */
|
||||
if(nc_inq_att(root,NC_GLOBAL,SUPERBLOCKATT,NULL,&len)!=0) ERR;
|
||||
/* Get its metadata */
|
||||
if(nc_inq_att(root,NC_GLOBAL,SUPERBLOCKATT,&xtype,&len)!=0) ERR;
|
||||
if(xtype != NC_INT) ERR;
|
||||
if(len != 1) ERR;
|
||||
|
||||
if(nc_get_att_int(root,NC_GLOBAL,SUPERBLOCKATT,&data)!=0) ERR;
|
||||
|
||||
/* Attempt to get attribute metadata piecemeal */
|
||||
stat = nc_inq_attid(root,NC_GLOBAL,SUPERBLOCKATT,&id);
|
||||
if(stat == NC_NOERR) ERR;
|
||||
stat = nc_inq_attname(root,NC_GLOBAL,id,name);
|
||||
if(stat == NC_NOERR) ERR;
|
||||
if(nc_inq_atttype(root,NC_GLOBAL,SUPERBLOCKATT,&xtype)!=0) ERR;
|
||||
if(xtype != NC_INT) ERR;
|
||||
if(nc_inq_attlen(root,NC_GLOBAL,SUPERBLOCKATT,&len)!=0) ERR;
|
||||
if(len != 1) ERR;
|
||||
|
||||
/*Overwrite; should fail */
|
||||
stat = nc_put_att_int(root,NC_GLOBAL,NCPROPS,NC_INT,1,&data);
|
||||
if(stat == NC_NOERR) ERR;
|
||||
@ -136,11 +165,23 @@ main(int argc, char **argv)
|
||||
|
||||
/* Ditto _IsNetcdf4 */
|
||||
|
||||
/* Get its value */
|
||||
if(nc_inq_att(root,NC_GLOBAL,ISNETCDF4ATT,NULL,&len)!=0) ERR;
|
||||
/* Get its metadata */
|
||||
if(nc_inq_att(root,NC_GLOBAL,ISNETCDF4ATT,&xtype,&len)!=0) ERR;
|
||||
if(xtype != NC_INT) ERR;
|
||||
if(len != 1) ERR;
|
||||
|
||||
if(nc_get_att_int(root,NC_GLOBAL,ISNETCDF4ATT,&data)!=0) ERR;
|
||||
|
||||
/* Attempt to get attribute metadata piecemeal */
|
||||
stat = nc_inq_attid(root,NC_GLOBAL,ISNETCDF4ATT,&id);
|
||||
if(stat == NC_NOERR) ERR;
|
||||
stat = nc_inq_attname(root,NC_GLOBAL,id,name);
|
||||
if(stat == NC_NOERR) ERR;
|
||||
if(nc_inq_atttype(root,NC_GLOBAL,ISNETCDF4ATT,&xtype)!=0) ERR;
|
||||
if(xtype != NC_INT) ERR;
|
||||
if(nc_inq_attlen(root,NC_GLOBAL,ISNETCDF4ATT,&len)!=0) ERR;
|
||||
if(len != 1) ERR;
|
||||
|
||||
/*Overwrite; should fail */
|
||||
stat = nc_put_att_int(root,NC_GLOBAL,ISNETCDF4ATT,NC_INT,1,&data);
|
||||
if(stat == NC_NOERR) ERR;
|
||||
|
@ -698,6 +698,9 @@ test_ncattcopy(path1, path2)
|
||||
error("%s: ncendef failed", pname);
|
||||
ncclose(cdfid); return ++nerrs;
|
||||
}
|
||||
if(strcmp(path1, "nctest_netcdf4.nc")==0) {
|
||||
int x=0;
|
||||
}
|
||||
/* first (source) netcdf is in data mode */
|
||||
/* create second netCDF to copy attributes to */
|
||||
if ((cdfid2 = nccreate(path2, NC_CLOBBER)) == -1) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user