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