/src/gdal/netcdf-c-4.7.4/libsrc4/nc4attr.c
Line | Count | Source |
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 | 895k | { |
50 | 895k | NC_ATT_INFO_T *att = NULL; |
51 | 895k | int my_attnum = -1; |
52 | 895k | int need_to_convert = 0; |
53 | 895k | int range_error = NC_NOERR; |
54 | 895k | void *bufr = NULL; |
55 | 895k | size_t type_size; |
56 | 895k | int varid; |
57 | 895k | int i; |
58 | 895k | int retval; |
59 | | |
60 | 895k | LOG((3, "%s: mem_type %d", __func__, mem_type)); |
61 | | |
62 | | /* Get the varid, or NC_GLOBAL. */ |
63 | 895k | varid = var ? var->hdr.id : NC_GLOBAL; |
64 | | |
65 | 895k | if (attnum) |
66 | 163k | my_attnum = *attnum; |
67 | | |
68 | 895k | if (name == NULL) |
69 | 0 | BAIL(NC_EBADNAME); |
70 | | |
71 | | /* Find the attribute, if it exists. */ |
72 | 895k | if ((retval = nc4_find_grp_att(grp, varid, name, my_attnum, &att))) |
73 | 705k | 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 | 189k | if (mem_type == NC_NAT) |
78 | 113k | 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 | 189k | if (data && att->len) |
85 | 67.5k | if ((att->nc_typeid == NC_CHAR && mem_type != NC_CHAR) || |
86 | 67.5k | (att->nc_typeid != NC_CHAR && mem_type == NC_CHAR)) |
87 | 0 | BAIL(NC_ECHAR); /* take that, you freak! */ |
88 | | |
89 | | /* Copy the info. */ |
90 | 189k | if (lenp) |
91 | 76.0k | *lenp = att->len; |
92 | 189k | if (xtype) |
93 | 89.4k | *xtype = att->nc_typeid; |
94 | 189k | if (attnum) { |
95 | 2.04k | *attnum = att->hdr.id; |
96 | 2.04k | } |
97 | | |
98 | | /* Zero len attributes are easy to read! */ |
99 | 189k | if (!att->len) |
100 | 18.2k | BAIL(NC_NOERR); |
101 | | |
102 | | /* Later on, we will need to know the size of this type. */ |
103 | 171k | if ((retval = nc4_get_typelen_mem(h5, mem_type, &type_size))) |
104 | 0 | 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 | 171k | if (data && att->len && mem_type != att->nc_typeid && |
110 | 0 | mem_type != NC_NAT && |
111 | 0 | !(mem_type == NC_CHAR && |
112 | 0 | (att->nc_typeid == NC_UBYTE || att->nc_typeid == NC_BYTE))) |
113 | 0 | { |
114 | 0 | if (!(bufr = malloc((size_t)(att->len * type_size)))) |
115 | 0 | BAIL(NC_ENOMEM); |
116 | 0 | need_to_convert++; |
117 | 0 | if ((retval = nc4_convert_type(att->data, bufr, att->nc_typeid, |
118 | 0 | mem_type, (size_t)att->len, &range_error, |
119 | 0 | NULL, (h5->cmode & NC_CLASSIC_MODEL)))) |
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 | 171k | else |
131 | 171k | { |
132 | 171k | bufr = att->data; |
133 | 171k | } |
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 | 171k | if (data) |
140 | 67.5k | { |
141 | 67.5k | if (att->vldata) |
142 | 0 | { |
143 | 0 | size_t base_typelen; |
144 | 0 | nc_hvl_t *vldest = data; |
145 | 0 | NC_TYPE_INFO_T *type; |
146 | | |
147 | | /* Get the type object for the attribute's type */ |
148 | 0 | if ((retval = nc4_find_type(h5, att->nc_typeid, &type))) |
149 | 0 | BAIL(retval); |
150 | | |
151 | | /* Retrieve the size of the base type */ |
152 | 0 | if ((retval = nc4_get_typelen_mem(h5, type->u.v.base_nc_typeid, &base_typelen))) |
153 | 0 | BAIL(retval); |
154 | | |
155 | 0 | for (i = 0; i < att->len; i++) |
156 | 0 | { |
157 | 0 | vldest[i].len = att->vldata[i].len; |
158 | 0 | if (!(vldest[i].p = malloc(vldest[i].len * base_typelen))) |
159 | 0 | BAIL(NC_ENOMEM); |
160 | 0 | memcpy(vldest[i].p, att->vldata[i].p, vldest[i].len * base_typelen); |
161 | 0 | } |
162 | 0 | } |
163 | 67.5k | else if (att->stdata) |
164 | 0 | { |
165 | 0 | for (i = 0; i < att->len; i++) |
166 | 0 | { |
167 | | /* Check for NULL pointer for string (valid in HDF5) */ |
168 | 0 | if(att->stdata[i]) |
169 | 0 | { |
170 | 0 | if (!(((char **)data)[i] = strdup(att->stdata[i]))) |
171 | 0 | BAIL(NC_ENOMEM); |
172 | 0 | } |
173 | 0 | else |
174 | 0 | ((char **)data)[i] = att->stdata[i]; |
175 | 0 | } |
176 | 0 | } |
177 | 67.5k | else |
178 | 67.5k | { |
179 | 67.5k | memcpy(data, bufr, (size_t)(att->len * type_size)); |
180 | 67.5k | } |
181 | 67.5k | } |
182 | | |
183 | 189k | exit: |
184 | 189k | if (need_to_convert) |
185 | 0 | free(bufr); |
186 | 189k | if (range_error) |
187 | 0 | retval = NC_ERANGE; |
188 | 189k | return retval; |
189 | 171k | } |
190 | | |
191 | | /** |
192 | | * @internal Get or put attribute metadata from our linked list of |
193 | | * file info. Always locate the attribute by name, never by attnum. |
194 | | * The mem_type is ignored if data=NULL. |
195 | | * |
196 | | * @param ncid File and group ID. |
197 | | * @param varid Variable ID. |
198 | | * @param name Name of attribute. |
199 | | * @param xtype Pointer that gets (file) type of attribute. Ignored if |
200 | | * NULL. |
201 | | * @param mem_type The type of attribute data in memory. |
202 | | * @param lenp Pointer that gets length of attribute array. Ignored if |
203 | | * NULL. |
204 | | * @param attnum Pointer that gets the index number of this |
205 | | * attribute. Ignored if NULL. |
206 | | * @param data Pointer that gets attribute data. Ignored if NULL. |
207 | | * |
208 | | * @return ::NC_NOERR No error. |
209 | | * @return ::NC_EBADID Bad ncid. |
210 | | * @author Ed Hartnett |
211 | | */ |
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 | 0 | { |
216 | 0 | NC_FILE_INFO_T *h5; |
217 | 0 | NC_GRP_INFO_T *grp; |
218 | 0 | NC_VAR_INFO_T *var = NULL; |
219 | 0 | char norm_name[NC_MAX_NAME + 1]; |
220 | 0 | int retval; |
221 | |
|
222 | 0 | LOG((3, "%s: ncid 0x%x varid %d mem_type %d", __func__, ncid, |
223 | 0 | varid, mem_type)); |
224 | | |
225 | | /* Find info for this file, group, and h5 info. */ |
226 | 0 | if ((retval = nc4_find_grp_h5(ncid, &grp, &h5))) |
227 | 0 | return retval; |
228 | 0 | assert(h5 && grp); |
229 | | |
230 | | /* Check varid */ |
231 | 0 | if (varid != NC_GLOBAL) |
232 | 0 | { |
233 | 0 | if (!(var = (NC_VAR_INFO_T*)ncindexith(grp->vars,varid))) |
234 | 0 | return NC_ENOTVAR; |
235 | 0 | assert(var->hdr.id == varid); |
236 | 0 | } |
237 | | |
238 | | /* Name is required. */ |
239 | 0 | if (!name) |
240 | 0 | return NC_EBADNAME; |
241 | | |
242 | | /* Normalize name. */ |
243 | 0 | if ((retval = nc4_normalize_name(name, norm_name))) |
244 | 0 | return retval; |
245 | | |
246 | 0 | return nc4_get_att_ptrs(h5, grp, var, norm_name, xtype, mem_type, lenp, |
247 | 0 | attnum, data); |
248 | 0 | } |
249 | | |
250 | | /** |
251 | | * @internal Learn about an att. All the nc4 nc_inq_ functions just |
252 | | * call nc4_get_att to get the metadata on an attribute. |
253 | | * |
254 | | * @param ncid File and group ID. |
255 | | * @param varid Variable ID. |
256 | | * @param name Name of attribute. |
257 | | * @param xtypep Pointer that gets type of attribute. |
258 | | * @param lenp Pointer that gets length of attribute data array. |
259 | | * |
260 | | * @return ::NC_NOERR No error. |
261 | | * @return ::NC_EBADID Bad ncid. |
262 | | * @author Ed Hartnett |
263 | | */ |
264 | | int |
265 | | NC4_inq_att(int ncid, int varid, const char *name, nc_type *xtypep, |
266 | | size_t *lenp) |
267 | 0 | { |
268 | 0 | LOG((2, "%s: ncid 0x%x varid %d name %s", __func__, ncid, varid, name)); |
269 | 0 | return nc4_get_att(ncid, varid, name, xtypep, NC_NAT, lenp, NULL, NULL); |
270 | 0 | } |
271 | | |
272 | | /** |
273 | | * @internal Learn an attnum, given a name. |
274 | | * |
275 | | * @param ncid File and group ID. |
276 | | * @param varid Variable ID. |
277 | | * @param name Name of attribute. |
278 | | * @param attnump Pointer that gets the attribute index number. |
279 | | * |
280 | | * @return ::NC_NOERR No error. |
281 | | * @author Ed Hartnett |
282 | | */ |
283 | | int |
284 | | NC4_inq_attid(int ncid, int varid, const char *name, int *attnump) |
285 | 0 | { |
286 | 0 | LOG((2, "%s: ncid 0x%x varid %d name %s", __func__, ncid, varid, name)); |
287 | 0 | return nc4_get_att(ncid, varid, name, NULL, NC_NAT, NULL, attnump, NULL); |
288 | 0 | } |
289 | | |
290 | | /** |
291 | | * @internal Given an attnum, find the att's name. |
292 | | * |
293 | | * @param ncid File and group ID. |
294 | | * @param varid Variable ID. |
295 | | * @param attnum The index number of the attribute. |
296 | | * @param name Pointer that gets name of attribute. |
297 | | * |
298 | | * @return ::NC_NOERR No error. |
299 | | * @return ::NC_EBADID Bad ncid. |
300 | | * @author Ed Hartnett |
301 | | */ |
302 | | int |
303 | | NC4_inq_attname(int ncid, int varid, int attnum, char *name) |
304 | 0 | { |
305 | 0 | NC_ATT_INFO_T *att; |
306 | 0 | int retval; |
307 | |
|
308 | 0 | LOG((2, "nc_inq_attname: ncid 0x%x varid %d attnum %d", ncid, varid, |
309 | 0 | attnum)); |
310 | | |
311 | | /* Find the attribute metadata. */ |
312 | 0 | if ((retval = nc4_find_nc_att(ncid, varid, NULL, attnum, &att))) |
313 | 0 | return retval; |
314 | | |
315 | | /* Get the name. */ |
316 | 0 | if (name) |
317 | 0 | strcpy(name, att->hdr.name); |
318 | |
|
319 | 0 | return NC_NOERR; |
320 | 0 | } |
321 | | |
322 | | /** |
323 | | * @internal Get an attribute. |
324 | | * |
325 | | * @param ncid File and group ID. |
326 | | * @param varid Variable ID. |
327 | | * @param name Name of attribute. |
328 | | * @param value Pointer that gets attribute data. |
329 | | * @param memtype The type the data should be converted to as it is read. |
330 | | * |
331 | | * @return ::NC_NOERR No error. |
332 | | * @return ::NC_EBADID Bad ncid. |
333 | | * @author Ed Hartnett |
334 | | */ |
335 | | int |
336 | | NC4_get_att(int ncid, int varid, const char *name, void *value, nc_type memtype) |
337 | 0 | { |
338 | 0 | return nc4_get_att(ncid, varid, name, NULL, memtype, NULL, NULL, value); |
339 | 0 | } |