/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 h5 File object |
30 | | * @param grp Group object |
31 | | * @param var Variable object |
32 | | * @param name Name of attribute. Must already be normalized. |
33 | | * @param xtype Pointer that gets (file) type of attribute. Ignored if |
34 | | * NULL. |
35 | | * @param mem_type The type of attribute data in memory. |
36 | | * @param lenp Pointer that gets length of attribute array. Ignored if |
37 | | * NULL. |
38 | | * @param attnum Pointer that gets the index number of this |
39 | | * attribute. Ignored if NULL. |
40 | | * @param data Pointer that gets attribute data. Ignored if NULL. |
41 | | * |
42 | | * @return ::NC_NOERR No error. |
43 | | * @return ::NC_EBADID Bad ncid. |
44 | | * @author Ed Hartnett |
45 | | */ |
46 | | int |
47 | | nc4_get_att_ptrs(NC_FILE_INFO_T *h5, NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, |
48 | | const char *name, nc_type *xtype, nc_type mem_type, |
49 | | size_t *lenp, int *attnum, void *data) |
50 | 0 | { |
51 | 0 | NC_ATT_INFO_T *att = NULL; |
52 | 0 | int my_attnum = -1; |
53 | 0 | int need_to_convert = 0; |
54 | 0 | int range_error = NC_NOERR; |
55 | 0 | void *bufr = NULL; |
56 | 0 | size_t type_size; |
57 | 0 | int varid; |
58 | 0 | int retval; |
59 | |
|
60 | 0 | LOG((3, "%s: mem_type %d", __func__, mem_type)); |
61 | | |
62 | | /* Get the varid, or NC_GLOBAL. */ |
63 | 0 | varid = var ? var->hdr.id : NC_GLOBAL; |
64 | |
|
65 | 0 | if (attnum) |
66 | 0 | my_attnum = *attnum; |
67 | |
|
68 | 0 | if (name == NULL) |
69 | 0 | BAIL(NC_EBADNAME); |
70 | | |
71 | | /* Find the attribute, if it exists. */ |
72 | 0 | if ((retval = nc4_find_grp_att(grp, varid, name, my_attnum, &att))) |
73 | 0 | 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 | 0 | if (mem_type == NC_NAT) |
78 | 0 | 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 | 0 | if (data && att->len) |
85 | 0 | if ((att->nc_typeid == NC_CHAR && mem_type != NC_CHAR) || |
86 | 0 | (att->nc_typeid != NC_CHAR && mem_type == NC_CHAR)) |
87 | 0 | BAIL(NC_ECHAR); /* take that, you freak! */ |
88 | | |
89 | | /* Copy the info. */ |
90 | 0 | if (lenp) |
91 | 0 | *lenp = att->len; |
92 | 0 | if (xtype) |
93 | 0 | *xtype = att->nc_typeid; |
94 | 0 | if (attnum) { |
95 | 0 | *attnum = att->hdr.id; |
96 | 0 | } |
97 | | |
98 | | /* Zero len attributes are easy to read! */ |
99 | 0 | if (!att->len) |
100 | 0 | BAIL(NC_NOERR); |
101 | | |
102 | | /* Later on, we will need to know the size of this type. */ |
103 | 0 | 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 | 0 | 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 | NC_NOQUANTIZE, 0))) |
121 | 0 | BAIL(retval); |
122 | | |
123 | | /* For strict netcdf-3 rules, ignore erange errors between UBYTE |
124 | | * and BYTE types. */ |
125 | 0 | if ((h5->cmode & NC_CLASSIC_MODEL) && |
126 | 0 | (att->nc_typeid == NC_UBYTE || att->nc_typeid == NC_BYTE) && |
127 | 0 | (mem_type == NC_UBYTE || mem_type == NC_BYTE) && |
128 | 0 | range_error) |
129 | 0 | range_error = 0; |
130 | 0 | } |
131 | 0 | else |
132 | 0 | { |
133 | 0 | bufr = att->data; |
134 | 0 | } |
135 | | |
136 | | /* If the caller wants data, copy it for him. If he hasn't |
137 | | allocated enough memory for it, he will burn in segmentation |
138 | | fault hell, writhing with the agony of undiscovered memory |
139 | | bugs! */ |
140 | 0 | if (data) |
141 | 0 | { |
142 | 0 | { |
143 | 0 | if((retval = nc_copy_data(h5->controller->ext_ncid,mem_type,bufr,att->len,data))) |
144 | 0 | BAIL(retval); |
145 | 0 | } |
146 | 0 | } |
147 | | |
148 | 0 | exit: |
149 | 0 | if (need_to_convert) |
150 | 0 | free(bufr); |
151 | 0 | if (range_error) |
152 | 0 | retval = NC_ERANGE; |
153 | 0 | return retval; |
154 | 0 | } |
155 | | |
156 | | /** |
157 | | * @internal Get or put attribute metadata from our linked list of |
158 | | * file info. Always locate the attribute by name, never by attnum. |
159 | | * The mem_type is ignored if data=NULL. |
160 | | * |
161 | | * @param ncid File and group ID. |
162 | | * @param varid Variable ID. |
163 | | * @param name Name of attribute. |
164 | | * @param xtype Pointer that gets (file) type of attribute. Ignored if |
165 | | * NULL. |
166 | | * @param mem_type The type of attribute data in memory. |
167 | | * @param lenp Pointer that gets length of attribute array. Ignored if |
168 | | * NULL. |
169 | | * @param attnum Pointer that gets the index number of this |
170 | | * attribute. Ignored if NULL. |
171 | | * @param data Pointer that gets attribute data. Ignored if NULL. |
172 | | * |
173 | | * @return ::NC_NOERR No error. |
174 | | * @return ::NC_EBADID Bad ncid. |
175 | | * @author Ed Hartnett |
176 | | */ |
177 | | int |
178 | | nc4_get_att(int ncid, int varid, const char *name, nc_type *xtype, |
179 | | nc_type mem_type, size_t *lenp, int *attnum, void *data) |
180 | 0 | { |
181 | 0 | NC_FILE_INFO_T *h5; |
182 | 0 | NC_GRP_INFO_T *grp; |
183 | 0 | NC_VAR_INFO_T *var = NULL; |
184 | 0 | char norm_name[NC_MAX_NAME + 1]; |
185 | 0 | int retval; |
186 | |
|
187 | 0 | LOG((3, "%s: ncid 0x%x varid %d mem_type %d", __func__, ncid, |
188 | 0 | varid, mem_type)); |
189 | | |
190 | | /* Find info for this file, group, and h5 info. */ |
191 | 0 | if ((retval = nc4_find_grp_h5(ncid, &grp, &h5))) |
192 | 0 | return retval; |
193 | 0 | assert(h5 && grp); |
194 | | |
195 | | /* Check varid */ |
196 | 0 | if (varid != NC_GLOBAL) |
197 | 0 | { |
198 | 0 | if (!(var = (NC_VAR_INFO_T*)ncindexith(grp->vars,varid))) |
199 | 0 | return NC_ENOTVAR; |
200 | 0 | assert(var->hdr.id == varid); |
201 | 0 | } |
202 | | |
203 | | /* Name is required. */ |
204 | 0 | if (!name) |
205 | 0 | return NC_EBADNAME; |
206 | | |
207 | | /* Normalize name. */ |
208 | 0 | if ((retval = nc4_normalize_name(name, norm_name))) |
209 | 0 | return retval; |
210 | | |
211 | 0 | return nc4_get_att_ptrs(h5, grp, var, norm_name, xtype, mem_type, lenp, |
212 | 0 | attnum, data); |
213 | 0 | } |
214 | | |
215 | | /** |
216 | | * @internal Learn about an att. All the nc4 nc_inq_ functions just |
217 | | * call nc4_get_att to get the metadata on an attribute. |
218 | | * |
219 | | * @param ncid File and group ID. |
220 | | * @param varid Variable ID. |
221 | | * @param name Name of attribute. |
222 | | * @param xtypep Pointer that gets type of attribute. |
223 | | * @param lenp Pointer that gets length of attribute data array. |
224 | | * |
225 | | * @return ::NC_NOERR No error. |
226 | | * @return ::NC_EBADID Bad ncid. |
227 | | * @author Ed Hartnett |
228 | | */ |
229 | | int |
230 | | NC4_inq_att(int ncid, int varid, const char *name, nc_type *xtypep, |
231 | | size_t *lenp) |
232 | 0 | { |
233 | 0 | LOG((2, "%s: ncid 0x%x varid %d name %s", __func__, ncid, varid, name)); |
234 | 0 | return nc4_get_att(ncid, varid, name, xtypep, NC_NAT, lenp, NULL, NULL); |
235 | 0 | } |
236 | | |
237 | | /** |
238 | | * @internal Learn an attnum, given a name. |
239 | | * |
240 | | * @param ncid File and group ID. |
241 | | * @param varid Variable ID. |
242 | | * @param name Name of attribute. |
243 | | * @param attnump Pointer that gets the attribute index number. |
244 | | * |
245 | | * @return ::NC_NOERR No error. |
246 | | * @author Ed Hartnett |
247 | | */ |
248 | | int |
249 | | NC4_inq_attid(int ncid, int varid, const char *name, int *attnump) |
250 | 0 | { |
251 | 0 | LOG((2, "%s: ncid 0x%x varid %d name %s", __func__, ncid, varid, name)); |
252 | 0 | return nc4_get_att(ncid, varid, name, NULL, NC_NAT, NULL, attnump, NULL); |
253 | 0 | } |
254 | | |
255 | | /** |
256 | | * @internal Given an attnum, find the att's name. |
257 | | * |
258 | | * @param ncid File and group ID. |
259 | | * @param varid Variable ID. |
260 | | * @param attnum The index number of the attribute. |
261 | | * @param name Pointer that gets name of attribute. |
262 | | * |
263 | | * @return ::NC_NOERR No error. |
264 | | * @return ::NC_EBADID Bad ncid. |
265 | | * @author Ed Hartnett |
266 | | */ |
267 | | int |
268 | | NC4_inq_attname(int ncid, int varid, int attnum, char *name) |
269 | 0 | { |
270 | 0 | NC_ATT_INFO_T *att; |
271 | 0 | int retval; |
272 | |
|
273 | 0 | LOG((2, "nc_inq_attname: ncid 0x%x varid %d attnum %d", ncid, varid, |
274 | 0 | attnum)); |
275 | | |
276 | | /* Find the attribute metadata. */ |
277 | 0 | if ((retval = nc4_find_nc_att(ncid, varid, NULL, attnum, &att))) |
278 | 0 | return retval; |
279 | | |
280 | | /* Get the name. */ |
281 | 0 | if (name) |
282 | 0 | strcpy(name, att->hdr.name); |
283 | |
|
284 | 0 | return NC_NOERR; |
285 | 0 | } |
286 | | |
287 | | /** |
288 | | * @internal Get an attribute. |
289 | | * |
290 | | * @param ncid File and group ID. |
291 | | * @param varid Variable ID. |
292 | | * @param name Name of attribute. |
293 | | * @param value Pointer that gets attribute data. |
294 | | * @param memtype The type the data should be converted to as it is read. |
295 | | * |
296 | | * @return ::NC_NOERR No error. |
297 | | * @return ::NC_EBADID Bad ncid. |
298 | | * @author Ed Hartnett |
299 | | */ |
300 | | int |
301 | | NC4_get_att(int ncid, int varid, const char *name, void *value, nc_type memtype) |
302 | 0 | { |
303 | 0 | return nc4_get_att(ncid, varid, name, NULL, memtype, NULL, NULL, value); |
304 | 0 | } |