NetCDF  4.8.1
nc4attr.c
Go to the documentation of this file.
1 /* Copyright 2003-2018, University Corporation for Atmospheric
2  * Research. See COPYRIGHT file for copying and redistribution
3  * conditions. */
19 #include "nc.h"
20 #include "nc4internal.h"
21 #include "nc4dispatch.h"
22 #include "ncdispatch.h"
23 
45 int
46 nc4_get_att_ptrs(NC_FILE_INFO_T *h5, NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var,
47  const char *name, nc_type *xtype, nc_type mem_type,
48  size_t *lenp, int *attnum, void *data)
49 {
50  NC_ATT_INFO_T *att = NULL;
51  int my_attnum = -1;
52  int need_to_convert = 0;
53  int range_error = NC_NOERR;
54  void *bufr = NULL;
55  size_t type_size;
56  int varid;
57  int i;
58  int retval;
59 
60  LOG((3, "%s: mem_type %d", __func__, mem_type));
61 
62  /* Get the varid, or NC_GLOBAL. */
63  varid = var ? var->hdr.id : NC_GLOBAL;
64 
65  if (attnum)
66  my_attnum = *attnum;
67 
68  if (name == NULL)
69  BAIL(NC_EBADNAME);
70 
71  /* Find the attribute, if it exists. */
72  if ((retval = nc4_find_grp_att(grp, varid, name, my_attnum, &att)))
73  return retval;
74 
75  /* If mem_type is NC_NAT, it means we want to use the attribute's
76  * file type as the mem type as well. */
77  if (mem_type == NC_NAT)
78  mem_type = att->nc_typeid;
79 
80  /* If the attribute is NC_CHAR, and the mem_type isn't, or vice
81  * versa, that's a freakish attempt to convert text to
82  * numbers. Some pervert out there is trying to pull a fast one!
83  * Send him an NC_ECHAR error. */
84  if (data && att->len)
85  if ((att->nc_typeid == NC_CHAR && mem_type != NC_CHAR) ||
86  (att->nc_typeid != NC_CHAR && mem_type == NC_CHAR))
87  BAIL(NC_ECHAR); /* take that, you freak! */
88 
89  /* Copy the info. */
90  if (lenp)
91  *lenp = att->len;
92  if (xtype)
93  *xtype = att->nc_typeid;
94  if (attnum) {
95  *attnum = att->hdr.id;
96  }
97 
98  /* Zero len attributes are easy to read! */
99  if (!att->len)
100  BAIL(NC_NOERR);
101 
102  /* Later on, we will need to know the size of this type. */
103  if ((retval = nc4_get_typelen_mem(h5, mem_type, &type_size)))
104  BAIL(retval);
105 
106  /* We may have to convert data. Treat NC_CHAR the same as
107  * NC_UBYTE. If the mem_type is NAT, don't try any conversion - use
108  * the attribute's type. */
109  if (data && att->len && mem_type != att->nc_typeid &&
110  mem_type != NC_NAT &&
111  !(mem_type == NC_CHAR &&
112  (att->nc_typeid == NC_UBYTE || att->nc_typeid == NC_BYTE)))
113  {
114  if (!(bufr = malloc((size_t)(att->len * type_size))))
115  BAIL(NC_ENOMEM);
116  need_to_convert++;
117  if ((retval = nc4_convert_type(att->data, bufr, att->nc_typeid,
118  mem_type, (size_t)att->len, &range_error,
119  NULL, (h5->cmode & NC_CLASSIC_MODEL))))
120  BAIL(retval);
121 
122  /* For strict netcdf-3 rules, ignore erange errors between UBYTE
123  * and BYTE types. */
124  if ((h5->cmode & NC_CLASSIC_MODEL) &&
125  (att->nc_typeid == NC_UBYTE || att->nc_typeid == NC_BYTE) &&
126  (mem_type == NC_UBYTE || mem_type == NC_BYTE) &&
127  range_error)
128  range_error = 0;
129  }
130  else
131  {
132  bufr = att->data;
133  }
134 
135  /* If the caller wants data, copy it for him. If he hasn't
136  allocated enough memory for it, he will burn in segmentation
137  fault hell, writhing with the agony of undiscovered memory
138  bugs! */
139  if (data)
140  {
141  if (att->vldata)
142  {
143  size_t base_typelen;
144  nc_hvl_t *vldest = data;
145  NC_TYPE_INFO_T *type;
146 
147  /* Get the type object for the attribute's type */
148  if ((retval = nc4_find_type(h5, att->nc_typeid, &type)))
149  BAIL(retval);
150 
151  /* Retrieve the size of the base type */
152  if ((retval = nc4_get_typelen_mem(h5, type->u.v.base_nc_typeid, &base_typelen)))
153  BAIL(retval);
154 
155  for (i = 0; i < att->len; i++)
156  {
157  vldest[i].len = att->vldata[i].len;
158  if (!(vldest[i].p = malloc(vldest[i].len * base_typelen)))
159  BAIL(NC_ENOMEM);
160  memcpy(vldest[i].p, att->vldata[i].p, vldest[i].len * base_typelen);
161  }
162  }
163  else if (att->stdata)
164  {
165  for (i = 0; i < att->len; i++)
166  {
167  /* Check for NULL pointer for string (valid in HDF5) */
168  if(att->stdata[i])
169  {
170  if (!(((char **)data)[i] = strdup(att->stdata[i])))
171  BAIL(NC_ENOMEM);
172  }
173  else
174  ((char **)data)[i] = att->stdata[i];
175  }
176  }
177  else
178  {
179  memcpy(data, bufr, (size_t)(att->len * type_size));
180  }
181  }
182 
183 exit:
184  if (need_to_convert)
185  free(bufr);
186  if (range_error)
187  retval = NC_ERANGE;
188  return retval;
189 }
190 
212 int
213 nc4_get_att(int ncid, int varid, const char *name, nc_type *xtype,
214  nc_type mem_type, size_t *lenp, int *attnum, void *data)
215 {
216  NC_FILE_INFO_T *h5;
217  NC_GRP_INFO_T *grp;
218  NC_VAR_INFO_T *var = NULL;
219  char norm_name[NC_MAX_NAME + 1];
220  int retval;
221 
222  LOG((3, "%s: ncid 0x%x varid %d mem_type %d", __func__, ncid,
223  varid, mem_type));
224 
225  /* Find info for this file, group, and h5 info. */
226  if ((retval = nc4_find_grp_h5(ncid, &grp, &h5)))
227  return retval;
228  assert(h5 && grp);
229 
230  /* Check varid */
231  if (varid != NC_GLOBAL)
232  {
233  if (!(var = (NC_VAR_INFO_T*)ncindexith(grp->vars,varid)))
234  return NC_ENOTVAR;
235  assert(var->hdr.id == varid);
236  }
237 
238  /* Name is required. */
239  if (!name)
240  return NC_EBADNAME;
241 
242  /* Normalize name. */
243  if ((retval = nc4_normalize_name(name, norm_name)))
244  return retval;
245 
246  return nc4_get_att_ptrs(h5, grp, var, norm_name, xtype, mem_type, lenp,
247  attnum, data);
248 }
249 
264 int
265 NC4_inq_att(int ncid, int varid, const char *name, nc_type *xtypep,
266  size_t *lenp)
267 {
268  LOG((2, "%s: ncid 0x%x varid %d name %s", __func__, ncid, varid, name));
269  return nc4_get_att(ncid, varid, name, xtypep, NC_NAT, lenp, NULL, NULL);
270 }
271 
283 int
284 NC4_inq_attid(int ncid, int varid, const char *name, int *attnump)
285 {
286  LOG((2, "%s: ncid 0x%x varid %d name %s", __func__, ncid, varid, name));
287  return nc4_get_att(ncid, varid, name, NULL, NC_NAT, NULL, attnump, NULL);
288 }
289 
302 int
303 NC4_inq_attname(int ncid, int varid, int attnum, char *name)
304 {
305  NC_ATT_INFO_T *att;
306  int retval;
307 
308  LOG((2, "nc_inq_attname: ncid 0x%x varid %d attnum %d", ncid, varid,
309  attnum));
310 
311  /* Find the attribute metadata. */
312  if ((retval = nc4_find_nc_att(ncid, varid, NULL, attnum, &att)))
313  return retval;
314 
315  /* Get the name. */
316  if (name)
317  strcpy(name, att->hdr.name);
318 
319  return NC_NOERR;
320 }
321 
335 int
336 NC4_get_att(int ncid, int varid, const char *name, void *value, nc_type memtype)
337 {
338  return nc4_get_att(ncid, varid, name, NULL, memtype, NULL, NULL, value);
339 }
NC_NOERR
#define NC_NOERR
No Error.
Definition: netcdf.h:333
NC_BYTE
#define NC_BYTE
signed 1 byte integer
Definition: netcdf.h:35
NC_MAX_NAME
#define NC_MAX_NAME
Maximum for classic library.
Definition: netcdf.h:276
NC_UBYTE
#define NC_UBYTE
unsigned 1 byte int
Definition: netcdf.h:42
NC_ERANGE
#define NC_ERANGE
Math result not representable.
Definition: netcdf.h:412
NC_GLOBAL
#define NC_GLOBAL
Attribute id to put/get a global attribute.
Definition: netcdf.h:249
nc_type
int nc_type
The nc_type type is just an int.
Definition: netcdf.h:25
NC_ECHAR
#define NC_ECHAR
Attempt to convert between text & numbers.
Definition: netcdf.h:394
NC_CLASSIC_MODEL
#define NC_CLASSIC_MODEL
Enforce classic model on netCDF-4.
Definition: netcdf.h:139
NC_ENOMEM
#define NC_ENOMEM
Memory allocation (malloc) failure.
Definition: netcdf.h:413
NC_NAT
#define NC_NAT
Not A Type.
Definition: netcdf.h:34
NC_CHAR
#define NC_CHAR
ISO/ASCII character.
Definition: netcdf.h:36
NC_ENOTVAR
#define NC_ENOTVAR
Variable not found.
Definition: netcdf.h:387
NC_EBADNAME
#define NC_EBADNAME
Attribute or variable name contains illegal characters.
Definition: netcdf.h:405