/src/netcdf-c/libsrc4/nc4attr.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright 2003-2018, University Corporation for Atmospheric |
2 | | * Research. See COPYRIGHT file for copying and redistribution |
3 | | * conditions. */ |
4 | | /** |
5 | | * @file |
6 | | * |
7 | | * @internal This file is part of netcdf-4, a netCDF-like interface |
8 | | * for HDF5, or a HDF5 backend for netCDF, depending on your point of |
9 | | * view. |
10 | | * |
11 | | * This file handles the nc4 attribute functions. |
12 | | * |
13 | | * Remember that with atts, type conversion can take place when |
14 | | * writing them, and when reading them. |
15 | | * |
16 | | * @author Ed Hartnett |
17 | | */ |
18 | | |
19 | | #include "nc.h" |
20 | | #include "nc4internal.h" |
21 | | #include "nc4dispatch.h" |
22 | | #include "ncdispatch.h" |
23 | | |
24 | | /** |
25 | | * @internal Get or put attribute metadata from our linked list of |
26 | | * file info. Always locate the attribute by name, never by attnum. |
27 | | * The mem_type is ignored if data=NULL. |
28 | | * |
29 | | * @param ncid File and group ID. |
30 | | * @param varid Variable ID. |
31 | | * @param name Name of attribute. Must already be normalized. |
32 | | * @param xtype Pointer that gets (file) type of attribute. Ignored if |
33 | | * NULL. |
34 | | * @param mem_type The type of attribute data in memory. |
35 | | * @param lenp Pointer that gets length of attribute array. Ignored if |
36 | | * NULL. |
37 | | * @param attnum Pointer that gets the index number of this |
38 | | * attribute. Ignored if NULL. |
39 | | * @param data Pointer that gets attribute data. Ignored if NULL. |
40 | | * |
41 | | * @return ::NC_NOERR No error. |
42 | | * @return ::NC_EBADID Bad ncid. |
43 | | * @author Ed Hartnett |
44 | | */ |
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 | 0 | { |
50 | 0 | NC_ATT_INFO_T *att = NULL; |
51 | 0 | int my_attnum = -1; |
52 | 0 | int need_to_convert = 0; |
53 | 0 | int range_error = NC_NOERR; |
54 | 0 | void *bufr = NULL; |
55 | 0 | size_t type_size; |
56 | 0 | int varid; |
57 | 0 | int retval; |
58 | |
|
59 | 0 | LOG((3, "%s: mem_type %d", __func__, mem_type)); |
60 | | |
61 | | /* Get the varid, or NC_GLOBAL. */ |
62 | 0 | varid = var ? var->hdr.id : NC_GLOBAL; |
63 | |
|
64 | 0 | if (attnum) |
65 | 0 | my_attnum = *attnum; |
66 | |
|
67 | 0 | if (name == NULL) |
68 | 0 | BAIL(NC_EBADNAME); |
69 | | |
70 | | /* Find the attribute, if it exists. */ |
71 | 0 | if ((retval = nc4_find_grp_att(grp, varid, name, my_attnum, &att))) |
72 | 0 | return retval; |
73 | | |
74 | | /* If mem_type is NC_NAT, it means we want to use the attribute's |
75 | | * file type as the mem type as well. */ |
76 | 0 | if (mem_type == NC_NAT) |
77 | 0 | mem_type = att->nc_typeid; |
78 | | |
79 | | /* If the attribute is NC_CHAR, and the mem_type isn't, or vice |
80 | | * versa, that's a freakish attempt to convert text to |
81 | | * numbers. Some pervert out there is trying to pull a fast one! |
82 | | * Send him an NC_ECHAR error. */ |
83 | 0 | if (data && att->len) |
84 | 0 | if ((att->nc_typeid == NC_CHAR && mem_type != NC_CHAR) || |
85 | 0 | (att->nc_typeid != NC_CHAR && mem_type == NC_CHAR)) |
86 | 0 | BAIL(NC_ECHAR); /* take that, you freak! */ |
87 | | |
88 | | /* Copy the info. */ |
89 | 0 | if (lenp) |
90 | 0 | *lenp = att->len; |
91 | 0 | if (xtype) |
92 | 0 | *xtype = att->nc_typeid; |
93 | 0 | if (attnum) { |
94 | 0 | *attnum = att->hdr.id; |
95 | 0 | } |
96 | | |
97 | | /* Zero len attributes are easy to read! */ |
98 | 0 | if (!att->len) |
99 | 0 | BAIL(NC_NOERR); |
100 | | |
101 | | /* Later on, we will need to know the size of this type. */ |
102 | 0 | if ((retval = nc4_get_typelen_mem(h5, mem_type, &type_size))) |
103 | 0 | BAIL(retval); |
104 | | |
105 | | /* We may have to convert data. Treat NC_CHAR the same as |
106 | | * NC_UBYTE. If the mem_type is NAT, don't try any conversion - use |
107 | | * the attribute's type. */ |
108 | 0 | if (data && att->len && mem_type != att->nc_typeid && |
109 | 0 | mem_type != NC_NAT && |
110 | 0 | !(mem_type == NC_CHAR && |
111 | 0 | (att->nc_typeid == NC_UBYTE || att->nc_typeid == NC_BYTE))) |
112 | 0 | { |
113 | 0 | if (!(bufr = malloc((size_t)(att->len * type_size)))) |
114 | 0 | BAIL(NC_ENOMEM); |
115 | 0 | need_to_convert++; |
116 | 0 | if ((retval = nc4_convert_type(att->data, bufr, att->nc_typeid, |
117 | 0 | mem_type, (size_t)att->len, &range_error, |
118 | 0 | NULL, (h5->cmode & NC_CLASSIC_MODEL), |
119 | 0 | NC_NOQUANTIZE, 0))) |
120 | 0 | BAIL(retval); |
121 | | |
122 | | /* For strict netcdf-3 rules, ignore erange errors between UBYTE |
123 | | * and BYTE types. */ |
124 | 0 | if ((h5->cmode & NC_CLASSIC_MODEL) && |
125 | 0 | (att->nc_typeid == NC_UBYTE || att->nc_typeid == NC_BYTE) && |
126 | 0 | (mem_type == NC_UBYTE || mem_type == NC_BYTE) && |
127 | 0 | range_error) |
128 | 0 | range_error = 0; |
129 | 0 | } |
130 | 0 | else |
131 | 0 | { |
132 | 0 | bufr = att->data; |
133 | 0 | } |
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 | 0 | if (data) |
140 | 0 | { |
141 | | #ifdef SEPDATA |
142 | | if (att->vldata) |
143 | | { |
144 | | size_t base_typelen; |
145 | | nc_hvl_t *vldest = data; |
146 | | NC_TYPE_INFO_T *type; |
147 | | int i; |
148 | | |
149 | | /* Get the type object for the attribute's type */ |
150 | | if ((retval = nc4_find_type(h5, att->nc_typeid, &type))) |
151 | | BAIL(retval); |
152 | | |
153 | | /* Retrieve the size of the base type */ |
154 | | if ((retval = nc4_get_typelen_mem(h5, type->u.v.base_nc_typeid, &base_typelen))) |
155 | | BAIL(retval); |
156 | | |
157 | | for (i = 0; i < att->len; i++) |
158 | | { |
159 | | vldest[i].len = att->vldata[i].len; |
160 | | if (!(vldest[i].p = malloc(vldest[i].len * base_typelen))) |
161 | | BAIL(NC_ENOMEM); |
162 | | memcpy(vldest[i].p, att->vldata[i].p, vldest[i].len * base_typelen); |
163 | | } |
164 | | } |
165 | | else if (att->stdata) |
166 | | { |
167 | | int i; |
168 | | for (i = 0; i < att->len; i++) |
169 | | { |
170 | | /* Check for NULL pointer for string (valid in HDF5) */ |
171 | | if(att->stdata[i]) |
172 | | { |
173 | | if (!(((char **)data)[i] = strdup(att->stdata[i]))) |
174 | | BAIL(NC_ENOMEM); |
175 | | } |
176 | | else |
177 | | ((char **)data)[i] = att->stdata[i]; |
178 | | } |
179 | | } |
180 | | else |
181 | | { |
182 | | memcpy(data, bufr, (size_t)(att->len * type_size)); |
183 | | } |
184 | | #else |
185 | 0 | { |
186 | 0 | if((retval = nc_copy_data(h5->controller->ext_ncid,mem_type,bufr,att->len,data))) |
187 | 0 | BAIL(retval); |
188 | 0 | } |
189 | 0 | #endif |
190 | 0 | } |
191 | | |
192 | 0 | exit: |
193 | 0 | if (need_to_convert) |
194 | 0 | free(bufr); |
195 | 0 | if (range_error) |
196 | 0 | retval = NC_ERANGE; |
197 | 0 | return retval; |
198 | 0 | } |
199 | | |
200 | | /** |
201 | | * @internal Get or put attribute metadata from our linked list of |
202 | | * file info. Always locate the attribute by name, never by attnum. |
203 | | * The mem_type is ignored if data=NULL. |
204 | | * |
205 | | * @param ncid File and group ID. |
206 | | * @param varid Variable ID. |
207 | | * @param name Name of attribute. |
208 | | * @param xtype Pointer that gets (file) type of attribute. Ignored if |
209 | | * NULL. |
210 | | * @param mem_type The type of attribute data in memory. |
211 | | * @param lenp Pointer that gets length of attribute array. Ignored if |
212 | | * NULL. |
213 | | * @param attnum Pointer that gets the index number of this |
214 | | * attribute. Ignored if NULL. |
215 | | * @param data Pointer that gets attribute data. Ignored if NULL. |
216 | | * |
217 | | * @return ::NC_NOERR No error. |
218 | | * @return ::NC_EBADID Bad ncid. |
219 | | * @author Ed Hartnett |
220 | | */ |
221 | | int |
222 | | nc4_get_att(int ncid, int varid, const char *name, nc_type *xtype, |
223 | | nc_type mem_type, size_t *lenp, int *attnum, void *data) |
224 | 0 | { |
225 | 0 | NC_FILE_INFO_T *h5; |
226 | 0 | NC_GRP_INFO_T *grp; |
227 | 0 | NC_VAR_INFO_T *var = NULL; |
228 | 0 | char norm_name[NC_MAX_NAME + 1]; |
229 | 0 | int retval; |
230 | |
|
231 | 0 | LOG((3, "%s: ncid 0x%x varid %d mem_type %d", __func__, ncid, |
232 | 0 | varid, mem_type)); |
233 | | |
234 | | /* Find info for this file, group, and h5 info. */ |
235 | 0 | if ((retval = nc4_find_grp_h5(ncid, &grp, &h5))) |
236 | 0 | return retval; |
237 | 0 | assert(h5 && grp); |
238 | | |
239 | | /* Check varid */ |
240 | 0 | if (varid != NC_GLOBAL) |
241 | 0 | { |
242 | 0 | if (!(var = (NC_VAR_INFO_T*)ncindexith(grp->vars,varid))) |
243 | 0 | return NC_ENOTVAR; |
244 | 0 | assert(var->hdr.id == varid); |
245 | 0 | } |
246 | | |
247 | | /* Name is required. */ |
248 | 0 | if (!name) |
249 | 0 | return NC_EBADNAME; |
250 | | |
251 | | /* Normalize name. */ |
252 | 0 | if ((retval = nc4_normalize_name(name, norm_name))) |
253 | 0 | return retval; |
254 | | |
255 | 0 | return nc4_get_att_ptrs(h5, grp, var, norm_name, xtype, mem_type, lenp, |
256 | 0 | attnum, data); |
257 | 0 | } |
258 | | |
259 | | /** |
260 | | * @internal Learn about an att. All the nc4 nc_inq_ functions just |
261 | | * call nc4_get_att to get the metadata on an attribute. |
262 | | * |
263 | | * @param ncid File and group ID. |
264 | | * @param varid Variable ID. |
265 | | * @param name Name of attribute. |
266 | | * @param xtypep Pointer that gets type of attribute. |
267 | | * @param lenp Pointer that gets length of attribute data array. |
268 | | * |
269 | | * @return ::NC_NOERR No error. |
270 | | * @return ::NC_EBADID Bad ncid. |
271 | | * @author Ed Hartnett |
272 | | */ |
273 | | int |
274 | | NC4_inq_att(int ncid, int varid, const char *name, nc_type *xtypep, |
275 | | size_t *lenp) |
276 | 0 | { |
277 | 0 | LOG((2, "%s: ncid 0x%x varid %d name %s", __func__, ncid, varid, name)); |
278 | 0 | return nc4_get_att(ncid, varid, name, xtypep, NC_NAT, lenp, NULL, NULL); |
279 | 0 | } |
280 | | |
281 | | /** |
282 | | * @internal Learn an attnum, given a name. |
283 | | * |
284 | | * @param ncid File and group ID. |
285 | | * @param varid Variable ID. |
286 | | * @param name Name of attribute. |
287 | | * @param attnump Pointer that gets the attribute index number. |
288 | | * |
289 | | * @return ::NC_NOERR No error. |
290 | | * @author Ed Hartnett |
291 | | */ |
292 | | int |
293 | | NC4_inq_attid(int ncid, int varid, const char *name, int *attnump) |
294 | 0 | { |
295 | 0 | LOG((2, "%s: ncid 0x%x varid %d name %s", __func__, ncid, varid, name)); |
296 | 0 | return nc4_get_att(ncid, varid, name, NULL, NC_NAT, NULL, attnump, NULL); |
297 | 0 | } |
298 | | |
299 | | /** |
300 | | * @internal Given an attnum, find the att's name. |
301 | | * |
302 | | * @param ncid File and group ID. |
303 | | * @param varid Variable ID. |
304 | | * @param attnum The index number of the attribute. |
305 | | * @param name Pointer that gets name of attribute. |
306 | | * |
307 | | * @return ::NC_NOERR No error. |
308 | | * @return ::NC_EBADID Bad ncid. |
309 | | * @author Ed Hartnett |
310 | | */ |
311 | | int |
312 | | NC4_inq_attname(int ncid, int varid, int attnum, char *name) |
313 | 0 | { |
314 | 0 | NC_ATT_INFO_T *att; |
315 | 0 | int retval; |
316 | |
|
317 | 0 | LOG((2, "nc_inq_attname: ncid 0x%x varid %d attnum %d", ncid, varid, |
318 | 0 | attnum)); |
319 | | |
320 | | /* Find the attribute metadata. */ |
321 | 0 | if ((retval = nc4_find_nc_att(ncid, varid, NULL, attnum, &att))) |
322 | 0 | return retval; |
323 | | |
324 | | /* Get the name. */ |
325 | 0 | if (name) |
326 | 0 | strcpy(name, att->hdr.name); |
327 | |
|
328 | 0 | return NC_NOERR; |
329 | 0 | } |
330 | | |
331 | | /** |
332 | | * @internal Get an attribute. |
333 | | * |
334 | | * @param ncid File and group ID. |
335 | | * @param varid Variable ID. |
336 | | * @param name Name of attribute. |
337 | | * @param value Pointer that gets attribute data. |
338 | | * @param memtype The type the data should be converted to as it is read. |
339 | | * |
340 | | * @return ::NC_NOERR No error. |
341 | | * @return ::NC_EBADID Bad ncid. |
342 | | * @author Ed Hartnett |
343 | | */ |
344 | | int |
345 | | NC4_get_att(int ncid, int varid, const char *name, void *value, nc_type memtype) |
346 | 0 | { |
347 | 0 | return nc4_get_att(ncid, varid, name, NULL, memtype, NULL, NULL, value); |
348 | 0 | } |