/src/netcdf-c/libnczarr/zvar.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright 2003-2019, University Corporation for Atmospheric |
2 | | * Research. See COPYRIGHT file for copying and redistribution |
3 | | * conditions.*/ |
4 | | |
5 | | /** |
6 | | * @file |
7 | | * @internal This file handles the ZARR variable functions. |
8 | | * |
9 | | * @author Dennis Heimbigner, Ed Hartnett |
10 | | */ |
11 | | |
12 | | #include "zincludes.h" |
13 | | #include <math.h> /* For pow() used below. */ |
14 | | |
15 | | /* Mnemonics */ |
16 | | #define CREATE 0 |
17 | | #define NOCREATE 1 |
18 | | |
19 | | |
20 | | #ifdef LOGGING |
21 | | static void |
22 | | reportchunking(const char* title, NC_VAR_INFO_T* var) |
23 | | { |
24 | | int i; |
25 | | char buf[8192]; |
26 | | |
27 | | buf[0] = '\0'; /* for strlcat */ |
28 | | strlcat(buf,title,sizeof(buf)); |
29 | | strlcat(buf,"chunksizes for var ",sizeof(buf)); |
30 | | strlcat(buf,var->hdr.name,sizeof(buf)); |
31 | | strlcat(buf,"sizes=",sizeof(buf)); |
32 | | for(i=0;i<var->ndims;i++) { |
33 | | char digits[64]; |
34 | | if(i > 0) strlcat(buf,",",sizeof(buf)); |
35 | | snprintf(digits,sizeof(digits),"%ld",(unsigned long)var->chunksizes[i]); |
36 | | strlcat(buf,digits,sizeof(buf)); |
37 | | } |
38 | | LOG((3,"%s",buf)); |
39 | | } |
40 | | #endif |
41 | | |
42 | | /* Mnemonic */ |
43 | 0 | #define READING 1 |
44 | 0 | #define WRITING 0 |
45 | | |
46 | | /** @internal Default size for unlimited dim chunksize. */ |
47 | | #define DEFAULT_1D_UNLIM_SIZE (4096) |
48 | | |
49 | | /** Number of bytes in 64 KB. */ |
50 | | #define SIXTY_FOUR_KB (65536) |
51 | | |
52 | | /** @internal Temp name used when renaming vars to preserve varid |
53 | | * order. */ |
54 | | #define NC_TEMP_NAME "_netcdf4_temporary_variable_name_for_rename" |
55 | | |
56 | | /** |
57 | | * @internal Check a set of chunksizes to see if they specify a chunk |
58 | | * that is too big. |
59 | | * |
60 | | * @param grp Pointer to the group info. |
61 | | * @param var Pointer to the var info. |
62 | | * @param chunksizes Array of chunksizes to check. |
63 | | * |
64 | | * @returns ::NC_NOERR No error. |
65 | | * @returns ::NC_EBADID Bad ncid. |
66 | | * @returns ::NC_ENOTVAR Invalid variable ID. |
67 | | * @returns ::NC_EBADCHUNK Bad chunksize. |
68 | | */ |
69 | | static int |
70 | | check_chunksizes(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, const size_t *chunksizes) |
71 | 0 | { |
72 | 0 | double dprod; |
73 | 0 | size_t type_len; |
74 | 0 | int d; |
75 | 0 | int retval = NC_NOERR; |
76 | |
|
77 | 0 | if ((retval = nc4_get_typelen_mem(grp->nc4_info, var->type_info->hdr.id, &type_len))) |
78 | 0 | goto done; |
79 | 0 | if (var->type_info->nc_type_class == NC_VLEN) |
80 | 0 | dprod = (double)sizeof(nc_hvl_t); |
81 | 0 | else |
82 | 0 | dprod = (double)type_len; |
83 | 0 | for (d = 0; d < var->ndims; d++) |
84 | 0 | dprod *= (double)chunksizes[d]; |
85 | |
|
86 | 0 | if (dprod > (double) NC_MAX_UINT) |
87 | 0 | {retval = NC_EBADCHUNK; goto done;} |
88 | 0 | done: |
89 | 0 | return retval; |
90 | 0 | } |
91 | | |
92 | | /** |
93 | | * @internal Determine some default chunksizes for a variable. |
94 | | * |
95 | | * @param grp Pointer to the group info. |
96 | | * @param var Pointer to the var info. |
97 | | * |
98 | | * @returns ::NC_NOERR for success |
99 | | * @returns ::NC_EBADID Bad ncid. |
100 | | * @returns ::NC_ENOTVAR Invalid variable ID. |
101 | | * @author Dennis Heimbigner, Ed Hartnett |
102 | | */ |
103 | | int |
104 | | ncz_find_default_chunksizes2(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var) |
105 | 0 | { |
106 | 0 | int d; |
107 | 0 | size_t type_size; |
108 | 0 | float num_values = 1, num_unlim = 0; |
109 | 0 | int retval; |
110 | 0 | size_t suggested_size; |
111 | | #ifdef LOGGING |
112 | | double total_chunk_size; |
113 | | #endif |
114 | |
|
115 | 0 | type_size = var->type_info->size; |
116 | |
|
117 | | #ifdef LOGGING |
118 | | /* Later this will become the total number of bytes in the default |
119 | | * chunk. */ |
120 | | total_chunk_size = (double) type_size; |
121 | | #endif |
122 | |
|
123 | 0 | if(var->chunksizes == NULL) { |
124 | 0 | if((var->chunksizes = calloc(1,sizeof(size_t)*var->ndims)) == NULL) |
125 | 0 | return NC_ENOMEM; |
126 | 0 | } |
127 | | |
128 | | /* How many values in the variable (or one record, if there are |
129 | | * unlimited dimensions). */ |
130 | 0 | for (d = 0; d < var->ndims; d++) |
131 | 0 | { |
132 | 0 | assert(var->dim[d]); |
133 | 0 | if (! var->dim[d]->unlimited) |
134 | 0 | num_values *= (float)var->dim[d]->len; |
135 | | #ifdef UNLIMITED |
136 | | else { |
137 | | num_unlim++; |
138 | | var->chunksizes[d] = 1; /* overwritten below, if all dims are unlimited */ |
139 | | } |
140 | | #endif |
141 | 0 | } |
142 | | #ifdef UNLIMITED |
143 | | /* Special case to avoid 1D vars with unlim dim taking huge amount |
144 | | of space (DEFAULT_CHUNK_SIZE bytes). Instead we limit to about |
145 | | 4KB */ |
146 | | if (var->ndims == 1 && num_unlim == 1) { |
147 | | if (DEFAULT_CHUNK_SIZE / type_size <= 0) |
148 | | suggested_size = 1; |
149 | | else if (DEFAULT_CHUNK_SIZE / type_size > DEFAULT_1D_UNLIM_SIZE) |
150 | | suggested_size = DEFAULT_1D_UNLIM_SIZE; |
151 | | else |
152 | | suggested_size = DEFAULT_CHUNK_SIZE / type_size; |
153 | | var->chunksizes[0] = suggested_size / type_size; |
154 | | LOG((4, "%s: name %s dim %d DEFAULT_CHUNK_SIZE %d num_values %f type_size %d " |
155 | | "chunksize %ld", __func__, var->hdr.name, d, DEFAULT_CHUNK_SIZE, num_values, type_size, var->chunksizes[0])); |
156 | | } |
157 | | if (var->ndims > 1 && var->ndims == num_unlim) { /* all dims unlimited */ |
158 | | suggested_size = pow((double)DEFAULT_CHUNK_SIZE/type_size, 1.0/(double)(var->ndims)); |
159 | | for (d = 0; d < var->ndims; d++) |
160 | | { |
161 | | var->chunksizes[d] = suggested_size ? suggested_size : 1; |
162 | | LOG((4, "%s: name %s dim %d DEFAULT_CHUNK_SIZE %d num_values %f type_size %d " |
163 | | "chunksize %ld", __func__, var->hdr.name, d, DEFAULT_CHUNK_SIZE, num_values, type_size, var->chunksizes[d])); |
164 | | } |
165 | | } |
166 | | #endif |
167 | | |
168 | | /* Pick a chunk length for each dimension, if one has not already |
169 | | * been picked above. */ |
170 | 0 | for (d = 0; d < var->ndims; d++) |
171 | 0 | if (!var->chunksizes[d]) |
172 | 0 | { |
173 | 0 | suggested_size = (pow((double)DEFAULT_CHUNK_SIZE/(num_values * type_size), |
174 | 0 | 1.0/(double)(var->ndims - num_unlim)) * var->dim[d]->len - .5); |
175 | 0 | if (suggested_size > var->dim[d]->len) |
176 | 0 | suggested_size = var->dim[d]->len; |
177 | 0 | var->chunksizes[d] = suggested_size ? suggested_size : 1; |
178 | 0 | LOG((4, "%s: name %s dim %d DEFAULT_CHUNK_SIZE %d num_values %f type_size %d " |
179 | 0 | "chunksize %ld", __func__, var->hdr.name, d, DEFAULT_CHUNK_SIZE, num_values, type_size, var->chunksizes[d])); |
180 | 0 | } |
181 | |
|
182 | | #ifdef LOGGING |
183 | | /* Find total chunk size. */ |
184 | | for (d = 0; d < var->ndims; d++) |
185 | | total_chunk_size *= (double) var->chunksizes[d]; |
186 | | LOG((4, "total_chunk_size %f", total_chunk_size)); |
187 | | #endif |
188 | | |
189 | | /* But did this result in a chunk that is too big? */ |
190 | 0 | retval = check_chunksizes(grp, var, var->chunksizes); |
191 | 0 | if (retval) |
192 | 0 | { |
193 | | /* Other error? */ |
194 | 0 | if (retval != NC_EBADCHUNK) |
195 | 0 | return THROW(retval); |
196 | | |
197 | | /* Chunk is too big! Reduce each dimension by half and try again. */ |
198 | 0 | for ( ; retval == NC_EBADCHUNK; retval = check_chunksizes(grp, var, var->chunksizes)) |
199 | 0 | for (d = 0; d < var->ndims; d++) |
200 | 0 | var->chunksizes[d] = var->chunksizes[d]/2 ? var->chunksizes[d]/2 : 1; |
201 | 0 | } |
202 | | |
203 | | /* Do we have any big data overhangs? They can be dangerous to |
204 | | * babies, the elderly, or confused campers who have had too much |
205 | | * beer. */ |
206 | 0 | for (d = 0; d < var->ndims; d++) |
207 | 0 | { |
208 | 0 | size_t num_chunks; |
209 | 0 | size_t overhang; |
210 | 0 | assert(var->chunksizes[d] > 0); |
211 | 0 | num_chunks = (var->dim[d]->len + var->chunksizes[d] - 1) / var->chunksizes[d]; |
212 | 0 | if(num_chunks > 0) { |
213 | 0 | overhang = (num_chunks * var->chunksizes[d]) - var->dim[d]->len; |
214 | 0 | var->chunksizes[d] -= overhang / num_chunks; |
215 | 0 | } |
216 | 0 | } |
217 | | |
218 | | #ifdef LOGGING |
219 | | reportchunking("find_default: ",var); |
220 | | #endif |
221 | 0 | return NC_NOERR; |
222 | 0 | } |
223 | | |
224 | | #if 0 |
225 | | /** |
226 | | * @internal Give a var a secret ZARR name. This is needed when a var |
227 | | * is defined with the same name as a dim, but it is not a coord var |
228 | | * of that dim. In that case, the var uses a secret name inside the |
229 | | * ZARR file. |
230 | | * |
231 | | * @param var Pointer to var info. |
232 | | * @param name Name to use for base of secret name. |
233 | | * |
234 | | * @returns ::NC_NOERR No error. |
235 | | * @returns ::NC_EMAXNAME Name too long to fit secret prefix. |
236 | | * @returns ::NC_ENOMEM Out of memory. |
237 | | * @author Dennis Heimbigner, Ed Hartnett |
238 | | */ |
239 | | static int |
240 | | give_var_secret_name(NC_VAR_INFO_T *var, const char *name) |
241 | | { |
242 | | /* Set a different ncz name for this variable to avoid name |
243 | | * clash. */ |
244 | | if (strlen(name) + strlen(NON_COORD_PREPEND) > NC_MAX_NAME) |
245 | | return NC_EMAXNAME; |
246 | | if (!(var->ncz_name = malloc((strlen(NON_COORD_PREPEND) + |
247 | | strlen(name) + 1) * sizeof(char)))) |
248 | | return NC_ENOMEM; |
249 | | |
250 | | sprintf(var->ncz_name, "%s%s", NON_COORD_PREPEND, name); |
251 | | |
252 | | return NC_NOERR; |
253 | | } |
254 | | #endif /*0*/ |
255 | | |
256 | | /** |
257 | | * @internal This is called when a new netCDF-4 variable is defined |
258 | | * with nc_def_var(). |
259 | | * |
260 | | * @param ncid File ID. |
261 | | * @param name Name. |
262 | | * @param xtype Type. |
263 | | * @param ndims Number of dims. ZARR has maximum of 32. |
264 | | * @param dimidsp Array of dim IDs. |
265 | | * @param varidp Gets the var ID. |
266 | | * |
267 | | * @returns ::NC_NOERR No error. |
268 | | * @returns ::NC_EBADID Bad ncid. |
269 | | * @returns ::NC_ENOTVAR Invalid variable ID. |
270 | | * @returns ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is |
271 | | * not netCDF-4/NCZ. |
272 | | * @returns ::NC_ESTRICTNC3 Attempting netcdf-4 operation on strict nc3 |
273 | | * netcdf-4 file. |
274 | | * @returns ::NC_ELATEDEF Too late to change settings for this variable. |
275 | | * @returns ::NC_ENOTINDEFINE Not in define mode. |
276 | | * @returns ::NC_EPERM File is read only. |
277 | | * @returns ::NC_EMAXDIMS Classic model file exceeds ::NC_MAX_VAR_DIMS. |
278 | | * @returns ::NC_ESTRICTNC3 Attempting to create netCDF-4 type var in |
279 | | * classic model file |
280 | | * @returns ::NC_EBADNAME Bad name. |
281 | | * @returns ::NC_EBADTYPE Bad type. |
282 | | * @returns ::NC_ENOMEM Out of memory. |
283 | | * @returns ::NC_EHDFERR Error returned by ZARR layer. |
284 | | * @returns ::NC_EINVAL Invalid input |
285 | | * @author Dennis Heimbigner, Ed Hartnett |
286 | | */ |
287 | | int |
288 | | NCZ_def_var(int ncid, const char *name, nc_type xtype, int ndims, |
289 | | const int *dimidsp, int *varidp) |
290 | 0 | { |
291 | 0 | NC_GRP_INFO_T *grp; |
292 | 0 | NC_VAR_INFO_T *var; |
293 | 0 | NC_DIM_INFO_T *dim; |
294 | 0 | NC_FILE_INFO_T *h5; |
295 | 0 | NC_TYPE_INFO_T *type = NULL; |
296 | 0 | NCZ_VAR_INFO_T* zvar = NULL; |
297 | 0 | char norm_name[NC_MAX_NAME + 1]; |
298 | 0 | int d; |
299 | 0 | int retval; |
300 | |
|
301 | 0 | ZTRACE(1,"ncid=%d name=%s xtype=%d ndims=%d dimids=%s",ncid,name,xtype,ndims,nczprint_idvector(ndims,dimidsp)); |
302 | | |
303 | | /* Find info for this file and group, and set pointer to each. */ |
304 | 0 | if ((retval = nc4_find_grp_h5(ncid, &grp, &h5))) |
305 | 0 | BAIL(retval); |
306 | 0 | assert(grp && grp->format_grp_info && h5); |
307 | | |
308 | | #ifdef LOOK |
309 | | /* HDF5 allows maximum of 32 dimensions. */ |
310 | | if (ndims > H5S_MAX_RANK) |
311 | | BAIL(NC_EMAXDIMS); |
312 | | #endif |
313 | | |
314 | | /* If it's not in define mode, strict nc3 files error out, |
315 | | * otherwise switch to define mode. This will also check that the |
316 | | * file is writable. */ |
317 | 0 | if (!(h5->flags & NC_INDEF)) |
318 | 0 | { |
319 | 0 | if (h5->cmode & NC_CLASSIC_MODEL) |
320 | 0 | BAIL(NC_ENOTINDEFINE); |
321 | 0 | if ((retval = NCZ_redef(ncid))) |
322 | 0 | BAIL(retval); |
323 | 0 | } |
324 | 0 | assert(!h5->no_write); |
325 | | |
326 | | /* Check and normalize the name. */ |
327 | 0 | if ((retval = nc4_check_name(name, norm_name))) |
328 | 0 | BAIL(retval); |
329 | | |
330 | | /* Not a Type is, well, not a type.*/ |
331 | 0 | if (xtype == NC_NAT) |
332 | 0 | BAIL(NC_EBADTYPE); |
333 | | |
334 | | /* For classic files, only classic types are allowed. */ |
335 | 0 | if (h5->cmode & NC_CLASSIC_MODEL && xtype > NC_DOUBLE) |
336 | 0 | BAIL(NC_ESTRICTNC3); |
337 | | |
338 | | /* For classic files limit number of dims. */ |
339 | 0 | if (h5->cmode & NC_CLASSIC_MODEL && ndims > NC_MAX_VAR_DIMS) |
340 | 0 | BAIL(NC_EMAXDIMS); |
341 | | |
342 | | /* cast needed for braindead systems with signed size_t */ |
343 | 0 | if ((unsigned long) ndims > X_INT_MAX) /* Backward compat */ |
344 | 0 | BAIL(NC_EINVAL); |
345 | | |
346 | | /* Check that this name is not in use as a var, grp, or type. */ |
347 | 0 | if ((retval = nc4_check_dup_name(grp, norm_name))) |
348 | 0 | BAIL(retval); |
349 | | |
350 | | /* For non-scalar vars, dim IDs must be provided. */ |
351 | 0 | if (ndims && !dimidsp) |
352 | 0 | BAIL(NC_EINVAL); |
353 | | |
354 | | /* Check all the dimids to make sure they exist. */ |
355 | 0 | for (d = 0; d < ndims; d++) |
356 | 0 | if ((retval = nc4_find_dim(grp, dimidsp[d], &dim, NULL))) |
357 | 0 | BAIL(retval); |
358 | | |
359 | | /* These degrubbing messages sure are handy! */ |
360 | 0 | LOG((2, "%s: name %s type %d ndims %d", __func__, norm_name, xtype, ndims)); |
361 | | #ifdef LOGGING |
362 | | { |
363 | | int dd; |
364 | | for (dd = 0; dd < ndims; dd++) |
365 | | LOG((4, "dimid[%d] %d", dd, dimidsp[dd])); |
366 | | } |
367 | | #endif |
368 | | |
369 | | /* If this is a user-defined type, there is a type struct with |
370 | | * all the type information. For atomic types, fake up a type |
371 | | * struct. */ |
372 | 0 | if((retval = ncz_gettype(h5,grp,xtype,&type))) |
373 | 0 | BAIL(retval); |
374 | | |
375 | | /* Create a new var and fill in some cache setting values. */ |
376 | 0 | if ((retval = nc4_var_list_add(grp, norm_name, ndims, &var))) |
377 | 0 | BAIL(retval); |
378 | | |
379 | | /* Add storage for NCZ-specific var info. */ |
380 | 0 | if (!(var->format_var_info = calloc(1, sizeof(NCZ_VAR_INFO_T)))) |
381 | 0 | BAIL(NC_ENOMEM); |
382 | 0 | zvar = var->format_var_info; |
383 | 0 | zvar->common.file = h5; |
384 | 0 | zvar->scalar = (ndims == 0 ? 1 : 0); |
385 | |
|
386 | 0 | zvar->dimension_separator = NC_getglobalstate()->zarr.dimension_separator; |
387 | 0 | assert(zvar->dimension_separator != 0); |
388 | | |
389 | | /* Set these state flags for the var. */ |
390 | 0 | var->is_new_var = NC_TRUE; |
391 | 0 | var->meta_read = NC_TRUE; |
392 | 0 | var->atts_read = NC_TRUE; |
393 | | |
394 | | /* Set the filter list */ |
395 | 0 | assert(var->filters == NULL); |
396 | 0 | var->filters = (void*)nclistnew(); |
397 | | |
398 | | /* Point to the type, and increment its ref. count */ |
399 | 0 | var->type_info = type; |
400 | | #ifdef LOOK |
401 | | var->type_info->rc++; |
402 | | #endif |
403 | 0 | type = NULL; |
404 | | |
405 | | /* Propagate the endianness */ |
406 | 0 | var->endianness = var->type_info->endianness; |
407 | | |
408 | | /* Set variables no_fill to match the database default unless the |
409 | | * variable type is variable length (NC_STRING or NC_VLEN) or is |
410 | | * user-defined type. */ |
411 | 0 | if (var->type_info->nc_type_class <= NC_STRING) |
412 | 0 | var->no_fill = (h5->fill_mode == NC_NOFILL); |
413 | | |
414 | | /* Assign dimensions to the variable. At the same time, check to |
415 | | * see if this is a coordinate variable. If so, it will have the |
416 | | * same name as one of its dimensions. If it is a coordinate var, |
417 | | * is it a coordinate var in the same group as the dim? Also, check |
418 | | * whether we should use contiguous or chunked storage. */ |
419 | 0 | var->storage = NC_CHUNKED; |
420 | 0 | for (d = 0; d < ndims; d++) |
421 | 0 | { |
422 | 0 | NC_GRP_INFO_T *dim_grp; |
423 | | /* Look up each dimension */ |
424 | 0 | if ((retval = nc4_find_dim(grp, dimidsp[d], &dim, &dim_grp))) |
425 | 0 | BAIL(retval); |
426 | 0 | assert(dim && dim->format_dim_info); |
427 | | #ifdef UNLIMITED |
428 | | /* Check for unlimited dimension and turn off contiguous storage. */ |
429 | | if (dim->unlimited) |
430 | | var->contiguous = NC_FALSE; |
431 | | #endif |
432 | | /* Track dimensions for variable */ |
433 | 0 | var->dimids[d] = dimidsp[d]; |
434 | 0 | var->dim[d] = dim; |
435 | 0 | } |
436 | | |
437 | | /* Determine default chunksizes for this variable. (Even for |
438 | | * variables which may be contiguous.) */ |
439 | 0 | LOG((4, "allocating array of %d size_t to hold chunksizes for var %s", |
440 | 0 | var->ndims, var->hdr.name)); |
441 | 0 | if(!var->chunksizes) { |
442 | 0 | if(var->ndims) { |
443 | 0 | if (!(var->chunksizes = calloc(var->ndims, sizeof(size_t)))) |
444 | 0 | BAIL(NC_ENOMEM); |
445 | 0 | if ((retval = ncz_find_default_chunksizes2(grp, var))) |
446 | 0 | BAIL(retval); |
447 | 0 | } else { |
448 | | /* Pretend that scalars are like var[1] */ |
449 | 0 | if (!(var->chunksizes = calloc(1, sizeof(size_t)))) |
450 | 0 | BAIL(NC_ENOMEM); |
451 | 0 | var->chunksizes[0] = 1; |
452 | 0 | } |
453 | 0 | } |
454 | | |
455 | | /* Compute the chunksize cross product */ |
456 | 0 | zvar->chunkproduct = 1; |
457 | 0 | if(!zvar->scalar) |
458 | 0 | {for(d=0;d<var->ndims;d++) {zvar->chunkproduct *= var->chunksizes[d];}} |
459 | 0 | zvar->chunksize = zvar->chunkproduct * var->type_info->size; |
460 | | |
461 | | /* Override the cache setting to use NCZarr defaults */ |
462 | 0 | var->chunkcache.size = CHUNK_CACHE_SIZE_NCZARR; |
463 | 0 | var->chunkcache.nelems = ceildiv(var->chunkcache.size,zvar->chunksize); |
464 | 0 | var->chunkcache.preemption = 1; /* not used */ |
465 | | |
466 | | /* Create the cache */ |
467 | 0 | if((retval=NCZ_create_chunk_cache(var,zvar->chunkproduct*var->type_info->size,zvar->dimension_separator,&zvar->cache))) |
468 | 0 | BAIL(retval); |
469 | | |
470 | | /* Return the varid. */ |
471 | 0 | if (varidp) |
472 | 0 | *varidp = var->hdr.id; |
473 | 0 | LOG((4, "new varid %d", var->hdr.id)); |
474 | |
|
475 | 0 | exit: |
476 | 0 | if (type) |
477 | 0 | if ((retval = nc4_type_free(type))) |
478 | 0 | BAILLOG(retval); |
479 | 0 | return ZUNTRACE(retval); |
480 | 0 | } |
481 | | |
482 | | /** |
483 | | * @internal This functions sets extra stuff about a netCDF-4 variable which |
484 | | * must be set before the enddef but after the def_var. |
485 | | * |
486 | | * @note All pointer parameters may be NULL, in which case they are ignored. |
487 | | * @param ncid File ID. |
488 | | * @param varid Variable ID. |
489 | | * @param shuffle Pointer to shuffle setting. |
490 | | * @param deflate Pointer to deflate setting. |
491 | | * @param deflate_level Pointer to deflate level. |
492 | | * @param fletcher32 Pointer to fletcher32 setting. |
493 | | * @param contiguous Pointer to contiguous setting. |
494 | | * @param chunksizes Array of chunksizes. |
495 | | * @param no_fill Pointer to no_fill setting. |
496 | | * @param fill_value Pointer to fill value. |
497 | | * @param endianness Pointer to endianness setting. |
498 | | * |
499 | | * @returns ::NC_NOERR for success |
500 | | * @returns ::NC_EBADID Bad ncid. |
501 | | * @returns ::NC_ENOTVAR Invalid variable ID. |
502 | | * @returns ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is |
503 | | * not netCDF-4/NCZ. |
504 | | * @returns ::NC_ESTRICTNC3 Attempting netcdf-4 operation on strict nc3 |
505 | | * netcdf-4 file. |
506 | | * @returns ::NC_ELATEDEF Too late to change settings for this variable. |
507 | | * @returns ::NC_ENOTINDEFINE Not in define mode. |
508 | | * @returns ::NC_EPERM File is read only. |
509 | | * @returns ::NC_EINVAL Invalid input |
510 | | * @returns ::NC_EBADCHUNK Bad chunksize. |
511 | | * @author Dennis Heimbigner, Ed Hartnett |
512 | | */ |
513 | | static int |
514 | | ncz_def_var_extra(int ncid, int varid, int *shuffle, int *unused1, |
515 | | int *unused2, int *fletcher32, int *storagep, |
516 | | const size_t *chunksizes, int *no_fill, |
517 | | const void *fill_value, int *endianness, |
518 | | int *quantize_mode, int *nsd) |
519 | 0 | { |
520 | 0 | NC_GRP_INFO_T *grp; |
521 | 0 | NC_FILE_INFO_T *h5; |
522 | 0 | NC_VAR_INFO_T *var; |
523 | 0 | NCZ_VAR_INFO_T *zvar; |
524 | 0 | int d; |
525 | 0 | int retval = NC_NOERR; |
526 | 0 | int storage = NC_CHUNKED; |
527 | |
|
528 | 0 | LOG((2, "%s: ncid 0x%x varid %d", __func__, ncid, varid)); |
529 | |
|
530 | 0 | ZTRACE(2,"ncid=%d varid=%d shuffle=%d fletcher32=%d no_fill=%d, fill_value=%p endianness=%d quantize_mode=%d nsd=%d", |
531 | 0 | ncid,varid, |
532 | 0 | (shuffle?*shuffle:-1), |
533 | 0 | (fletcher32?*fletcher32:-1), |
534 | 0 | (no_fill?*no_fill:-1), |
535 | 0 | fill_value, |
536 | 0 | (endianness?*endianness:-1), |
537 | 0 | (quantize_mode?*quantize_mode:-1), |
538 | 0 | (nsd?*nsd:-1) |
539 | 0 | ); |
540 | | |
541 | | /* Find info for this file and group, and set pointer to each. */ |
542 | 0 | if ((retval = nc4_find_nc_grp_h5(ncid, NULL, &grp, &h5))) |
543 | 0 | goto done; |
544 | 0 | assert(grp && h5); |
545 | | |
546 | | /* Trying to write to a read-only file? No way, Jose! */ |
547 | 0 | if (h5->no_write) |
548 | 0 | {retval = NC_EPERM; goto done;} |
549 | | |
550 | | /* Find the var. */ |
551 | 0 | if (!(var = (NC_VAR_INFO_T *)ncindexith(grp->vars, varid))) |
552 | 0 | {retval = NC_ENOTVAR; goto done;} |
553 | 0 | assert(var && var->hdr.id == varid); |
554 | | |
555 | 0 | zvar = var->format_var_info; |
556 | |
|
557 | 0 | ZTRACEMORE(1,"\tstoragep=%d chunksizes=%s",(storagep?*storagep:-1),(chunksizes?nczprint_sizevector(var->ndims,chunksizes):"null")); |
558 | | |
559 | | /* Can't turn on parallel and deflate/fletcher32/szip/shuffle |
560 | | * before HDF5 1.10.3. */ |
561 | 0 | #ifndef HDF5_SUPPORTS_PAR_FILTERS |
562 | 0 | if (h5->parallel == NC_TRUE) |
563 | 0 | if (nclistlength(((NClist*)var->filters)) > 0 || fletcher32 || shuffle) |
564 | 0 | {retval = NC_EINVAL; goto done;} |
565 | 0 | #endif |
566 | | |
567 | | /* If the HDF5 dataset has already been created, then it is too |
568 | | * late to set all the extra stuff. */ |
569 | 0 | if (var->created) |
570 | 0 | {retval = NC_ELATEDEF; goto done;} |
571 | | |
572 | | #if 0 |
573 | | /* Check compression options. */ |
574 | | if (deflate && !deflate_level) |
575 | | {retval = NC_EINVAL; goto done;} |
576 | | |
577 | | /* Valid deflate level? */ |
578 | | if (deflate) |
579 | | { |
580 | | if (*deflate) |
581 | | if (*deflate_level < NC_MIN_DEFLATE_LEVEL || |
582 | | *deflate_level > NC_MAX_DEFLATE_LEVEL) |
583 | | {retval = NC_EINVAL; goto done;} |
584 | | |
585 | | /* For scalars, just ignore attempt to deflate. */ |
586 | | if (!var->ndims) |
587 | | goto done; |
588 | | |
589 | | /* If szip is in use, return an error. */ |
590 | | if ((retval = nc_inq_var_szip(ncid, varid, &option_mask, NULL))) |
591 | | goto done; |
592 | | if (option_mask) |
593 | | {retval = NC_EINVAL; goto done;} |
594 | | |
595 | | /* Set the deflate settings. */ |
596 | | var->contiguous = NC_FALSE; |
597 | | var->deflate = *deflate; |
598 | | if (*deflate) |
599 | | var->deflate_level = *deflate_level; |
600 | | LOG((3, "%s: *deflate_level %d", __func__, *deflate_level)); |
601 | | } |
602 | | #endif |
603 | | |
604 | | /* Shuffle filter? */ |
605 | 0 | if (shuffle && *shuffle) { |
606 | 0 | retval = nc_inq_var_filter_info(ncid,varid,H5Z_FILTER_SHUFFLE,NULL,NULL); |
607 | 0 | if(!retval || retval == NC_ENOFILTER) { |
608 | 0 | if((retval = NCZ_def_var_filter(ncid,varid,H5Z_FILTER_SHUFFLE,0,NULL))) return retval; |
609 | 0 | var->storage = NC_CHUNKED; |
610 | 0 | } |
611 | 0 | } |
612 | | |
613 | | /* Fletcher32 checksum error protection? */ |
614 | 0 | if (fletcher32 && fletcher32) { |
615 | 0 | retval = nc_inq_var_filter_info(ncid,varid,H5Z_FILTER_FLETCHER32,NULL,NULL); |
616 | 0 | if(!retval || retval == NC_ENOFILTER) { |
617 | 0 | if((retval = NCZ_def_var_filter(ncid,varid,H5Z_FILTER_FLETCHER32,0,NULL))) return retval; |
618 | 0 | var->storage = NC_CHUNKED; |
619 | 0 | } |
620 | 0 | } |
621 | | |
622 | | /* Handle storage settings. */ |
623 | 0 | if (storagep) |
624 | 0 | { |
625 | 0 | storage = *storagep; |
626 | | /* Does the user want a contiguous or compact dataset? Not so |
627 | | * fast! Make sure that there are no unlimited dimensions, and |
628 | | * no filters in use for this data. */ |
629 | 0 | if (storage != NC_CHUNKED) |
630 | 0 | { |
631 | 0 | if (nclistlength(((NClist*)var->filters)) > 0) |
632 | 0 | {retval = NC_EINVAL; goto done;} |
633 | 0 | for (d = 0; d < var->ndims; d++) |
634 | 0 | if (var->dim[d]->unlimited) |
635 | 0 | {retval = NC_EINVAL; goto done;} |
636 | 0 | storage = NC_CHUNKED; /*only chunked supported */ |
637 | 0 | } |
638 | | |
639 | | /* Handle chunked storage settings. */ |
640 | 0 | if (storage == NC_CHUNKED && var->ndims == 0) { |
641 | 0 | {retval = NC_EINVAL; goto done;} |
642 | 0 | } else if (storage == NC_CHUNKED && var->ndims > 0) { |
643 | 0 | var->storage = NC_CHUNKED; |
644 | | |
645 | | /* If the user provided chunksizes, check that they are valid |
646 | | * and that their total size of chunk is less than 4 GB. */ |
647 | 0 | if (chunksizes) |
648 | 0 | { |
649 | | /* Check the chunksizes for validity. */ |
650 | 0 | if ((retval = check_chunksizes(grp, var, chunksizes))) |
651 | 0 | goto done; |
652 | | |
653 | | /* Ensure chunksize is smaller than dimension size */ |
654 | 0 | for (d = 0; d < var->ndims; d++) |
655 | 0 | if (!var->dim[d]->unlimited && var->dim[d]->len > 0 && |
656 | 0 | chunksizes[d] > var->dim[d]->len) |
657 | 0 | {retval = NC_EBADCHUNK; goto done;} |
658 | 0 | } |
659 | 0 | } |
660 | 0 | else if (storage == NC_CONTIGUOUS || storage == NC_COMPACT) |
661 | 0 | { |
662 | 0 | var->storage = NC_CHUNKED; |
663 | 0 | } |
664 | | |
665 | | /* Is this a variable with a chunksize greater than the current |
666 | | * cache size? */ |
667 | 0 | if (var->storage == NC_CHUNKED) |
668 | 0 | { |
669 | 0 | int anyzero = 0; /* check for any zero length chunksizes */ |
670 | 0 | zvar = var->format_var_info; |
671 | 0 | assert(zvar->cache != NULL); |
672 | 0 | zvar->cache->valid = 0; |
673 | 0 | if(chunksizes) { |
674 | 0 | for (d = 0; d < var->ndims; d++) { |
675 | 0 | var->chunksizes[d] = chunksizes[d]; |
676 | 0 | if(chunksizes[d] == 0) anyzero = 1; |
677 | 0 | } |
678 | 0 | } |
679 | | /* If chunksizes == NULL or anyzero then use defaults */ |
680 | 0 | if(chunksizes == NULL || anyzero) { /* Use default chunking */ |
681 | 0 | if ((retval = ncz_find_default_chunksizes2(grp, var))) |
682 | 0 | goto done; |
683 | 0 | } |
684 | 0 | assert(var->chunksizes != NULL); |
685 | | /* Set the chunksize product for this variable. */ |
686 | 0 | zvar->chunkproduct = 1; |
687 | 0 | for (d = 0; d < var->ndims; d++) |
688 | 0 | zvar->chunkproduct *= var->chunksizes[d]; |
689 | 0 | zvar->chunksize = zvar->chunkproduct * var->type_info->size; |
690 | 0 | } |
691 | | /* Adjust cache */ |
692 | 0 | if((retval = NCZ_adjust_var_cache(var))) goto done; |
693 | | |
694 | | #ifdef LOGGING |
695 | | { |
696 | | int dfalt = (chunksizes == NULL); |
697 | | reportchunking(dfalt ? "extra: default: " : "extra: user: ", var); |
698 | | } |
699 | | #endif |
700 | 0 | } |
701 | | |
702 | | /* Are we setting a fill modes? */ |
703 | 0 | if (no_fill) |
704 | 0 | { |
705 | 0 | if (*no_fill) |
706 | 0 | { |
707 | | /* NC_STRING types may not turn off fill mode. It's disallowed |
708 | | * by HDF5 and will cause a HDF5 error later. */ |
709 | 0 | if (*no_fill) |
710 | 0 | if (var->type_info->hdr.id == NC_STRING) |
711 | 0 | {retval = NC_EINVAL; goto done;} |
712 | | |
713 | | /* Set the no-fill mode. */ |
714 | 0 | var->no_fill = NC_TRUE; |
715 | 0 | } |
716 | 0 | else |
717 | 0 | var->no_fill = NC_FALSE; |
718 | 0 | } |
719 | | |
720 | | /* Are we setting a fill value? */ |
721 | 0 | if (fill_value && no_fill && !(*no_fill)) |
722 | 0 | { |
723 | | /* Copy the fill_value. */ |
724 | 0 | LOG((4, "Copying fill value into metadata for variable %s", |
725 | 0 | var->hdr.name)); |
726 | | |
727 | | /* If there's a _FillValue attribute, delete it. */ |
728 | 0 | retval = NCZ_del_att(ncid, varid, _FillValue); |
729 | 0 | if (retval && retval != NC_ENOTATT) |
730 | 0 | goto done; |
731 | | |
732 | | /* Create a _FillValue attribute; will also fill in var->fill_value */ |
733 | 0 | if ((retval = nc_put_att(ncid, varid, _FillValue, var->type_info->hdr.id, |
734 | 0 | 1, fill_value))) |
735 | 0 | goto done; |
736 | | /* Reclaim any existing fill_chunk */ |
737 | 0 | if((retval = NCZ_reclaim_fill_chunk(zvar->cache))) goto done; |
738 | 0 | } else if (var->fill_value && no_fill && (*no_fill)) { /* Turning off fill value? */ |
739 | | /* If there's a _FillValue attribute, delete it. */ |
740 | 0 | retval = NCZ_del_att(ncid, varid, _FillValue); |
741 | 0 | if (retval && retval != NC_ENOTATT) return retval; |
742 | 0 | if((retval = NCZ_reclaim_fill_value(var))) return retval; |
743 | 0 | } |
744 | | |
745 | | /* Is the user setting the endianness? */ |
746 | 0 | if (endianness) |
747 | 0 | { |
748 | | /* Setting endianness is only premitted on atomic integer and |
749 | | * atomic float types. */ |
750 | 0 | switch (var->type_info->hdr.id) |
751 | 0 | { |
752 | 0 | case NC_BYTE: |
753 | 0 | case NC_SHORT: |
754 | 0 | case NC_INT: |
755 | 0 | case NC_FLOAT: |
756 | 0 | case NC_DOUBLE: |
757 | 0 | case NC_UBYTE: |
758 | 0 | case NC_USHORT: |
759 | 0 | case NC_UINT: |
760 | 0 | case NC_INT64: |
761 | 0 | case NC_UINT64: |
762 | 0 | break; |
763 | 0 | default: |
764 | 0 | {retval = NC_EINVAL; goto done;} |
765 | 0 | } |
766 | 0 | var->type_info->endianness = *endianness; |
767 | | /* Propagate */ |
768 | 0 | var->endianness = *endianness; |
769 | 0 | } |
770 | | |
771 | | /* Remember quantization settings. They will be used when data are |
772 | | * written. |
773 | | * Code block is identical to one in hdf5var.c---consider functionalizing */ |
774 | 0 | if (quantize_mode) |
775 | 0 | { |
776 | | /* Only four valid mode settings. */ |
777 | 0 | if (*quantize_mode != NC_NOQUANTIZE && |
778 | 0 | *quantize_mode != NC_QUANTIZE_BITGROOM && |
779 | 0 | *quantize_mode != NC_QUANTIZE_GRANULARBR && |
780 | 0 | *quantize_mode != NC_QUANTIZE_BITROUND) |
781 | 0 | return NC_EINVAL; |
782 | | |
783 | 0 | if (*quantize_mode == NC_QUANTIZE_BITGROOM || |
784 | 0 | *quantize_mode == NC_QUANTIZE_GRANULARBR || |
785 | 0 | *quantize_mode == NC_QUANTIZE_BITROUND) |
786 | 0 | { |
787 | | |
788 | | /* Only float and double types can have quantization. */ |
789 | 0 | if (var->type_info->hdr.id != NC_FLOAT && |
790 | 0 | var->type_info->hdr.id != NC_DOUBLE) |
791 | 0 | return NC_EINVAL; |
792 | | |
793 | | /* All quantization codecs require number of significant digits */ |
794 | 0 | if (!nsd) |
795 | 0 | return NC_EINVAL; |
796 | | |
797 | | /* NSD must be in range. */ |
798 | 0 | if (*nsd <= 0) |
799 | 0 | return NC_EINVAL; |
800 | | |
801 | 0 | if (*quantize_mode == NC_QUANTIZE_BITGROOM || |
802 | 0 | *quantize_mode == NC_QUANTIZE_GRANULARBR) |
803 | 0 | { |
804 | 0 | if (var->type_info->hdr.id == NC_FLOAT && |
805 | 0 | *nsd > NC_QUANTIZE_MAX_FLOAT_NSD) |
806 | 0 | return NC_EINVAL; |
807 | 0 | if (var->type_info->hdr.id == NC_DOUBLE && |
808 | 0 | *nsd > NC_QUANTIZE_MAX_DOUBLE_NSD) |
809 | 0 | return NC_EINVAL; |
810 | 0 | } |
811 | 0 | else if (*quantize_mode == NC_QUANTIZE_BITROUND) |
812 | 0 | { |
813 | 0 | if (var->type_info->hdr.id == NC_FLOAT && |
814 | 0 | *nsd > NC_QUANTIZE_MAX_FLOAT_NSB) |
815 | 0 | return NC_EINVAL; |
816 | 0 | if (var->type_info->hdr.id == NC_DOUBLE && |
817 | 0 | *nsd > NC_QUANTIZE_MAX_DOUBLE_NSB) |
818 | 0 | return NC_EINVAL; |
819 | 0 | } |
820 | | |
821 | 0 | var->nsd = *nsd; |
822 | 0 | } |
823 | | |
824 | 0 | var->quantize_mode = *quantize_mode; |
825 | | |
826 | | /* If quantization is turned off, then set nsd to 0. */ |
827 | 0 | if (*quantize_mode == NC_NOQUANTIZE) |
828 | 0 | var->nsd = 0; |
829 | 0 | } |
830 | | |
831 | 0 | done: |
832 | 0 | return ZUNTRACE(retval); |
833 | 0 | } |
834 | | |
835 | | /** |
836 | | * @internal Set compression settings on a variable. This is called by |
837 | | * nc_def_var_deflate(). |
838 | | * |
839 | | * @param ncid File ID. |
840 | | * @param varid Variable ID. |
841 | | * @param shuffle True to turn on the shuffle filter. |
842 | | * @param deflate True to turn on deflation. |
843 | | * @param deflate_level A number between 0 (no compression) and 9 |
844 | | * (maximum compression). |
845 | | * |
846 | | * @returns ::NC_NOERR No error. |
847 | | * @returns ::NC_EBADID Bad ncid. |
848 | | * @returns ::NC_ENOTVAR Invalid variable ID. |
849 | | * @returns ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is |
850 | | * not netCDF-4/NCZ. |
851 | | * @returns ::NC_ELATEDEF Too late to change settings for this variable. |
852 | | * @returns ::NC_ENOTINDEFINE Not in define mode. |
853 | | * @returns ::NC_EINVAL Invalid input |
854 | | * @author Dennis Heimbigner, Ed Hartnett |
855 | | */ |
856 | | int |
857 | | NCZ_def_var_deflate(int ncid, int varid, int shuffle, int deflate, |
858 | | int deflate_level) |
859 | 0 | { |
860 | 0 | int stat = NC_NOERR; |
861 | 0 | unsigned int level = (unsigned int)deflate_level; |
862 | | /* Set shuffle first */ |
863 | 0 | if((stat = ncz_def_var_extra(ncid, varid, &shuffle, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL))) goto done; |
864 | 0 | if(deflate) |
865 | 0 | stat = nc_def_var_filter(ncid, varid, H5Z_FILTER_DEFLATE,1,&level); |
866 | 0 | if(stat) goto done; |
867 | 0 | done: |
868 | 0 | return stat; |
869 | 0 | } |
870 | | |
871 | | /** |
872 | | * @internal Set checksum on a variable. This is called by |
873 | | * nc_def_var_fletcher32(). |
874 | | * |
875 | | * @param ncid File ID. |
876 | | * @param varid Variable ID. |
877 | | * @param fletcher32 Pointer to fletcher32 setting. |
878 | | * |
879 | | * @returns ::NC_NOERR No error. |
880 | | * @returns ::NC_EBADID Bad ncid. |
881 | | * @returns ::NC_ENOTVAR Invalid variable ID. |
882 | | * @returns ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is |
883 | | * not netCDF-4/NCZ. |
884 | | * @returns ::NC_ELATEDEF Too late to change settings for this variable. |
885 | | * @returns ::NC_ENOTINDEFINE Not in define mode. |
886 | | * @returns ::NC_EINVAL Invalid input |
887 | | * @author Dennis Heimbigner, Ed Hartnett |
888 | | */ |
889 | | int |
890 | | NCZ_def_var_fletcher32(int ncid, int varid, int fletcher32) |
891 | 0 | { |
892 | 0 | return ncz_def_var_extra(ncid, varid, NULL, NULL, NULL, &fletcher32, |
893 | 0 | NULL, NULL, NULL, NULL, NULL, NULL, NULL); |
894 | 0 | } |
895 | | |
896 | | /** |
897 | | * @internal Define chunking stuff for a var. This is called by |
898 | | * nc_def_var_chunking(). Chunking is required in any dataset with one |
899 | | * or more unlimited dimensions in NCZ, or any dataset using a |
900 | | * filter. |
901 | | * |
902 | | * @param ncid File ID. |
903 | | * @param varid Variable ID. |
904 | | * @param contiguous Pointer to contiguous setting. |
905 | | * @param chunksizesp Array of chunksizes. |
906 | | * |
907 | | * @returns ::NC_NOERR No error. |
908 | | * @returns ::NC_EBADID Bad ncid. |
909 | | * @returns ::NC_ENOTVAR Invalid variable ID. |
910 | | * @returns ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is |
911 | | * not netCDF-4/NCZ. |
912 | | * @returns ::NC_ELATEDEF Too late to change settings for this variable. |
913 | | * @returns ::NC_ENOTINDEFINE Not in define mode. |
914 | | * @returns ::NC_EINVAL Invalid input |
915 | | * @returns ::NC_EBADCHUNK Bad chunksize. |
916 | | * @author Dennis Heimbigner, Ed Hartnett |
917 | | */ |
918 | | int |
919 | | NCZ_def_var_chunking(int ncid, int varid, int contiguous, const size_t *chunksizesp) |
920 | 0 | { |
921 | 0 | return ncz_def_var_extra(ncid, varid, NULL, NULL, NULL, NULL, |
922 | 0 | &contiguous, chunksizesp, NULL, NULL, NULL, NULL, NULL); |
923 | 0 | } |
924 | | |
925 | | /** |
926 | | * @internal Define chunking stuff for a var. This is called by |
927 | | * the fortran API. |
928 | | * |
929 | | * @param ncid File ID. |
930 | | * @param varid Variable ID. |
931 | | * @param contiguous Pointer to contiguous setting. |
932 | | * @param chunksizesp Array of chunksizes. |
933 | | * |
934 | | * @returns ::NC_NOERR No error. |
935 | | * @returns ::NC_EBADID Bad ncid. |
936 | | * @returns ::NC_ENOTVAR Invalid variable ID. |
937 | | * @returns ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is |
938 | | * not netCDF-4/NCZ. |
939 | | * @returns ::NC_ELATEDEF Too late to change settings for this variable. |
940 | | * @returns ::NC_ENOTINDEFINE Not in define mode. |
941 | | * @returns ::NC_EINVAL Invalid input |
942 | | * @returns ::NC_EBADCHUNK Bad chunksize. |
943 | | * @author Dennis Heimbigner, Ed Hartnett |
944 | | */ |
945 | | int |
946 | | ncz_def_var_chunking_ints(int ncid, int varid, int contiguous, int *chunksizesp) |
947 | 0 | { |
948 | 0 | NC_VAR_INFO_T *var; |
949 | 0 | size_t *cs; |
950 | 0 | int i, retval; |
951 | | |
952 | | /* Get pointer to the var. */ |
953 | 0 | if ((retval = nc4_find_grp_h5_var(ncid, varid, NULL, NULL, &var))) |
954 | 0 | return THROW(retval); |
955 | 0 | assert(var); |
956 | | |
957 | | /* Allocate space for the size_t copy of the chunksizes array. */ |
958 | 0 | if (var->ndims) |
959 | 0 | if (!(cs = malloc(var->ndims * sizeof(size_t)))) |
960 | 0 | return NC_ENOMEM; |
961 | | |
962 | | /* Copy to size_t array. */ |
963 | 0 | for (i = 0; i < var->ndims; i++) |
964 | 0 | cs[i] = chunksizesp[i]; |
965 | |
|
966 | 0 | retval = ncz_def_var_extra(ncid, varid, NULL, NULL, NULL, NULL, |
967 | 0 | &contiguous, cs, NULL, NULL, NULL, NULL, NULL); |
968 | |
|
969 | 0 | if (var->ndims) |
970 | 0 | free(cs); |
971 | 0 | return THROW(retval); |
972 | 0 | } |
973 | | |
974 | | /** |
975 | | * @internal This functions sets fill value and no_fill mode for a |
976 | | * netCDF-4 variable. It is called by nc_def_var_fill(). |
977 | | * |
978 | | * @note All pointer parameters may be NULL, in which case they are ignored. |
979 | | * @param ncid File ID. |
980 | | * @param varid Variable ID. |
981 | | * @param no_fill No_fill setting. |
982 | | * @param fill_value Pointer to fill value. |
983 | | * |
984 | | * @returns ::NC_NOERR for success |
985 | | * @returns ::NC_EBADID Bad ncid. |
986 | | * @returns ::NC_ENOTVAR Invalid variable ID. |
987 | | * @returns ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is |
988 | | * not netCDF-4/NCZ. |
989 | | * @returns ::NC_ESTRICTNC3 Attempting netcdf-4 operation on strict nc3 |
990 | | * netcdf-4 file. |
991 | | * @returns ::NC_ELATEDEF Too late to change settings for this variable. |
992 | | * @returns ::NC_ENOTINDEFINE Not in define mode. |
993 | | * @returns ::NC_EPERM File is read only. |
994 | | * @returns ::NC_EINVAL Invalid input |
995 | | * @author Dennis Heimbigner, Ed Hartnett |
996 | | */ |
997 | | int |
998 | | NCZ_def_var_fill(int ncid, int varid, int no_fill, const void *fill_value) |
999 | 0 | { |
1000 | 0 | return ncz_def_var_extra(ncid, varid, NULL, NULL, NULL, NULL, NULL, |
1001 | 0 | NULL, &no_fill, fill_value, NULL, NULL, NULL); |
1002 | 0 | } |
1003 | | |
1004 | | /** |
1005 | | * @internal This functions sets endianness for a netCDF-4 |
1006 | | * variable. Called by nc_def_var_endian(). |
1007 | | * |
1008 | | * @note All pointer parameters may be NULL, in which case they are ignored. |
1009 | | * @param ncid File ID. |
1010 | | * @param varid Variable ID. |
1011 | | * @param endianness Endianness setting. |
1012 | | * |
1013 | | * @returns ::NC_NOERR for success |
1014 | | * @returns ::NC_EBADID Bad ncid. |
1015 | | * @returns ::NC_ENOTVAR Invalid variable ID. |
1016 | | * @returns ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is |
1017 | | * not netCDF-4/NCZ. |
1018 | | * @returns ::NC_ESTRICTNC3 Attempting netcdf-4 operation on strict nc3 |
1019 | | * netcdf-4 file. |
1020 | | * @returns ::NC_ELATEDEF Too late to change settings for this variable. |
1021 | | * @returns ::NC_ENOTINDEFINE Not in define mode. |
1022 | | * @returns ::NC_EPERM File is read only. |
1023 | | * @returns ::NC_EINVAL Invalid input |
1024 | | * @author Dennis Heimbigner, Ed Hartnett |
1025 | | */ |
1026 | | int |
1027 | | NCZ_def_var_endian(int ncid, int varid, int endianness) |
1028 | 0 | { |
1029 | 0 | return ncz_def_var_extra(ncid, varid, NULL, NULL, NULL, NULL, NULL, |
1030 | 0 | NULL, NULL, NULL, &endianness, NULL, NULL); |
1031 | 0 | } |
1032 | | |
1033 | | /** |
1034 | | * @internal Set quantization settings on a variable. This is |
1035 | | * called by nc_def_var_quantize(). |
1036 | | * |
1037 | | * Quantization allows the user to specify a number of significant |
1038 | | * digits for variables of type ::NC_FLOAT or ::NC_DOUBLE. (Attempting |
1039 | | * to set quantize for other types will result in an ::NC_EINVAL |
1040 | | * error.) |
1041 | | * |
1042 | | * When quantize is turned on, and the number of significant digits |
1043 | | * (NSD) has been specified, then the netCDF library will quantize according |
1044 | | * to the selected algorithm. BitGroom interprets NSD as decimal digits |
1045 | | * will apply all zeros or all ones (alternating) to bits which are not |
1046 | | * needed to specify the value to the number of significant decimal digits. |
1047 | | * BitGroom retain the same number of bits for all values of a variable. |
1048 | | * BitRound (BR) interprets NSD as binary digits (i.e., bits) and keeps the |
1049 | | * the user-specified number of significant bits then rounds the result |
1050 | | * to the nearest representable number according to IEEE rounding rules. |
1051 | | * BG and BR both retain a uniform number of significant bits for all |
1052 | | * values of a variable. Granular BitRound interprest NSD as decimal |
1053 | | * digits. GranularBR determines the number of bits to necessary to |
1054 | | * retain the user-specified number of significant digits individually |
1055 | | * for every value of the variable. GranularBR then applies the BR |
1056 | | * quantization algorithm on a granular, value-by-value, rather than |
1057 | | * uniformly for the entire variable. GranularBR quantizes more bits |
1058 | | * than BG, and is thus more compressive and less accurate than BG. |
1059 | | * BR knows bits and makes no guarantees about decimal precision. |
1060 | | * All quantization algorithms change the values of the data, and make |
1061 | | * it more compressible. |
1062 | | * |
1063 | | * Quantizing the data does not reduce the size of the data on disk, |
1064 | | * but combining quantize with compression will allow for better |
1065 | | * compression. Since the data values are changed, the use of quantize |
1066 | | * and compression such as deflate constitute lossy compression. |
1067 | | * |
1068 | | * Producers of large datasets may find that using quantize with |
1069 | | * compression will result in significant improvent in the final data |
1070 | | * size. |
1071 | | * |
1072 | | * Variables which use quantize will have added an attribute with name |
1073 | | * ::NC_QUANTIZE_BITGROOM_ATT_NAME, ::NC_QUANTIZE_GRANULARBR_ATT_NAME, |
1074 | | * or ::NC_QUANTIZE_BITROUND_ATT_NAME that contains the number of |
1075 | | * significant digits. Users should not delete or change this attribute. |
1076 | | * This is the only record that quantize has been applied to the data. |
1077 | | * |
1078 | | * As with the deflate settings, quantize settings may only be |
1079 | | * modified before the first call to nc_enddef(). Once nc_enddef() is |
1080 | | * called for the file, quantize settings for any variable in the file |
1081 | | * may not be changed. |
1082 | | * |
1083 | | * Use of quantization is fully backwards compatible with existing |
1084 | | * versions and packages that can read compressed netCDF data. A |
1085 | | * variable which has been quantized is readable to older versions of |
1086 | | * the netCDF libraries, and to netCDF-Java. |
1087 | | * |
1088 | | * @param ncid File ID. |
1089 | | * @param varid Variable ID. NC_GLOBAL may not be used. |
1090 | | * @param quantize_mode Quantization mode. May be ::NC_NOQUANTIZE or |
1091 | | * ::NC_QUANTIZE_BITGROOM, ::NC_QUANTIZE_BITROUND or ::NC_QUANTIZE_GRANULARBR. |
1092 | | * @param nsd Number of significant digits (either decimal or binary). |
1093 | | * May be any integer from 1 to ::NC_QUANTIZE_MAX_FLOAT_NSD (for variables |
1094 | | * of type ::NC_FLOAT) or ::NC_QUANTIZE_MAX_DOUBLE_NSD (for variables |
1095 | | * of type ::NC_DOUBLE) for mode ::NC_QUANTIZE_BITGROOM and mode |
1096 | | * ::NC_QUANTIZE_GRANULARBR. May be any integer from 1 to |
1097 | | * ::NC_QUANTIZE_MAX_FLOAT_NSB (for variables of type ::NC_FLOAT) or |
1098 | | * ::NC_QUANTIZE_MAX_DOUBLE_NSB (for variables of type ::NC_DOUBLE) |
1099 | | * for mode ::NC_QUANTIZE_BITROUND. |
1100 | | * |
1101 | | * @returns ::NC_NOERR No error. |
1102 | | * @returns ::NC_EBADID Bad ncid. |
1103 | | * @returns ::NC_ENOTVAR Invalid variable ID. |
1104 | | * @returns ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is |
1105 | | * not netCDF-4/HDF5. |
1106 | | * @returns ::NC_ELATEDEF Too late to change settings for this variable. |
1107 | | * @returns ::NC_ENOTINDEFINE Not in define mode. |
1108 | | * @returns ::NC_EINVAL Invalid input |
1109 | | * @author Ed Hartnett, Dennis Heimbigner |
1110 | | */ |
1111 | | int |
1112 | | NCZ_def_var_quantize(int ncid, int varid, int quantize_mode, int nsd) |
1113 | 0 | { |
1114 | 0 | return ncz_def_var_extra(ncid, varid, NULL, NULL, NULL, NULL, |
1115 | 0 | NULL, NULL, NULL, NULL, NULL, |
1116 | 0 | &quantize_mode, &nsd); |
1117 | 0 | } |
1118 | | |
1119 | | /** |
1120 | | Ensure that the quantize information for a variable is defined. |
1121 | | Keep a flag in the NCZ_VAR_INFO_T struct to indicate if quantize |
1122 | | info is defined, and if not, read the attribute. |
1123 | | */ |
1124 | | int |
1125 | | NCZ_ensure_quantizer(int ncid, NC_VAR_INFO_T* var) |
1126 | 0 | { |
1127 | 0 | int nsd = 0; |
1128 | | |
1129 | | /* Read the attribute */ |
1130 | 0 | if(NCZ_get_att(ncid,var->hdr.id,NC_QUANTIZE_BITGROOM_ATT_NAME,&nsd,NC_INT)==NC_NOERR) { |
1131 | 0 | var->quantize_mode = NC_QUANTIZE_BITGROOM; |
1132 | 0 | var->nsd = nsd; |
1133 | 0 | } else if(NCZ_get_att(ncid,var->hdr.id,NC_QUANTIZE_GRANULARBR_ATT_NAME,&nsd,NC_INT)==NC_NOERR) { |
1134 | 0 | var->quantize_mode = NC_QUANTIZE_GRANULARBR; |
1135 | 0 | var->nsd = nsd; |
1136 | 0 | } else if(NCZ_get_att(ncid,var->hdr.id,NC_QUANTIZE_BITROUND_ATT_NAME,&nsd,NC_INT)==NC_NOERR) { |
1137 | 0 | var->quantize_mode = NC_QUANTIZE_BITROUND; |
1138 | 0 | var->nsd = nsd; |
1139 | 0 | } else { |
1140 | 0 | var->quantize_mode = NC_NOQUANTIZE; |
1141 | 0 | var->nsd = 0; |
1142 | 0 | } |
1143 | 0 | if(var->quantize_mode < 0) var->quantize_mode = 0; |
1144 | 0 | return NC_NOERR; |
1145 | 0 | } |
1146 | | |
1147 | | /** |
1148 | | * @internal Get quantize information about a variable. Pass NULL for |
1149 | | * whatever you don't care about. Note that this can require reading |
1150 | | * all the attributes for the variable. |
1151 | | * |
1152 | | * @param ncid File ID. |
1153 | | * @param varid Variable ID. |
1154 | | * @param quantize_modep Gets quantize mode. |
1155 | | * @param nsdp Gets Number of Significant Digits if quantize is in use. |
1156 | | * |
1157 | | * @returns ::NC_NOERR No error. |
1158 | | * @returns ::NC_EBADID Bad ncid. |
1159 | | * @returns ::NC_ENOTVAR Bad varid. |
1160 | | * @returns ::NC_EINVAL Invalid input. |
1161 | | * @author Ed Hartnett |
1162 | | */ |
1163 | | int |
1164 | | NCZ_inq_var_quantize(int ncid, int varid, int *quantize_modep, |
1165 | | int *nsdp) |
1166 | 0 | { |
1167 | 0 | NC_VAR_INFO_T *var; |
1168 | 0 | int retval; |
1169 | |
|
1170 | 0 | LOG((2, "%s: ncid 0x%x varid %d", __func__, ncid, varid)); |
1171 | | |
1172 | | /* Find info for this file and group, and set pointer to each. */ |
1173 | | /* Get pointer to the var. */ |
1174 | 0 | if ((retval = nc4_find_grp_h5_var(ncid, varid, NULL, NULL, &var))) |
1175 | 0 | return retval; |
1176 | 0 | if (!var) |
1177 | 0 | return NC_ENOTVAR; |
1178 | 0 | assert(var->hdr.id == varid); |
1179 | 0 | if(var->quantize_mode == -1) |
1180 | 0 | {if((retval = NCZ_ensure_quantizer(ncid, var))) return retval;} |
1181 | | /* Copy the data to the user's data buffers. */ |
1182 | 0 | if (quantize_modep) |
1183 | 0 | *quantize_modep = var->quantize_mode; |
1184 | 0 | if (nsdp) |
1185 | 0 | *nsdp = var->nsd; |
1186 | 0 | return NC_NOERR; |
1187 | 0 | } |
1188 | | |
1189 | | /** |
1190 | | * @internal Rename a var to "bubba," for example. This is called by |
1191 | | * nc_rename_var() for netCDF-4 files. This results in complexities |
1192 | | * when coordinate variables are involved. |
1193 | | |
1194 | | * Whenever a var has the same name as a dim, and also uses that dim |
1195 | | * as its first dimension, then that var is aid to be a coordinate |
1196 | | * variable for that dimensions. Coordinate variables are represented |
1197 | | * in the ZARR by making them dimscales. Dimensions without coordinate |
1198 | | * vars are represented by datasets which are dimscales, but have a |
1199 | | * special attribute marking them as dimscales without associated |
1200 | | * coordinate variables. |
1201 | | * |
1202 | | * When a var is renamed, we must detect whether it has become a |
1203 | | * coordinate var (by being renamed to the same name as a dim that is |
1204 | | * also its first dimension), or whether it is no longer a coordinate |
1205 | | * var. These cause flags to be set in NC_VAR_INFO_T which are used at |
1206 | | * enddef time to make changes in the ZARR file. |
1207 | | * |
1208 | | * @param ncid File ID. |
1209 | | * @param varid Variable ID |
1210 | | * @param name New name of the variable. |
1211 | | * |
1212 | | * @returns ::NC_NOERR No error. |
1213 | | * @returns ::NC_EBADID Bad ncid. |
1214 | | * @returns ::NC_ENOTVAR Invalid variable ID. |
1215 | | * @returns ::NC_EBADNAME Bad name. |
1216 | | * @returns ::NC_EMAXNAME Name is too long. |
1217 | | * @returns ::NC_ENAMEINUSE Name in use. |
1218 | | * @returns ::NC_ENOMEM Out of memory. |
1219 | | * @author Dennis Heimbigner, Ed Hartnett |
1220 | | */ |
1221 | | int |
1222 | | NCZ_rename_var(int ncid, int varid, const char *name) |
1223 | 0 | { |
1224 | 0 | NC_GRP_INFO_T *grp; |
1225 | 0 | NC_FILE_INFO_T *h5; |
1226 | 0 | NC_VAR_INFO_T *var; |
1227 | 0 | int retval = NC_NOERR; |
1228 | |
|
1229 | 0 | if (!name) |
1230 | 0 | return NC_EINVAL; |
1231 | | |
1232 | 0 | LOG((2, "%s: ncid 0x%x varid %d name %s", __func__, ncid, varid, name)); |
1233 | |
|
1234 | 0 | ZTRACE(1,"ncid=%d varid=%d name='%s'",ncid,varid,name); |
1235 | | |
1236 | | /* Find info for this file and group, and set pointer to each. */ |
1237 | 0 | if ((retval = nc4_find_grp_h5(ncid, &grp, &h5))) |
1238 | 0 | return THROW(retval); |
1239 | 0 | assert(h5 && grp && grp->format_grp_info); |
1240 | | |
1241 | | /* Is the new name too long? */ |
1242 | 0 | if (strlen(name) > NC_MAX_NAME) |
1243 | 0 | return NC_EMAXNAME; |
1244 | | |
1245 | | /* Trying to write to a read-only file? No way, Jose! */ |
1246 | 0 | if (h5->no_write) |
1247 | 0 | return NC_EPERM; |
1248 | | |
1249 | | /* Check name validity, if strict nc3 rules are in effect for this |
1250 | | * file. */ |
1251 | 0 | if ((retval = NC_check_name(name))) |
1252 | 0 | return THROW(retval); |
1253 | | |
1254 | | /* Get the variable wrt varid */ |
1255 | 0 | if (!(var = (NC_VAR_INFO_T *)ncindexith(grp->vars, varid))) |
1256 | 0 | return NC_ENOTVAR; |
1257 | | |
1258 | | /* Check if new name is in use; note that renaming to same name is |
1259 | | still an error according to the nc_test/test_write.c |
1260 | | code. Why?*/ |
1261 | 0 | if (ncindexlookup(grp->vars, name)) |
1262 | 0 | return NC_ENAMEINUSE; |
1263 | | |
1264 | | /* If we're not in define mode, new name must be of equal or |
1265 | | less size, if strict nc3 rules are in effect for this . */ |
1266 | 0 | if (!(h5->flags & NC_INDEF) && strlen(name) > strlen(var->hdr.name) && |
1267 | 0 | (h5->cmode & NC_CLASSIC_MODEL)) |
1268 | 0 | return NC_ENOTINDEFINE; |
1269 | | |
1270 | | #ifdef LOOK |
1271 | | /* Is there another dim with this name, for which this var will not |
1272 | | * be a coord var? If so, we have to create a dim without a |
1273 | | * variable for the old name. */ |
1274 | | if ((other_dim = (NC_DIM_INFO_T *)ncindexlookup(grp->dim, name)) && |
1275 | | strcmp(name, var->dim[0]->hdr.name)) |
1276 | | { |
1277 | | /* Create a dim without var dataset for old dim. */ |
1278 | | if ((retval = ncz_create_dim_wo_var(other_dim))) |
1279 | | return THROW(retval); |
1280 | | |
1281 | | /* Give this var a secret ZARR name so it can co-exist in file |
1282 | | * with dim wp var dataset. Base the secret name on the new var |
1283 | | * name. */ |
1284 | | if ((retval = give_var_secret_name(var, name))) |
1285 | | return THROW(retval); |
1286 | | use_secret_name++; |
1287 | | } |
1288 | | |
1289 | | /* Change the ZARR file, if this var has already been created |
1290 | | there. */ |
1291 | | if (var->created) |
1292 | | { |
1293 | | int v; |
1294 | | char *ncz_name; /* Dataset will be renamed to this. */ |
1295 | | ncz_name = use_secret_name ? var->ncz_name: (char *)name; |
1296 | | |
1297 | | /* Do we need to read var metadata? */ |
1298 | | if (!var->meta_read) |
1299 | | if ((retval = ncz_get_var_meta(var))) |
1300 | | return THROW(retval); |
1301 | | |
1302 | | if (var->ndims) |
1303 | | { |
1304 | | NCZ_DIM_INFO_T *ncz_d0; |
1305 | | ncz_d0 = (NCZ_DIM_INFO_T *)var->dim[0]->format_dim_info; |
1306 | | |
1307 | | /* Is there an existing dimscale-only dataset of this name? If |
1308 | | * so, it must be deleted. */ |
1309 | | if (ncz_d0->hdf_dimscaleid) |
1310 | | { |
1311 | | if ((retval = delete_dimscale_dataset(grp, var->dim[0]->hdr.id, |
1312 | | var->dim[0]))) |
1313 | | return THROW(retval); |
1314 | | } |
1315 | | } |
1316 | | |
1317 | | LOG((3, "Moving dataset %s to %s", var->hdr.name, name)); |
1318 | | if (H5Lmove(ncz_grp->hdf_grpid, var->hdr.name, ncz_grp->hdf_grpid, |
1319 | | ncz_name, H5P_DEFAULT, H5P_DEFAULT) < 0) |
1320 | | return NC_EHDFERR; |
1321 | | |
1322 | | /* Rename all the vars in this file with a varid greater than |
1323 | | * this var. Varids are assigned based on dataset creation time, |
1324 | | * and we have just changed that for this var. We must do the |
1325 | | * same for all vars with a > varid, so that the creation order |
1326 | | * will continue to be correct. */ |
1327 | | for (v = var->hdr.id + 1; v < ncindexsize(grp->vars); v++) |
1328 | | { |
1329 | | NC_VAR_INFO_T *my_var; |
1330 | | my_var = (NC_VAR_INFO_T *)ncindexith(grp->vars, v); |
1331 | | assert(my_var); |
1332 | | |
1333 | | LOG((3, "mandatory rename of %s to same name", my_var->hdr.name)); |
1334 | | |
1335 | | /* Rename to temp name. */ |
1336 | | if (H5Lmove(ncz_grp->hdf_grpid, my_var->hdr.name, ncz_grp->hdf_grpid, |
1337 | | NC_TEMP_NAME, H5P_DEFAULT, H5P_DEFAULT) < 0) |
1338 | | return NC_EHDFERR; |
1339 | | |
1340 | | /* Rename to real name. */ |
1341 | | if (H5Lmove(ncz_grp->hdf_grpid, NC_TEMP_NAME, ncz_grp->hdf_grpid, |
1342 | | my_var->hdr.name, H5P_DEFAULT, H5P_DEFAULT) < 0) |
1343 | | return NC_EHDFERR; |
1344 | | } |
1345 | | } |
1346 | | #endif |
1347 | | |
1348 | | /* Now change the name in our metadata. */ |
1349 | 0 | free(var->hdr.name); |
1350 | 0 | if (!(var->hdr.name = strdup(name))) |
1351 | 0 | return NC_ENOMEM; |
1352 | 0 | LOG((3, "var is now %s", var->hdr.name)); |
1353 | | |
1354 | | /* rebuild index. */ |
1355 | 0 | if (!ncindexrebuild(grp->vars)) |
1356 | 0 | return NC_EINTERNAL; |
1357 | | |
1358 | | #ifdef LOOK |
1359 | | /* Check if this was a coordinate variable previously, but names |
1360 | | * are different now */ |
1361 | | if (var->dimscale && strcmp(var->hdr.name, var->dim[0]->hdr.name)) |
1362 | | { |
1363 | | /* Break up the coordinate variable */ |
1364 | | if ((retval = ncz_break_coord_var(grp, var, var->dim[0]))) |
1365 | | return THROW(retval); |
1366 | | } |
1367 | | |
1368 | | /* Check if this should become a coordinate variable. */ |
1369 | | if (!var->dimscale) |
1370 | | { |
1371 | | /* Only variables with >0 dimensions can become coordinate |
1372 | | * variables. */ |
1373 | | if (var->ndims) |
1374 | | { |
1375 | | NC_GRP_INFO_T *dim_grp; |
1376 | | NC_DIM_INFO_T *dim; |
1377 | | |
1378 | | /* Check to see if this is became a coordinate variable. If |
1379 | | * so, it will have the same name as dimension index 0. If it |
1380 | | * is a coordinate var, is it a coordinate var in the same |
1381 | | * group as the dim? */ |
1382 | | if ((retval = ncz_find_dim(grp, var->dimids[0], &dim, &dim_grp))) |
1383 | | return THROW(retval); |
1384 | | if (!strcmp(dim->hdr.name, name) && dim_grp == grp) |
1385 | | { |
1386 | | /* Reform the coordinate variable. */ |
1387 | | if ((retval = ncz_reform_coord_var(grp, var, dim))) |
1388 | | return THROW(retval); |
1389 | | var->became_coord_var = NC_TRUE; |
1390 | | } |
1391 | | } |
1392 | | } |
1393 | | #endif |
1394 | | |
1395 | 0 | return THROW(retval); |
1396 | 0 | } |
1397 | | |
1398 | | /** |
1399 | | * @internal Write an array of data to a variable. This is called by |
1400 | | * nc_put_vara() and other nc_put_vara_* functions, for netCDF-4 |
1401 | | * files. |
1402 | | * |
1403 | | * @param ncid File ID. |
1404 | | * @param varid Variable ID. |
1405 | | * @param startp Array of start indices. |
1406 | | * @param countp Array of counts. |
1407 | | * @param op pointer that gets the data. |
1408 | | * @param memtype The type of these data in memory. |
1409 | | * |
1410 | | * @returns ::NC_NOERR for success |
1411 | | * @author Dennis Heimbigner, Ed Hartnett |
1412 | | */ |
1413 | | int |
1414 | | NCZ_put_vara(int ncid, int varid, const size_t *startp, |
1415 | | const size_t *countp, const void *op, int memtype) |
1416 | 0 | { |
1417 | 0 | return NCZ_put_vars(ncid, varid, startp, countp, NULL, op, memtype); |
1418 | 0 | } |
1419 | | |
1420 | | /** |
1421 | | * @internal Read an array of values. This is called by nc_get_vara() |
1422 | | * for netCDF-4 files, as well as all the other nc_get_vara_* |
1423 | | * functions. |
1424 | | * |
1425 | | * @param ncid File ID. |
1426 | | * @param varid Variable ID. |
1427 | | * @param startp Array of start indices. |
1428 | | * @param countp Array of counts. |
1429 | | * @param ip pointer that gets the data. |
1430 | | * @param memtype The type of these data after it is read into memory. |
1431 | | |
1432 | | * @returns ::NC_NOERR for success |
1433 | | * @author Dennis Heimbigner, Ed Hartnett |
1434 | | */ |
1435 | | int |
1436 | | NCZ_get_vara(int ncid, int varid, const size_t *startp, |
1437 | | const size_t *countp, void *ip, int memtype) |
1438 | 0 | { |
1439 | 0 | return NCZ_get_vars(ncid, varid, startp, countp, NULL, ip, memtype); |
1440 | 0 | } |
1441 | | |
1442 | | /** |
1443 | | * @internal Do some common check for NCZ_put_vars and |
1444 | | * NCZ_get_vars. These checks have to be done when both reading and |
1445 | | * writing data. |
1446 | | * |
1447 | | * @param mem_nc_type Pointer to type of data in memory. |
1448 | | * @param var Pointer to var info struct. |
1449 | | * @param h5 Pointer to ZARR file info struct. |
1450 | | * |
1451 | | * @return ::NC_NOERR No error. |
1452 | | * @author Dennis Heimbigner, Ed Hartnett |
1453 | | */ |
1454 | | static int |
1455 | | check_for_vara(nc_type *mem_nc_type, NC_VAR_INFO_T *var, NC_FILE_INFO_T *h5) |
1456 | 0 | { |
1457 | 0 | int retval; |
1458 | | |
1459 | | /* If mem_nc_type is NC_NAT, it means we want to use the file type |
1460 | | * as the mem type as well. */ |
1461 | 0 | assert(mem_nc_type); |
1462 | 0 | if (*mem_nc_type == NC_NAT) |
1463 | 0 | *mem_nc_type = var->type_info->hdr.id; |
1464 | 0 | assert(*mem_nc_type); |
1465 | | |
1466 | | /* No NC_CHAR conversions, you pervert! */ |
1467 | 0 | if (var->type_info->hdr.id != *mem_nc_type && |
1468 | 0 | (var->type_info->hdr.id == NC_CHAR || *mem_nc_type == NC_CHAR)) |
1469 | 0 | return NC_ECHAR; |
1470 | | |
1471 | | /* If we're in define mode, we can't read or write data. */ |
1472 | 0 | if (h5->flags & NC_INDEF) |
1473 | 0 | { |
1474 | 0 | if (h5->cmode & NC_CLASSIC_MODEL) |
1475 | 0 | return NC_EINDEFINE; |
1476 | 0 | if ((retval = ncz_enddef_netcdf4_file(h5))) |
1477 | 0 | return THROW(retval); |
1478 | 0 | } |
1479 | | |
1480 | 0 | return NC_NOERR; |
1481 | 0 | } |
1482 | | |
1483 | | #ifdef LOGGING |
1484 | | /** |
1485 | | * @intarnal Print some debug info about dimensions to the log. |
1486 | | */ |
1487 | | static void |
1488 | | log_dim_info(NC_VAR_INFO_T *var, size64_t *fdims, size64_t *fmaxdims, |
1489 | | size64_t *start, size64_t *count) |
1490 | | { |
1491 | | int d2; |
1492 | | |
1493 | | /* Print some debugging info... */ |
1494 | | LOG((4, "%s: var name %s ndims %d", __func__, var->hdr.name, var->ndims)); |
1495 | | LOG((4, "File space, and requested:")); |
1496 | | for (d2 = 0; d2 < var->ndims; d2++) |
1497 | | { |
1498 | | LOG((4, "fdims[%d]=%Ld fmaxdims[%d]=%Ld", d2, fdims[d2], d2, |
1499 | | fmaxdims[d2])); |
1500 | | LOG((4, "start[%d]=%Ld count[%d]=%Ld", d2, start[d2], d2, count[d2])); |
1501 | | } |
1502 | | } |
1503 | | #endif /* LOGGING */ |
1504 | | |
1505 | | /** |
1506 | | * @internal Write a strided array of data to a variable. This is |
1507 | | * called by nc_put_vars() and other nc_put_vars_* functions, for |
1508 | | * netCDF-4 files. Also the nc_put_vara() calls end up calling this |
1509 | | * with a NULL stride parameter. |
1510 | | * |
1511 | | * @param ncid File ID. |
1512 | | * @param varid Variable ID. |
1513 | | * @param startp Array of start indices. Must always be provided by |
1514 | | * caller for non-scalar vars. |
1515 | | * @param countp Array of counts. Will default to counts of full |
1516 | | * dimension size if NULL. |
1517 | | * @param stridep Array of strides. Will default to strides of 1 if |
1518 | | * NULL. |
1519 | | * @param data The data to be written. |
1520 | | * @param mem_nc_type The type of the data in memory. |
1521 | | * |
1522 | | * @returns ::NC_NOERR No error. |
1523 | | * @returns ::NC_EBADID Bad ncid. |
1524 | | * @returns ::NC_ENOTVAR Var not found. |
1525 | | * @returns ::NC_EHDFERR ZARR function returned error. |
1526 | | * @returns ::NC_EINVALCOORDS Incorrect start. |
1527 | | * @returns ::NC_EEDGE Incorrect start/count. |
1528 | | * @returns ::NC_ENOMEM Out of memory. |
1529 | | * @returns ::NC_EMPI MPI library error (parallel only) |
1530 | | * @returns ::NC_ECANTEXTEND Can't extend dimension for write. |
1531 | | * @returns ::NC_ERANGE Data conversion error. |
1532 | | * @author Dennis Heimbigner, Ed Hartnett |
1533 | | */ |
1534 | | int |
1535 | | NCZ_put_vars(int ncid, int varid, const size_t *startp, const size_t *countp, |
1536 | | const ptrdiff_t *stridep, const void *data, nc_type mem_nc_type) |
1537 | 0 | { |
1538 | 0 | NC_GRP_INFO_T *grp; |
1539 | 0 | NC_FILE_INFO_T *h5; |
1540 | 0 | NC_VAR_INFO_T *var; |
1541 | 0 | NC_DIM_INFO_T *dim; |
1542 | | #ifdef LOOK |
1543 | | hid_t file_spaceid = 0, mem_spaceid = 0, xfer_plistid = 0; |
1544 | | #endif |
1545 | 0 | size64_t fdims[NC_MAX_VAR_DIMS]; |
1546 | 0 | size64_t start[NC_MAX_VAR_DIMS], count[NC_MAX_VAR_DIMS]; |
1547 | 0 | size64_t stride[NC_MAX_VAR_DIMS]; |
1548 | 0 | int retval, range_error = 0, i, d2; |
1549 | 0 | void *bufr = NULL; |
1550 | 0 | int bufrd = 0; /* 1 => we allocated bufr */ |
1551 | 0 | int need_to_convert = 0; |
1552 | 0 | int zero_count = 0; /* true if a count is zero */ |
1553 | 0 | size_t len = 1; |
1554 | 0 | size64_t fmaxdims[NC_MAX_VAR_DIMS]; |
1555 | 0 | NCZ_VAR_INFO_T* zvar; |
1556 | |
|
1557 | 0 | NC_UNUSED(fmaxdims); |
1558 | |
|
1559 | 0 | #ifndef LOOK |
1560 | 0 | NC_UNUSED(fmaxdims); |
1561 | 0 | #endif |
1562 | | |
1563 | | /* Find info for this file, group, and var. */ |
1564 | 0 | if ((retval = nc4_find_grp_h5_var(ncid, varid, &h5, &grp, &var))) |
1565 | 0 | return THROW(retval); |
1566 | 0 | assert(h5 && grp && var && var->hdr.id == varid && var->format_var_info); |
1567 | | |
1568 | 0 | LOG((3, "%s: var->hdr.name %s mem_nc_type %d", __func__, |
1569 | 0 | var->hdr.name, mem_nc_type)); |
1570 | |
|
1571 | 0 | zvar = (NCZ_VAR_INFO_T*)var->format_var_info; |
1572 | | |
1573 | | /* Cannot convert to user-defined types. */ |
1574 | 0 | if (mem_nc_type >= NC_FIRSTUSERTYPEID) |
1575 | 0 | return THROW(NC_EINVAL); |
1576 | | |
1577 | | /* Check some stuff about the type and the file. If the file must |
1578 | | * be switched from define mode, it happens here. */ |
1579 | 0 | if ((retval = check_for_vara(&mem_nc_type, var, h5))) |
1580 | 0 | return THROW(retval); |
1581 | 0 | assert(!var->ndims || (startp && countp)); |
1582 | | |
1583 | | /* Convert from size_t and ptrdiff_t to size64_t */ |
1584 | | /* Also do sanity checks */ |
1585 | 0 | if(var->ndims == 0) { /* scalar */ |
1586 | 0 | start[0] = 0; |
1587 | 0 | count[0] = 1; |
1588 | 0 | stride[0] = 1; |
1589 | 0 | } else { |
1590 | 0 | for (i = 0; i < var->ndims; i++) |
1591 | 0 | { |
1592 | | /* Check for non-positive stride. */ |
1593 | 0 | if (stridep && stridep[i] <= 0) |
1594 | 0 | return NC_ESTRIDE; |
1595 | | |
1596 | 0 | start[i] = startp[i]; |
1597 | 0 | count[i] = countp ? countp[i] : var->dim[i]->len; |
1598 | 0 | stride[i] = stridep ? stridep[i] : 1; |
1599 | | |
1600 | | /* Check to see if any counts are zero. */ |
1601 | 0 | if (!count[i]) |
1602 | 0 | zero_count++; |
1603 | 0 | fdims[i] = var->dim[i]->len; |
1604 | 0 | } |
1605 | 0 | } |
1606 | | |
1607 | | #ifdef LOOK |
1608 | | /* Get file space of data. */ |
1609 | | if ((file_spaceid = H5Dget_space(ncz_var->hdf_datasetid)) < 0) |
1610 | | BAIL(NC_EHDFERR); |
1611 | | |
1612 | | /* Get the sizes of all the dims and put them in fdims. */ |
1613 | | if (H5Sget_simple_extent_dims(file_spaceid, fdims, fmaxdims) < 0) |
1614 | | BAIL(NC_EHDFERR); |
1615 | | #endif |
1616 | | |
1617 | | #ifdef LOGGING |
1618 | | log_dim_info(var, fdims, fmaxdims, start, count); |
1619 | | #endif |
1620 | | |
1621 | | /* Check dimension bounds. Remember that unlimited dimensions can |
1622 | | * put data beyond their current length. */ |
1623 | 0 | for (d2 = 0; d2 < var->ndims; d2++) |
1624 | 0 | { |
1625 | 0 | size64_t endindex = start[d2] + stride[d2] * (count[d2] - 1); /* last index written */ |
1626 | 0 | dim = var->dim[d2]; |
1627 | 0 | assert(dim && dim->hdr.id == var->dimids[d2]); |
1628 | 0 | if (count[d2] == 0) |
1629 | 0 | endindex = start[d2]; /* fixup for zero read count */ |
1630 | 0 | if (!dim->unlimited) |
1631 | 0 | { |
1632 | | /* Allow start to equal dim size if count is zero. */ |
1633 | 0 | if (start[d2] > fdims[d2] || |
1634 | 0 | (start[d2] == fdims[d2] && count[d2] > 0)) |
1635 | 0 | BAIL_QUIET(NC_EINVALCOORDS); |
1636 | 0 | if (!zero_count && endindex >= fdims[d2]) |
1637 | 0 | BAIL_QUIET(NC_EEDGE); |
1638 | 0 | } |
1639 | 0 | } |
1640 | | |
1641 | | #ifdef LOOK |
1642 | | /* Now you would think that no one would be crazy enough to write |
1643 | | a scalar dataspace with one of the array function calls, but you |
1644 | | would be wrong. So let's check to see if the dataset is |
1645 | | scalar. If it is, we won't try to set up a hyperslab. */ |
1646 | | if (H5Sget_simple_extent_type(file_spaceid) == H5S_SCALAR) |
1647 | | { |
1648 | | if ((mem_spaceid = H5Screate(H5S_SCALAR)) < 0) |
1649 | | BAIL(NC_EHDFERR); |
1650 | | } |
1651 | | else |
1652 | | { |
1653 | | if (H5Sselect_hyperslab(file_spaceid, H5S_SELECT_SET, start, stride, |
1654 | | count, NULL) < 0) |
1655 | | BAIL(NC_EHDFERR); |
1656 | | |
1657 | | /* Create a space for the memory, just big enough to hold the slab |
1658 | | we want. */ |
1659 | | if ((mem_spaceid = H5Screate_simple(var->ndims, count, NULL)) < 0) |
1660 | | BAIL(NC_EHDFERR); |
1661 | | } |
1662 | | #endif |
1663 | | |
1664 | | /* Are we going to convert any data? (No converting of compound or |
1665 | | * opaque or vlen types.) We also need to call this code if we are doing |
1666 | | * quantization. */ |
1667 | 0 | if ((mem_nc_type != var->type_info->hdr.id && |
1668 | 0 | mem_nc_type != NC_COMPOUND && mem_nc_type != NC_OPAQUE |
1669 | 0 | && mem_nc_type != NC_VLEN) |
1670 | 0 | || var->quantize_mode > 0) |
1671 | 0 | { |
1672 | 0 | size_t file_type_size; |
1673 | | |
1674 | | /* We must convert - allocate a buffer. */ |
1675 | 0 | need_to_convert++; |
1676 | 0 | if(zvar->scalar) |
1677 | 0 | len = 1; |
1678 | 0 | else for (d2=0; d2<var->ndims; d2++) |
1679 | 0 | len *= countp[d2]; |
1680 | |
|
1681 | 0 | LOG((4, "converting data for var %s type=%d len=%d", var->hdr.name, |
1682 | 0 | var->type_info->hdr.id, len)); |
1683 | | |
1684 | | /* Later on, we will need to know the size of this type in the |
1685 | | * file. */ |
1686 | 0 | assert(var->type_info->size); |
1687 | 0 | file_type_size = var->type_info->size; |
1688 | | |
1689 | | /* If we're reading, we need bufr to have enough memory to store |
1690 | | * the data in the file. If we're writing, we need bufr to be |
1691 | | * big enough to hold all the data in the file's type. */ |
1692 | 0 | if (len > 0) { |
1693 | 0 | assert(bufr == NULL); |
1694 | 0 | if (!(bufr = malloc(len * file_type_size))) |
1695 | 0 | BAIL(NC_ENOMEM); |
1696 | 0 | bufrd = 1; |
1697 | 0 | } |
1698 | 0 | } |
1699 | 0 | else |
1700 | 0 | bufr = (void *)data; |
1701 | | |
1702 | | #ifdef LOOK |
1703 | | /* Create the data transfer property list. */ |
1704 | | if ((xfer_plistid = H5Pcreate(H5P_DATASET_XFER)) < 0) |
1705 | | BAIL(NC_EHDFERR); |
1706 | | |
1707 | | #endif /*LOOK*/ |
1708 | | |
1709 | | /* Read this hyperslab from memory. Does the dataset have to be |
1710 | | extended? If it's already extended to the required size, it will |
1711 | | do no harm to reextend it to that size. */ |
1712 | 0 | if (var->ndims) |
1713 | 0 | { |
1714 | | #ifdef UNLIMITED |
1715 | | for (d2 = 0; d2 < var->ndims; d2++) |
1716 | | { |
1717 | | size64_t endindex = start[d2] + stride[d2] * (count[d2] - 1); /* last index written */ |
1718 | | if (count[d2] == 0) |
1719 | | endindex = start[d2]; |
1720 | | dim = var->dim[d2]; |
1721 | | assert(dim && dim->hdr.id == var->dimids[d2]); |
1722 | | if (dim->unlimited) |
1723 | | { |
1724 | | if (!zero_count && endindex >= fdims[d2]) |
1725 | | { |
1726 | | xtend_size[d2] = (long long unsigned)(endindex+1); |
1727 | | need_to_extend++; |
1728 | | } |
1729 | | else |
1730 | | xtend_size[d2] = (long long unsigned)fdims[d2]; |
1731 | | |
1732 | | if (!zero_count && endindex >= dim->len) |
1733 | | { |
1734 | | dim->len = endindex+1; |
1735 | | dim->extended = NC_TRUE; |
1736 | | } |
1737 | | } |
1738 | | else |
1739 | | { |
1740 | | xtend_size[d2] = (size64_t)dim->len; |
1741 | | } |
1742 | | } |
1743 | | #endif |
1744 | |
|
1745 | | #ifdef LOOK |
1746 | | /* If we need to extend it, we also need a new file_spaceid |
1747 | | to reflect the new size of the space. */ |
1748 | | if (need_to_extend) |
1749 | | { |
1750 | | LOG((4, "extending dataset")); |
1751 | | /* Convert xtend_size back to hsize_t for use with |
1752 | | * H5Dset_extent. */ |
1753 | | for (d2 = 0; d2 < var->ndims; d2++) |
1754 | | fdims[d2] = (size64_t)xtend_size[d2]; |
1755 | | if (H5Dset_extent(ncz_var->hdf_datasetid, fdims) < 0) |
1756 | | BAIL(NC_EHDFERR); |
1757 | | if (file_spaceid > 0 && H5Sclose(file_spaceid) < 0) |
1758 | | BAIL2(NC_EHDFERR); |
1759 | | if ((file_spaceid = H5Dget_space(ncz_var->hdf_datasetid)) < 0) |
1760 | | BAIL(NC_EHDFERR); |
1761 | | if (H5Sselect_hyperslab(file_spaceid, H5S_SELECT_SET, |
1762 | | start, stride, count, NULL) < 0) |
1763 | | BAIL(NC_EHDFERR); |
1764 | | } |
1765 | | #endif |
1766 | 0 | } |
1767 | | |
1768 | | /* Do we need to convert the data? */ |
1769 | 0 | if (need_to_convert) |
1770 | 0 | { |
1771 | 0 | if(var->quantize_mode < 0) {if((retval = NCZ_ensure_quantizer(ncid,var))) BAIL(retval);} |
1772 | 0 | assert(bufr != NULL); |
1773 | 0 | if ((retval = nc4_convert_type(data, bufr, mem_nc_type, var->type_info->hdr.id, |
1774 | 0 | len, &range_error, var->fill_value, |
1775 | 0 | (h5->cmode & NC_CLASSIC_MODEL), |
1776 | 0 | var->quantize_mode, var->nsd))) |
1777 | 0 | BAIL(retval); |
1778 | 0 | } |
1779 | | |
1780 | | #ifdef LOOK |
1781 | | /* Write the data. At last! */ |
1782 | | LOG((4, "about to write datasetid 0x%x mem_spaceid 0x%x " |
1783 | | "file_spaceid 0x%x", ncz_var->hdf_datasetid, mem_spaceid, file_spaceid)); |
1784 | | if (H5Dwrite(ncz_var->hdf_datasetid, |
1785 | | ((NCZ_TYPE_INFO_T *)var->type_info->format_type_info)->hdf_typeid, |
1786 | | mem_spaceid, file_spaceid, xfer_plistid, bufr) < 0) |
1787 | | BAIL(NC_EHDFERR); |
1788 | | #endif /*LOOK*/ |
1789 | | |
1790 | 0 | if((retval = NCZ_transferslice(var, WRITING, start, count, stride, bufr, var->type_info->hdr.id))) |
1791 | 0 | BAIL(retval); |
1792 | | |
1793 | | /* Remember that we have written to this var so that Fill Value |
1794 | | * can't be set for it. */ |
1795 | 0 | if (!var->written_to) |
1796 | 0 | var->written_to = NC_TRUE; |
1797 | | |
1798 | | /* For strict netcdf-3 rules, ignore erange errors between UBYTE |
1799 | | * and BYTE types. */ |
1800 | 0 | if ((h5->cmode & NC_CLASSIC_MODEL) && |
1801 | 0 | (var->type_info->hdr.id == NC_UBYTE || var->type_info->hdr.id == NC_BYTE) && |
1802 | 0 | (mem_nc_type == NC_UBYTE || mem_nc_type == NC_BYTE) && |
1803 | 0 | range_error) |
1804 | 0 | range_error = 0; |
1805 | |
|
1806 | 0 | exit: |
1807 | | #ifdef LOOK |
1808 | | if (file_spaceid > 0 && H5Sclose(file_spaceid) < 0) |
1809 | | BAIL2(NC_EHDFERR); |
1810 | | if (mem_spaceid > 0 && H5Sclose(mem_spaceid) < 0) |
1811 | | BAIL2(NC_EHDFERR); |
1812 | | if (xfer_plistid && (H5Pclose(xfer_plistid) < 0)) |
1813 | | BAIL2(NC_EPARINIT); |
1814 | | #endif |
1815 | 0 | if (bufrd && bufr) free(bufr); |
1816 | | |
1817 | | /* If there was an error return it, otherwise return any potential |
1818 | | range error value. If none, return NC_NOERR as usual.*/ |
1819 | 0 | if (retval) |
1820 | 0 | return THROW(retval); |
1821 | 0 | if (range_error) |
1822 | 0 | return NC_ERANGE; |
1823 | 0 | return NC_NOERR; |
1824 | 0 | } |
1825 | | |
1826 | | /** |
1827 | | * @internal Read a strided array of data from a variable. This is |
1828 | | * called by nc_get_vars() for netCDF-4 files, as well as all the |
1829 | | * other nc_get_vars_* functions. |
1830 | | * |
1831 | | * @param ncid File ID. |
1832 | | * @param varid Variable ID. |
1833 | | * @param startp Array of start indices. Must be provided for |
1834 | | * non-scalar vars. |
1835 | | * @param countp Array of counts. Will default to counts of extent of |
1836 | | * dimension if NULL. |
1837 | | * @param stridep Array of strides. Will default to strides of 1 if |
1838 | | * NULL. |
1839 | | * @param data The data to be written. |
1840 | | * @param mem_nc_type The type of the data in memory. (Convert to this |
1841 | | * type from file type.) |
1842 | | * |
1843 | | * @returns ::NC_NOERR No error. |
1844 | | * @returns ::NC_EBADID Bad ncid. |
1845 | | * @returns ::NC_ENOTVAR Var not found. |
1846 | | * @returns ::NC_EHDFERR ZARR function returned error. |
1847 | | * @returns ::NC_EINVALCOORDS Incorrect start. |
1848 | | * @returns ::NC_EEDGE Incorrect start/count. |
1849 | | * @returns ::NC_ENOMEM Out of memory. |
1850 | | * @returns ::NC_EMPI MPI library error (parallel only) |
1851 | | * @returns ::NC_ECANTEXTEND Can't extend dimension for write. |
1852 | | * @returns ::NC_ERANGE Data conversion error. |
1853 | | * @author Dennis Heimbigner, Ed Hartnett |
1854 | | */ |
1855 | | int |
1856 | | NCZ_get_vars(int ncid, int varid, const size_t *startp, const size_t *countp, |
1857 | | const ptrdiff_t *stridep, void *data, nc_type mem_nc_type) |
1858 | 0 | { |
1859 | 0 | NC_GRP_INFO_T *grp; |
1860 | 0 | NC_FILE_INFO_T *h5; |
1861 | 0 | NC_VAR_INFO_T *var; |
1862 | 0 | NC_DIM_INFO_T *dim; |
1863 | 0 | size_t file_type_size; |
1864 | 0 | size64_t count[NC_MAX_VAR_DIMS]; |
1865 | 0 | size64_t fdims[NC_MAX_VAR_DIMS]; |
1866 | 0 | size64_t fmaxdims[NC_MAX_VAR_DIMS]; |
1867 | 0 | size64_t start[NC_MAX_VAR_DIMS]; |
1868 | 0 | size64_t stride[NC_MAX_VAR_DIMS]; |
1869 | 0 | int no_read = 0, provide_fill = 0; |
1870 | 0 | int fill_value_size[NC_MAX_VAR_DIMS]; |
1871 | 0 | int retval, range_error = 0, i, d2; |
1872 | 0 | void *bufr = NULL; |
1873 | 0 | int need_to_convert = 0; |
1874 | 0 | size_t len = 1; |
1875 | 0 | NCZ_VAR_INFO_T* zvar = NULL; |
1876 | |
|
1877 | 0 | NC_UNUSED(fmaxdims); |
1878 | | |
1879 | | /* Find info for this file, group, and var. */ |
1880 | 0 | if ((retval = nc4_find_grp_h5_var(ncid, varid, &h5, &grp, &var))) |
1881 | 0 | return THROW(retval); |
1882 | 0 | assert(h5 && grp && var && var->hdr.id == varid && var->format_var_info && |
1883 | 0 | var->type_info && var->type_info->size && |
1884 | 0 | var->type_info->format_type_info); |
1885 | | |
1886 | 0 | LOG((3, "%s: var->hdr.name %s mem_nc_type %d", __func__, |
1887 | 0 | var->hdr.name, mem_nc_type)); |
1888 | |
|
1889 | 0 | zvar = (NCZ_VAR_INFO_T*)var->format_var_info; |
1890 | | |
1891 | | /* Check some stuff about the type and the file. Also end define |
1892 | | * mode, if needed. */ |
1893 | 0 | if ((retval = check_for_vara(&mem_nc_type, var, h5))) |
1894 | 0 | return THROW(retval); |
1895 | 0 | assert((!var->ndims || (startp && countp))); |
1896 | | |
1897 | | /* Convert from size_t and ptrdiff_t to size64_t. Also do sanity |
1898 | | * checks. */ |
1899 | 0 | if(var->ndims == 0) { /* scalar */ |
1900 | 0 | start[0] = 0; |
1901 | 0 | count[0] = 1; |
1902 | 0 | stride[0] = 1; |
1903 | 0 | } else { |
1904 | 0 | for (i = 0; i < var->ndims; i++) |
1905 | 0 | { |
1906 | | /* If any of the stride values are non-positive, fail. */ |
1907 | 0 | if (stridep && stridep[i] <= 0) |
1908 | 0 | return NC_ESTRIDE; |
1909 | 0 | start[i] = startp[i]; |
1910 | 0 | count[i] = countp[i]; |
1911 | 0 | stride[i] = stridep ? stridep[i] : 1; |
1912 | | /* if any of the count values are zero don't actually read. */ |
1913 | 0 | if (count[i] == 0) |
1914 | 0 | no_read++; |
1915 | | /* Get dimension sizes also */ |
1916 | 0 | fdims[i] = var->dim[i]->len; |
1917 | 0 | fmaxdims[i] = fdims[i]; |
1918 | 0 | } |
1919 | 0 | } |
1920 | | |
1921 | | #ifdef LOOK |
1922 | | /* Get file space of data. */ |
1923 | | if ((file_spaceid = H5Dget_space(ncz_var->hdf_datasetid)) < 0) |
1924 | | BAIL(NC_EHDFERR); |
1925 | | |
1926 | | /* Check to ensure the user selection is |
1927 | | * valid. H5Sget_simple_extent_dims gets the sizes of all the dims |
1928 | | * and put them in fdims. */ |
1929 | | if (H5Sget_simple_extent_dims(file_spaceid, fdims, fmaxdims) < 0) |
1930 | | BAIL(NC_EHDFERR); |
1931 | | #endif |
1932 | | |
1933 | | #ifdef LOGGING |
1934 | | log_dim_info(var, fdims, fmaxdims, start, count); |
1935 | | #endif |
1936 | | |
1937 | | /* Check the type_info fields. */ |
1938 | 0 | assert(var->type_info && var->type_info->size && |
1939 | 0 | var->type_info->format_type_info); |
1940 | | |
1941 | | /* Later on, we will need to know the size of this type in the |
1942 | | * file. */ |
1943 | 0 | file_type_size = var->type_info->size; |
1944 | | |
1945 | | /* Are we going to convert any data? (No converting of compound or |
1946 | | * opaque types.) */ |
1947 | 0 | if (mem_nc_type != var->type_info->hdr.id && |
1948 | 0 | mem_nc_type != NC_COMPOUND && mem_nc_type != NC_OPAQUE) |
1949 | 0 | { |
1950 | | /* We must convert - allocate a buffer. */ |
1951 | 0 | need_to_convert++; |
1952 | 0 | if(zvar->scalar) { |
1953 | 0 | len *= countp[0]; |
1954 | 0 | } else { |
1955 | 0 | for (d2 = 0; d2 < (var->ndims); d2++) |
1956 | 0 | len *= countp[d2]; |
1957 | 0 | } |
1958 | 0 | LOG((4, "converting data for var %s type=%d len=%d", var->hdr.name, |
1959 | 0 | var->type_info->hdr.id, len)); |
1960 | | |
1961 | | /* If we're reading, we need bufr to have enough memory to store |
1962 | | * the data in the file. If we're writing, we need bufr to be |
1963 | | * big enough to hold all the data in the file's type. */ |
1964 | 0 | if (len > 0) |
1965 | 0 | if (!(bufr = malloc(len * file_type_size))) |
1966 | 0 | BAIL(NC_ENOMEM); |
1967 | 0 | } |
1968 | 0 | else |
1969 | 0 | if (!bufr) |
1970 | 0 | bufr = data; |
1971 | | |
1972 | | /* Check dimension bounds. Remember that unlimited dimensions can |
1973 | | * put data beyond their current length. */ |
1974 | 0 | for (d2 = 0; d2 < var->ndims; d2++) |
1975 | 0 | { |
1976 | 0 | size64_t endindex = start[d2] + stride[d2] * (count[d2] - 1); /* last index read */ |
1977 | 0 | dim = var->dim[d2]; |
1978 | 0 | assert(dim && dim->hdr.id == var->dimids[d2]); |
1979 | 0 | if (count[d2] == 0) |
1980 | 0 | endindex = start[d2]; /* fixup for zero read count */ |
1981 | 0 | if (dim->unlimited) |
1982 | 0 | { |
1983 | 0 | size_t ulen; |
1984 | | |
1985 | | /* We can't go beyond the largest current extent of |
1986 | | the unlimited dim. */ |
1987 | 0 | if ((retval = NCZ_inq_dim(ncid, dim->hdr.id, NULL, &ulen))) |
1988 | 0 | BAIL(retval); |
1989 | | |
1990 | | /* Check for out of bound requests. */ |
1991 | | /* Allow start to equal dim size if count is zero. */ |
1992 | 0 | if (start[d2] > (size64_t)ulen || |
1993 | 0 | (start[d2] == (size64_t)ulen && count[d2] > 0)) |
1994 | 0 | BAIL_QUIET(NC_EINVALCOORDS); |
1995 | 0 | if (count[d2] && endindex >= ulen) |
1996 | 0 | BAIL_QUIET(NC_EEDGE); |
1997 | | |
1998 | | /* Things get a little tricky here. If we're getting a GET |
1999 | | request beyond the end of this var's current length in |
2000 | | an unlimited dimension, we'll later need to return the |
2001 | | fill value for the variable. */ |
2002 | 0 | if (!no_read) |
2003 | 0 | { |
2004 | 0 | if (start[d2] >= (size64_t)fdims[d2]) |
2005 | 0 | fill_value_size[d2] = count[d2]; |
2006 | 0 | else if (endindex >= fdims[d2]) |
2007 | 0 | fill_value_size[d2] = count[d2] - ((fdims[d2] - start[d2])/stride[d2]); |
2008 | 0 | else |
2009 | 0 | fill_value_size[d2] = 0; |
2010 | 0 | count[d2] -= fill_value_size[d2]; |
2011 | 0 | if (count[d2] == 0) |
2012 | 0 | no_read++; |
2013 | 0 | if (fill_value_size[d2]) |
2014 | 0 | provide_fill++; |
2015 | 0 | } |
2016 | 0 | else |
2017 | 0 | fill_value_size[d2] = count[d2]; |
2018 | 0 | } |
2019 | 0 | else /* Dim is not unlimited. */ |
2020 | 0 | { |
2021 | | /* Check for out of bound requests. */ |
2022 | | /* Allow start to equal dim size if count is zero. */ |
2023 | 0 | if (start[d2] > (size64_t)fdims[d2] || |
2024 | 0 | (start[d2] == (size64_t)fdims[d2] && count[d2] > 0)) |
2025 | 0 | BAIL_QUIET(NC_EINVALCOORDS); |
2026 | 0 | if (count[d2] && endindex >= fdims[d2]) |
2027 | 0 | BAIL_QUIET(NC_EEDGE); |
2028 | | /* Set the fill value boundary */ |
2029 | 0 | fill_value_size[d2] = count[d2]; |
2030 | 0 | } |
2031 | 0 | } |
2032 | | |
2033 | 0 | if (!no_read) |
2034 | 0 | { |
2035 | | #ifdef LOOK |
2036 | | /* Now you would think that no one would be crazy enough to write |
2037 | | a scalar dataspace with one of the array function calls, but you |
2038 | | would be wrong. So let's check to see if the dataset is |
2039 | | scalar. If it is, we won't try to set up a hyperslab. */ |
2040 | | if (H5Sget_simple_extent_type(file_spaceid) == H5S_SCALAR) |
2041 | | { |
2042 | | if ((mem_spaceid = H5Screate(H5S_SCALAR)) < 0) |
2043 | | BAIL(NC_EHDFERR); |
2044 | | scalar++; |
2045 | | } |
2046 | | else |
2047 | | { |
2048 | | if (H5Sselect_hyperslab(file_spaceid, H5S_SELECT_SET, |
2049 | | start, stride, count, NULL) < 0) |
2050 | | BAIL(NC_EHDFERR); |
2051 | | /* Create a space for the memory, just big enough to hold the slab |
2052 | | we want. */ |
2053 | | if ((mem_spaceid = H5Screate_simple(var->ndims, count, NULL)) < 0) |
2054 | | BAIL(NC_EHDFERR); |
2055 | | } |
2056 | | #endif |
2057 | |
|
2058 | | #ifdef LOOK |
2059 | | /* Fix bug when reading ZARR files with variable of type |
2060 | | * fixed-length string. We need to make it look like a |
2061 | | * variable-length string, because that's all netCDF-4 data |
2062 | | * model supports, lacking anonymous dimensions. So |
2063 | | * variable-length strings are in allocated memory that user has |
2064 | | * to free, which we allocate here. */ |
2065 | | if (var->type_info->nc_type_class == NC_STRING && |
2066 | | H5Tget_size(ncz_type->hdf_typeid) > 1 && |
2067 | | !H5Tis_variable_str(ncz_type->hdf_typeid)) |
2068 | | { |
2069 | | size64_t fstring_len; |
2070 | | |
2071 | | if ((fstring_len = H5Tget_size(ncz_type->hdf_typeid)) == 0) |
2072 | | BAIL(NC_EHDFERR); |
2073 | | if (!(*(char **)data = malloc(1 + fstring_len))) |
2074 | | BAIL(NC_ENOMEM); |
2075 | | bufr = *(char **)data; |
2076 | | } |
2077 | | #endif |
2078 | |
|
2079 | | #ifdef LOOK |
2080 | | /* Create the data transfer property list. */ |
2081 | | if ((xfer_plistid = H5Pcreate(H5P_DATASET_XFER)) < 0) |
2082 | | BAIL(NC_EHDFERR); |
2083 | | |
2084 | | /* Read this hyperslab into memory. */ |
2085 | | LOG((5, "About to H5Dread some data...")); |
2086 | | if (H5Dread(ncz_var->hdf_datasetid, |
2087 | | ((NCZ_TYPE_INFO_T *)var->type_info->format_type_info)->native_hdf_typeid, |
2088 | | mem_spaceid, file_spaceid, xfer_plistid, bufr) < 0) |
2089 | | BAIL(NC_EHDFERR); |
2090 | | #endif /*LOOK*/ |
2091 | |
|
2092 | 0 | if((retval = NCZ_transferslice(var, READING, start, count, stride, bufr, var->type_info->hdr.id))) |
2093 | 0 | BAIL(retval); |
2094 | 0 | } /* endif ! no_read */ |
2095 | | |
2096 | | /* Now we need to fake up any further data that was asked for, |
2097 | | using the fill values instead. First skip past the data we |
2098 | | just read, if any. */ |
2099 | 0 | if (!zvar->scalar && provide_fill) |
2100 | 0 | { |
2101 | 0 | void *filldata; |
2102 | 0 | size_t real_data_size = 0; |
2103 | 0 | size_t fill_len; |
2104 | | |
2105 | | /* Skip past the real data we've already read. */ |
2106 | 0 | if (!no_read) |
2107 | 0 | for (real_data_size = file_type_size, d2 = 0; d2 < var->ndims; d2++) |
2108 | 0 | real_data_size *= count[d2]; |
2109 | | |
2110 | | /* Get the fill value from the ZARR variable. Memory will be |
2111 | | * allocated. */ |
2112 | 0 | if (NCZ_ensure_fill_value(var)) |
2113 | 0 | BAIL(NC_EINVAL); |
2114 | | |
2115 | | /* How many fill values do we need? */ |
2116 | 0 | for (fill_len = 1, d2 = 0; d2 < var->ndims; d2++) |
2117 | 0 | fill_len *= (fill_value_size[d2] ? fill_value_size[d2] : 1); |
2118 | | |
2119 | | /* Copy the fill value into the rest of the data buffer. */ |
2120 | 0 | filldata = (char *)data + real_data_size; |
2121 | 0 | for (i = 0; i < fill_len; i++) |
2122 | 0 | { |
2123 | | /* Copy one instance of the fill_value */ |
2124 | 0 | if((retval = nc_copy_data(ncid,var->type_info->hdr.id,var->fill_value,1,filldata))) |
2125 | 0 | BAIL(retval); |
2126 | 0 | filldata = (char *)filldata + file_type_size; |
2127 | 0 | } |
2128 | 0 | } |
2129 | | |
2130 | | /* Convert data type if needed. */ |
2131 | 0 | if (need_to_convert) |
2132 | 0 | { |
2133 | 0 | if(var->quantize_mode < 0) {if((retval = NCZ_ensure_quantizer(ncid,var))) BAIL(retval);} |
2134 | 0 | if ((retval = nc4_convert_type(bufr, data, var->type_info->hdr.id, mem_nc_type, |
2135 | 0 | len, &range_error, var->fill_value, |
2136 | 0 | (h5->cmode & NC_CLASSIC_MODEL), var->quantize_mode, |
2137 | 0 | var->nsd))) |
2138 | 0 | BAIL(retval); |
2139 | | /* For strict netcdf-3 rules, ignore erange errors between UBYTE |
2140 | | * and BYTE types. */ |
2141 | 0 | if ((h5->cmode & NC_CLASSIC_MODEL) && |
2142 | 0 | (var->type_info->hdr.id == NC_UBYTE || var->type_info->hdr.id == NC_BYTE) && |
2143 | 0 | (mem_nc_type == NC_UBYTE || mem_nc_type == NC_BYTE) && |
2144 | 0 | range_error) |
2145 | 0 | range_error = 0; |
2146 | 0 | } |
2147 | | |
2148 | 0 | exit: |
2149 | | #ifdef LOOK |
2150 | | if (file_spaceid > 0) |
2151 | | if (H5Sclose(file_spaceid) < 0) |
2152 | | BAIL2(NC_EHDFERR); |
2153 | | if (mem_spaceid > 0) |
2154 | | if (H5Sclose(mem_spaceid) < 0) |
2155 | | BAIL2(NC_EHDFERR); |
2156 | | if (xfer_plistid > 0) |
2157 | | if (H5Pclose(xfer_plistid) < 0) |
2158 | | |
2159 | | BAIL2(NC_EHDFERR); |
2160 | | #endif |
2161 | 0 | if (need_to_convert && bufr) |
2162 | 0 | free(bufr); |
2163 | | /* If there was an error return it, otherwise return any potential |
2164 | | range error value. If none, return NC_NOERR as usual.*/ |
2165 | 0 | if (retval) |
2166 | 0 | return THROW(retval); |
2167 | 0 | if (range_error) |
2168 | 0 | return THROW(NC_ERANGE); |
2169 | 0 | return NC_NOERR; |
2170 | 0 | } |
2171 | | |
2172 | | /** |
2173 | | * @internal Get all the information about a variable. Pass NULL for |
2174 | | * whatever you don't care about. |
2175 | | * |
2176 | | * @param ncid File ID. |
2177 | | * @param varid Variable ID. |
2178 | | * @param name Gets name. |
2179 | | * @param xtypep Gets type. |
2180 | | * @param ndimsp Gets number of dims. |
2181 | | * @param dimidsp Gets array of dim IDs. |
2182 | | * @param nattsp Gets number of attributes. |
2183 | | * @param shufflep Gets shuffle setting. |
2184 | | * @param deflatep Gets deflate setting. |
2185 | | * @param deflate_levelp Gets deflate level. |
2186 | | * @param fletcher32p Gets fletcher32 setting. |
2187 | | * @param contiguousp Gets contiguous setting. |
2188 | | * @param chunksizesp Gets chunksizes. |
2189 | | * @param no_fill Gets fill mode. |
2190 | | * @param fill_valuep Gets fill value. |
2191 | | * @param endiannessp Gets one of ::NC_ENDIAN_BIG ::NC_ENDIAN_LITTLE |
2192 | | * @param idp Pointer to memory to store filter id. |
2193 | | * @param nparamsp Pointer to memory to store filter parameter count. |
2194 | | * @param params Pointer to vector of unsigned integers into which |
2195 | | * to store filter parameters. |
2196 | | * |
2197 | | * @returns ::NC_NOERR No error. |
2198 | | * @returns ::NC_EBADID Bad ncid. |
2199 | | * @returns ::NC_ENOTVAR Bad varid. |
2200 | | * @returns ::NC_ENOMEM Out of memory. |
2201 | | * @returns ::NC_EINVAL Invalid input. |
2202 | | * @author Dennis Heimbigner, Ed Hartnett |
2203 | | */ |
2204 | | int |
2205 | | NCZ_inq_var_all(int ncid, int varid, char *name, nc_type *xtypep, |
2206 | | int *ndimsp, int *dimidsp, int *nattsp, |
2207 | | int *shufflep, int *unused4, int *unused5, |
2208 | | int *fletcher32p, int *storagep, size_t *chunksizesp, |
2209 | | int *no_fill, void *fill_valuep, int *endiannessp, |
2210 | | unsigned int *unused1, size_t *unused2, unsigned int *unused3) |
2211 | 0 | { |
2212 | 0 | NC_FILE_INFO_T *h5; |
2213 | 0 | NC_GRP_INFO_T *grp; |
2214 | 0 | NC_VAR_INFO_T *var = NULL; |
2215 | 0 | int retval; |
2216 | |
|
2217 | 0 | ZTRACE(1,"ncid=%d varid=%d",ncid,varid); |
2218 | |
|
2219 | 0 | LOG((2, "%s: ncid 0x%x varid %d", __func__, ncid, varid)); |
2220 | | |
2221 | | /* Find the file, group, and var info, and do lazy att read if |
2222 | | * needed. */ |
2223 | 0 | if ((retval = ncz_find_grp_var_att(ncid, varid, NULL, 0, 0, NULL, |
2224 | 0 | &h5, &grp, &var, NULL))) |
2225 | 0 | goto done; |
2226 | 0 | assert(grp && h5); |
2227 | | |
2228 | | /* Short-circuit the filter-related inquiries */ |
2229 | 0 | if(shufflep) { |
2230 | 0 | *shufflep = 0; |
2231 | 0 | if((retval = NCZ_inq_var_filter_info(ncid,varid,2,NULL,NULL))==NC_NOERR) |
2232 | 0 | *shufflep = 1; |
2233 | 0 | } |
2234 | 0 | if(fletcher32p) { |
2235 | 0 | *fletcher32p = 0; |
2236 | 0 | if((retval = NCZ_inq_var_filter_info(ncid,varid,3,NULL,NULL))==NC_NOERR) |
2237 | 0 | *fletcher32p = 1; |
2238 | 0 | } |
2239 | | |
2240 | | /* Now that lazy atts have been read, use the libsrc4 function to |
2241 | | * get the answers. */ |
2242 | 0 | retval = NC4_inq_var_all(ncid, varid, name, xtypep, ndimsp, dimidsp, nattsp, |
2243 | 0 | NULL, unused4, unused5, NULL, |
2244 | 0 | storagep, chunksizesp, no_fill, fill_valuep, |
2245 | 0 | endiannessp, unused1, unused2, unused3); |
2246 | 0 | done: |
2247 | 0 | return ZUNTRACEX(retval,"xtype=%d natts=%d shuffle=%d fletcher32=%d no_fill=%d endianness=%d ndims=%d dimids=%s storage=%d chunksizes=%s", |
2248 | 0 | (xtypep?*xtypep:-1), |
2249 | 0 | (nattsp?*nattsp:-1), |
2250 | 0 | (shufflep?*shufflep:-1), |
2251 | 0 | (fletcher32p?*fletcher32p:-1), |
2252 | 0 | (no_fill?*no_fill:-1), |
2253 | 0 | (endiannessp?*endiannessp:-1), |
2254 | 0 | (ndimsp?*ndimsp:-1), |
2255 | 0 | (dimidsp?nczprint_idvector(var->ndims,dimidsp):"null"), |
2256 | 0 | (storagep?*storagep:-1), |
2257 | 0 | (chunksizesp?nczprint_sizevector(var->ndims,chunksizesp):"null")); |
2258 | 0 | } |
2259 | | |
2260 | | #ifdef LOOK |
2261 | | /** |
2262 | | * @internal A wrapper for NCZ_set_var_chunk_cache(), we need this |
2263 | | * version for fortran. Negative values leave settings as they are. |
2264 | | * |
2265 | | * @param ncid File ID. |
2266 | | * @param varid Variable ID. |
2267 | | * @param size Size in bytes to set cache. |
2268 | | * @param nelems Number of elements in cache. |
2269 | | * @param preemption Controls cache swapping. |
2270 | | * |
2271 | | * @returns ::NC_NOERR for success |
2272 | | * @author Dennis Heimbigner, Ed Hartnett |
2273 | | */ |
2274 | | int |
2275 | | ncz_set_var_chunk_cache_ints(int ncid, int varid, int size, int nelems, |
2276 | | int preemption) |
2277 | | { |
2278 | | size_t real_size = H5D_CHUNK_CACHE_NBYTES_DEFAULT; |
2279 | | size_t real_nelems = H5D_CHUNK_CACHE_NSLOTS_DEFAULT; |
2280 | | float real_preemption = CHUNK_CACHE_PREEMPTION; |
2281 | | |
2282 | | if (size >= 0) |
2283 | | real_size = ((size_t) size) * MEGABYTE; |
2284 | | |
2285 | | if (nelems >= 0) |
2286 | | real_nelems = nelems; |
2287 | | |
2288 | | if (preemption >= 0) |
2289 | | real_preemption = preemption / 100.; |
2290 | | |
2291 | | return NCZ_set_var_chunk_cache(ncid, varid, real_size, real_nelems, |
2292 | | real_preemption); |
2293 | | } |
2294 | | #endif |
2295 | | |
2296 | | int |
2297 | | ncz_gettype(NC_FILE_INFO_T* h5, NC_GRP_INFO_T* container, int xtype, NC_TYPE_INFO_T** typep) |
2298 | 0 | { |
2299 | 0 | int retval = NC_NOERR; |
2300 | 0 | NC_TYPE_INFO_T* type = NULL; |
2301 | 0 | NCZ_TYPE_INFO_T* ztype = NULL; |
2302 | | |
2303 | | /* If this is a user-defined type, there is a type struct with |
2304 | | * all the type information. For atomic types, fake up a type |
2305 | | * struct. */ |
2306 | 0 | if (xtype <= NC_STRING) |
2307 | 0 | { |
2308 | 0 | size_t len; |
2309 | 0 | char name[NC_MAX_NAME]; |
2310 | | |
2311 | | /* Get type name and length. */ |
2312 | 0 | if((retval = NC4_inq_atomic_type(xtype,name,&len))) |
2313 | 0 | BAIL(retval); |
2314 | | |
2315 | | /* Create new NC_TYPE_INFO_T struct for this atomic type. */ |
2316 | 0 | if ((retval = nc4_type_new(len, name, xtype, &type))) |
2317 | 0 | BAIL(retval); |
2318 | 0 | assert(type->rc == 0); |
2319 | 0 | type->container = container; |
2320 | 0 | type->endianness = (NC_isLittleEndian()?NC_ENDIAN_LITTLE:NC_ENDIAN_BIG); |
2321 | 0 | type->size = len; |
2322 | | |
2323 | | /* Allocate storage for NCZ-specific type info. */ |
2324 | 0 | if (!(ztype = calloc(1, sizeof(NCZ_TYPE_INFO_T)))) |
2325 | 0 | return NC_ENOMEM; |
2326 | 0 | type->format_type_info = ztype; |
2327 | 0 | ztype->common.file = h5; |
2328 | 0 | ztype = NULL; |
2329 | | |
2330 | | /* Set the "class" of the type */ |
2331 | 0 | if (xtype == NC_CHAR) |
2332 | 0 | type->nc_type_class = NC_CHAR; |
2333 | 0 | else |
2334 | 0 | { |
2335 | 0 | if(xtype == NC_FLOAT || xtype == NC_DOUBLE) |
2336 | 0 | type->nc_type_class = NC_FLOAT; |
2337 | 0 | else if(xtype < NC_STRING) |
2338 | 0 | type->nc_type_class = NC_INT; |
2339 | 0 | else |
2340 | 0 | type->nc_type_class = NC_STRING; |
2341 | 0 | } |
2342 | 0 | } |
2343 | 0 | else |
2344 | 0 | { |
2345 | | #ifdef LOOK |
2346 | | /* If this is a user defined type, find it. */ |
2347 | | if (nc4_find_type(grp->nc4_info, xtype, &type)) |
2348 | | #endif |
2349 | 0 | BAIL(NC_EBADTYPE); |
2350 | 0 | } |
2351 | | |
2352 | | /* increment its ref. count */ |
2353 | 0 | type->rc++; |
2354 | |
|
2355 | 0 | if(typep) {*typep = type; type = NULL;} |
2356 | 0 | return THROW(NC_NOERR); |
2357 | | |
2358 | 0 | exit: |
2359 | 0 | if (type) |
2360 | 0 | retval = nc4_type_free(type); |
2361 | 0 | nullfree(ztype); |
2362 | 0 | return THROW(retval); |
2363 | 0 | } |