Coverage Report

Created: 2023-05-28 06:42

/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
}