1/*
2  This file is part of netcdf-4, a netCDF-like interface for HDF5, or a
3  HDF5 backend for netCDF, depending on your point of view.
4
5  This file contains functions internal to the netcdf4 library. None of
6  the functions in this file are exposed in the exetnal API. These
7  functions handle the HDF interface.
8
9  Copyright 2003, University Corporation for Atmospheric
10  Research. See the COPYRIGHT file for copying and redistribution
11  conditions.
12
13  $Id: nc4hdf.c,v 1.273 2010/05/27 21:34:14 dmh Exp $
14*/
15
16#include "config.h"
17#include "nc4internal.h"
18#include "nc4dispatch.h"
19#include <H5DSpublic.h>
20#include <math.h>
21
22#ifdef USE_PARALLEL
23#include "netcdf_par.h"
24#endif
25
26#define NC3_STRICT_ATT_NAME "_nc3_strict"
27
28#define NC_HDF5_MAX_NAME 1024
29
30/* This is to track opened HDF5 objects to make sure they are
31 * closed. */
32#ifdef EXTRA_TESTS
33int num_plists;
34int num_spaces;
35#endif /* EXTRA_TESTS */
36
37/*! Flag attributes in a linked list as dirty.
38 *
39 * Given a linked list of attributes, flag each
40 * dirty.
41 *
42 * @param[in] attlist List of attributes, may be NULL.
43 * @return Returns NC_NOERR on succes, error on failure.
44 */
45static int flag_atts_dirty(NC_ATT_INFO_T **attlist) {
46
47  NC_ATT_INFO_T *att = NULL;
48
49  if(attlist == NULL) {
50    return NC_NOERR;
51  }
52
53  for(att = *attlistattatt = att->l.next) {
54    att->dirty = NC_TRUE;
55  }
56
57  return NC_NOERR;
58
59}
60
61/* This function is needed to handle one special case: what if the
62 * user defines a dim, writes metadata, then goes back into define
63 * mode and adds a coordinate var for the already existing dim. In
64 * that case, I need to recreate the dim's dimension scale dataset,
65 * and then I need to go to every var in the file which uses that
66 * dimension, and attach the new dimension scale. */
67int
68rec_reattach_scales(NC_GRP_INFO_T *grp, int dimidhid_t dimscaleid)
69{
70  NC_VAR_INFO_T *var;
71  NC_GRP_INFO_T *child_grp;
72  int d;
73  int retval;
74
75  assert(grp && grp->name && dimid >= 0 && dimscaleid >= 0);
76  LOG((3, "%s: grp->name %s", __func__grp->name));
77
78  /* If there are any child groups, attach dimscale there, if needed. */
79  for (child_grp = grp->childrenchild_grpchild_grp = child_grp->l.next)
80    if ((retval = rec_reattach_scales(child_grpdimiddimscaleid)))
81      return retval;
82
83  /* Find any vars that use this dimension id. */
84  for (var = grp->varvarvar = var->l.next)
85    for (d = 0; d < var->ndimsd++)
86      if (var->dimids[d] == dimid && !var->dimscale)
87        {
88          LOG((2, "%s: attaching scale for dimid %d to var %s",
89               __func__var->dimids[d], var->name));
90          if (var->created)
91            {
92              if (H5DSattach_scale(var->hdf_datasetiddimscaleidd) < 0)
93                return NC_EHDFERR;
94              var->dimscale_attached[d] = NC_TRUE;
95            }
96        }
97
98  return NC_NOERR;
99}
100
101/* This function is needed to handle one special case: what if the
102 * user defines a dim, writes metadata, then goes back into define
103 * mode and adds a coordinate var for the already existing dim. In
104 * that case, I need to recreate the dim's dimension scale dataset,
105 * and then I need to go to every var in the file which uses that
106 * dimension, and attach the new dimension scale. */
107int
108rec_detach_scales(NC_GRP_INFO_T *grp, int dimidhid_t dimscaleid)
109{
110  NC_VAR_INFO_T *var;
111  NC_GRP_INFO_T *child_grp;
112  int d;
113  int retval;
114
115  assert(grp && grp->name && dimid >= 0 && dimscaleid >= 0);
116  LOG((3, "%s: grp->name %s", __func__grp->name));
117
118  /* If there are any child groups, detach dimscale there, if needed. */
119  for (child_grp = grp->childrenchild_grpchild_grp = child_grp->l.next)
120    if ((retval = rec_detach_scales(child_grpdimiddimscaleid)))
121      return retval;
122
123  /* Find any vars that use this dimension id. */
124  for (var = grp->varvarvar = var->l.next)
125    for (d = 0; d < var->ndimsd++)
126      if (var->dimids[d] == dimid && !var->dimscale)
127        {
128          LOG((2, "%s: detaching scale for dimid %d to var %s",
129               __func__var->dimids[d], var->name));
130          if (var->created)
131            if (var->dimscale_attached && var->dimscale_attached[d])
132              {
133                if (H5DSdetach_scale(var->hdf_datasetiddimscaleidd) < 0)
134                  return NC_EHDFERR;
135                var->dimscale_attached[d] = NC_FALSE;
136              }
137        }
138
139  return NC_NOERR;
140}
141
142/* Open the dataset and leave it open. */
143int
144nc4_open_var_grp2(NC_GRP_INFO_T *grp, int varidhid_t *dataset)
145{
146  NC_VAR_INFO_T *var;
147
148  /* Find the requested varid. */
149  for (var = grp->varvarvar = var->l.next)
150    if (var->varid == varid)
151      break;
152  if (!var)
153    return NC_ENOTVAR;
154
155  /* Open this dataset if necessary. */
156  if (!var->hdf_datasetid)
157    if ((var->hdf_datasetid = H5Dopen2(grp->hdf_grpidvar->name,
158                                       H5P_DEFAULT)) < 0)
159      return NC_ENOTVAR;
160
161  *dataset = var->hdf_datasetid;
162
163  return NC_NOERR;
164}
165
166/* Get the default fill value for an atomic type. Memory for
167 * fill_value must already be allocated, or you are DOOMED!!!*/
168int
169nc4_get_default_fill_value(const NC_TYPE_INFO_T *type_info, void *fill_value)
170{
171  switch (type_info->nc_typeid)
172    {
173    case NC_CHAR:
174      *(char *)fill_value = NC_FILL_CHAR;
175      break;
176
177    case NC_STRING:
178      *(char **)fill_value = strdup(NC_FILL_STRING);
179      break;
180
181    case NC_BYTE:
182      *(signed char *)fill_value = NC_FILL_BYTE;
183      break;
184
185    case NC_SHORT:
186      *(short *)fill_value = NC_FILL_SHORT;
187      break;
188
189    case NC_INT:
190      *(int *)fill_value = NC_FILL_INT;
191      break;
192
193    case NC_UBYTE:
194      *(unsigned char *)fill_value = NC_FILL_UBYTE;
195      break;
196
197    case NC_USHORT:
198      *(unsigned short *)fill_value = NC_FILL_USHORT;
199      break;
200
201    case NC_UINT:
202      *(unsigned int *)fill_value = NC_FILL_UINT;
203      break;
204
205    case NC_INT64:
206      *(long long *)fill_value = NC_FILL_INT64;
207      break;
208
209    case NC_UINT64:
210      *(unsigned long long *)fill_value = NC_FILL_UINT64;
211      break;
212
213    case NC_FLOAT:
214      *(float *)fill_value = NC_FILL_FLOAT;
215      break;
216
217    case NC_DOUBLE:
218      *(double *)fill_value = NC_FILL_DOUBLE;
219      break;
220
221    default:
222      return NC_EINVAL;
223    }
224
225  return NC_NOERR;
226}
227
228/* What fill value should be used for a variable? */
229static int
230get_fill_value(NC_HDF5_FILE_INFO_T *h5NC_VAR_INFO_T *var, void **fillp)
231{
232  size_t size;
233  int retval;
234
235  /* Find out how much space we need for this type's fill value. */
236  if (var->type_info->nc_type_class == NC_VLEN)
237    size = sizeof(nc_vlen_t);
238  else if (var->type_info->nc_type_class == NC_STRING)
239    size = sizeof(char *);
240  else
241    {
242      if ((retval = nc4_get_typelen_mem(h5var->type_info->nc_typeid, 0, &size)))
243        return retval;
244    }
245  assert(size);
246
247  /* Allocate the space. */
248  if (!((*fillp) = calloc(1, size)))
249    return NC_ENOMEM;
250
251  /* If the user has set a fill_value for this var, use, otherwise
252   * find the default fill value. */
253  if (var->fill_value)
254    {
255      LOG((4, "Found a fill value for var %s", var->name));
256      if (var->type_info->nc_type_class == NC_VLEN)
257        {
258          nc_vlen_t *in_vlen = (nc_vlen_t *)(var->fill_value), *fv_vlen = (nc_vlen_t *)(*fillp);
259
260          fv_vlen->len = in_vlen->len;
261          if (!(fv_vlen->p = malloc(size * in_vlen->len)))
262            {
263              free(*fillp);
264              *fillp = NULL;
265              return NC_ENOMEM;
266            }
267          memcpy(fv_vlen->pin_vlen->pin_vlen->len * size);
268        }
269      else if (var->type_info->nc_type_class == NC_STRING)
270        {
271          if (*(char **)var->fill_value)
272            if (!(**(char ***)fillp = strdup(*(char **)var->fill_value)))
273              {
274                free(*fillp);
275                *fillp = NULL;
276                return NC_ENOMEM;
277              }
278        }
279      else
280        memcpy((*fillp), var->fill_valuesize);
281    }
282  else
283    {
284      if (nc4_get_default_fill_value(var->type_info, *fillp))
285        {
286          /* Note: release memory, but don't return error on failure */
287          free(*fillp);
288          *fillp = NULL;
289        }
290    }
291
292  return NC_NOERR;
293}
294
295/* Given a netcdf type, return appropriate HDF typeid. */
296/* (All hdf_typeid's returned from this routine must be H5Tclosed by the caller) */
297int
298nc4_get_hdf_typeid(NC_HDF5_FILE_INFO_T *h5nc_type xtype,
299                   hid_t *hdf_typeid, int endianness)
300{
301  NC_TYPE_INFO_T *type;
302  hid_t typeid = 0;
303  int retval = NC_NOERR;
304
305  assert(hdf_typeid && h5);
306
307  *hdf_typeid = -1;
308
309  /* Determine an appropriate HDF5 datatype */
310  if (xtype == NC_NAT)
311    /* NAT = 'Not A Type' (c.f. NaN) */
312    return NC_EBADTYPE;
313  else if (xtype == NC_CHAR || xtype == NC_STRING)
314    {
315      /* NC_CHAR & NC_STRING types create a new HDF5 datatype */
316      if (xtype == NC_CHAR)
317        {
318          if ((typeid = H5Tcopy(H5T_C_S1)) < 0)
319            return NC_EHDFERR;
320          if (H5Tset_strpad(typeidH5T_STR_NULLTERM) < 0)
321            BAIL(NC_EVARMETA);
322   if(H5Tset_cset(typeidH5T_CSET_UTF8) < 0)
323     BAIL(NC_EVARMETA);
324
325          /* Take ownership of the newly created HDF5 datatype */
326          *hdf_typeid = typeid;
327          typeid = 0;
328        }
329      else
330        {
331          if ((typeid = H5Tcopy(H5T_C_S1)) < 0)
332            return NC_EHDFERR;
333          if (H5Tset_size(typeidH5T_VARIABLE) < 0)
334            BAIL(NC_EVARMETA);
335   if(H5Tset_cset(typeidH5T_CSET_UTF8) < 0)
336     BAIL(NC_EVARMETA);
337
338          /* Take ownership of the newly created HDF5 datatype */
339          *hdf_typeid = typeid;
340          typeid = 0;
341        }
342    }
343  else
344    {
345      /* All other types use an existing HDF5 datatype */
346      switch (xtype)
347        {
348        case NC_BYTE: /* signed 1 byte integer */
349          if (endianness == NC_ENDIAN_LITTLE)
350            typeid = H5T_STD_I8LE;
351          else if (endianness == NC_ENDIAN_BIG)
352            typeid = H5T_STD_I8BE;
353          else
354            typeid = H5T_NATIVE_SCHAR;
355          break;
356
357        case NC_SHORT: /* signed 2 byte integer */
358          if (endianness == NC_ENDIAN_LITTLE)
359            typeid = H5T_STD_I16LE;
360          else if (endianness == NC_ENDIAN_BIG)
361            typeid = H5T_STD_I16BE;
362          else
363            typeid = H5T_NATIVE_SHORT;
364          break;
365
366        case NC_INT:
367          if (endianness == NC_ENDIAN_LITTLE)
368            typeid = H5T_STD_I32LE;
369          else if (endianness == NC_ENDIAN_BIG)
370            typeid = H5T_STD_I32BE;
371          else
372            typeid = H5T_NATIVE_INT;
373          break;
374
375        case NC_UBYTE:
376          if (endianness == NC_ENDIAN_LITTLE)
377            typeid = H5T_STD_U8LE;
378          else if (endianness == NC_ENDIAN_BIG)
379            typeid = H5T_STD_U8BE;
380          else
381            typeid = H5T_NATIVE_UCHAR;
382          break;
383
384        case NC_USHORT:
385          if (endianness == NC_ENDIAN_LITTLE)
386            typeid = H5T_STD_U16LE;
387          else if (endianness == NC_ENDIAN_BIG)
388            typeid = H5T_STD_U16BE;
389          else
390            typeid = H5T_NATIVE_USHORT;
391          break;
392
393        case NC_UINT:
394          if (endianness == NC_ENDIAN_LITTLE)
395            typeid = H5T_STD_U32LE;
396          else if (endianness == NC_ENDIAN_BIG)
397            typeid = H5T_STD_U32BE;
398          else
399            typeid = H5T_NATIVE_UINT;
400          break;
401
402        case NC_INT64:
403          if (endianness == NC_ENDIAN_LITTLE)
404            typeid = H5T_STD_I64LE;
405          else if (endianness == NC_ENDIAN_BIG)
406            typeid = H5T_STD_I64BE;
407          else
408            typeid = H5T_NATIVE_LLONG;
409          break;
410
411        case NC_UINT64:
412          if (endianness == NC_ENDIAN_LITTLE)
413            typeid = H5T_STD_U64LE;
414          else if (endianness == NC_ENDIAN_BIG)
415            typeid = H5T_STD_U64BE;
416          else
417            typeid = H5T_NATIVE_ULLONG;
418          break;
419
420        case NC_FLOAT:
421          if (endianness == NC_ENDIAN_LITTLE)
422            typeid = H5T_IEEE_F32LE;
423          else if (endianness == NC_ENDIAN_BIG)
424            typeid = H5T_IEEE_F32BE;
425          else
426            typeid = H5T_NATIVE_FLOAT;
427          break;
428
429        case NC_DOUBLE:
430          if (endianness == NC_ENDIAN_LITTLE)
431            typeid = H5T_IEEE_F64LE;
432          else if (endianness == NC_ENDIAN_BIG)
433            typeid = H5T_IEEE_F64BE;
434          else
435            typeid = H5T_NATIVE_DOUBLE;
436          break;
437
438        default:
439          /* Maybe this is a user defined type? */
440          if (nc4_find_type(h5xtype, &type))
441            return NC_EBADTYPE;
442          if (!type)
443            return NC_EBADTYPE;
444          typeid = type->hdf_typeid;
445          break;
446        }
447      assert(typeid);
448
449      /* Copy the HDF5 datatype, so the function operates uniformly */
450      if ((*hdf_typeid = H5Tcopy(typeid)) < 0)
451        return NC_EHDFERR;
452      typeid = 0;
453    }
454  assert(*hdf_typeid != -1);
455
456 exit:
457  if (typeid > 0 && H5Tclose(typeid) < 0)
458    BAIL2(NC_EHDFERR);
459  return retval;
460}
461
462/* Do some common check for nc4_put_vara and nc4_get_vara. These
463 * checks have to be done when both reading and writing data. */
464static int
465check_for_vara(nc_type *mem_nc_typeNC_VAR_INFO_T *varNC_HDF5_FILE_INFO_T *h5)
466{
467  int retval;
468
469  /* If mem_nc_type is NC_NAT, it means we want to use the file type
470   * as the mem type as well. */
471  assert(mem_nc_type);
472  if (*mem_nc_type == NC_NAT)
473    *mem_nc_type = var->type_info->nc_typeid;
474  assert(*mem_nc_type);
475
476  /* No NC_CHAR conversions, you pervert! */
477  if (var->type_info->nc_typeid != *mem_nc_type &&
478      (var->type_info->nc_typeid == NC_CHAR || *mem_nc_type == NC_CHAR))
479    return NC_ECHAR;
480
481  /* If we're in define mode, we can't read or write data. */
482  if (h5->flags & NC_INDEF)
483    {
484      if (h5->cmode & NC_CLASSIC_MODEL)
485        return NC_EINDEFINE;
486      if ((retval = nc4_enddef_netcdf4_file(h5)))
487        return retval;
488    }
489
490  return NC_NOERR;
491}
492
493#ifdef LOGGING
494/* Print some debug info about dimensions to the log. */
495static void
496log_dim_info(NC_VAR_INFO_T *varhsize_t *fdimshsize_t *fmaxdims,
497             hsize_t *starthsize_t *count)
498{
499  int d2;
500
501  /* Print some debugging info... */
502  LOG((4, "%s: var name %s ndims %d", __func__var->namevar->ndims));
503  LOG((4, "File space, and requested:"));
504  for (d2 = 0; d2 < var->ndimsd2++)
505    {
506      LOG((4, "fdims[%d]=%Ld fmaxdims[%d]=%Ld", d2fdims[d2], d2,
507           fmaxdims[d2]));
508      LOG((4, "start[%d]=%Ld  count[%d]=%Ld", d2start[d2], d2count[d2]));
509    }
510}
511#endif /* LOGGING */
512
513#ifdef USE_PARALLEL4
514static int
515set_par_access(NC_HDF5_FILE_INFO_T *h5NC_VAR_INFO_T *varhid_t xfer_plistid)
516{
517  /* If netcdf is built with parallel I/O, then parallel access can
518   * be used, and, if this file was opened or created for parallel
519   * access, we need to set the transfer mode. */
520  if (h5->parallel)
521    {
522      H5FD_mpio_xfer_t hdf5_xfer_mode;
523
524      /* Decide on collective or independent. */
525      hdf5_xfer_mode = (var->parallel_access != NC_INDEPENDENT) ?
526        H5FD_MPIO_COLLECTIVE : H5FD_MPIO_INDEPENDENT;
527
528      /* Set the mode in the transfer property list. */
529      if (H5Pset_dxpl_mpio(xfer_plistidhdf5_xfer_mode) < 0)
530        return NC_EPARINIT;
531
532      LOG((4, "%s: %d H5FD_MPIO_COLLECTIVE: %d H5FD_MPIO_INDEPENDENT: %d",
533           __func__, (int)hdf5_xfer_modeH5FD_MPIO_COLLECTIVEH5FD_MPIO_INDEPENDENT));
534    }
535  return NC_NOERR;
536}
537#endif
538
539/* Write an array of data to a variable. When it comes right down to
540 * it, this is what netCDF-4 is all about, this is *the* function, the
541 * big enchilda, the grand poo-bah, the alpha dog, the head honcho,
542 * the big cheese, the mighty kahuna, the top bananna, the high
543 * muckity-muck, numero uno. Well, you get the idea.  */
544int
545nc4_put_vara(NC *nc, int ncid, int varid, const size_t *startp,
546             const size_t *countpnc_type mem_nc_type, int is_long, void *data)
547{
548  NC_GRP_INFO_T *grp;
549  NC_HDF5_FILE_INFO_T *h5;
550  NC_VAR_INFO_T *var;
551  NC_DIM_INFO_T *dim;
552  hid_t file_spaceid = 0, mem_spaceid = 0, xfer_plistid = 0;
553  long long unsigned xtend_size[NC_MAX_VAR_DIMS];
554  hsize_t fdims[NC_MAX_VAR_DIMS], fmaxdims[NC_MAX_VAR_DIMS];
555  hsize_t start[NC_MAX_VAR_DIMS], count[NC_MAX_VAR_DIMS];
556  char *name_to_use;
557  int need_to_extend = 0;
558  int retval = NC_NOERRrange_error = 0, id2;
559  void *bufr = NULL;
560#ifndef HDF5_CONVERT
561  int need_to_convert = 0;
562  size_t len = 1;
563#endif
564#ifdef HDF5_CONVERT
565  hid_t mem_typeid = 0;
566#endif
567
568  /* Find our metadata for this file, group, and var. */
569  assert(nc);
570  if ((retval = nc4_find_g_var_nc(ncncidvarid, &grp, &var)))
571    return retval;
572  h5 = NC4_DATA(nc);
573  assert(grp && h5 && var && var->name);
574
575  LOG((3, "%s: var->name %s mem_nc_type %d is_long %d",
576       __func__var->namemem_nc_typeis_long));
577
578  /* Check some stuff about the type and the file. If the file must
579   * be switched from define mode, it happens here. */
580  if ((retval = check_for_vara(&mem_nc_typevarh5)))
581    return retval;
582
583  /* Convert from size_t and ptrdiff_t to hssize_t, and hsize_t. */
584  for (i = 0; i < var->ndimsi++)
585    {
586      start[i] = startp[i];
587      count[i] = countp[i];
588    }
589
590  /* Open this dataset if necessary, also checking for a weird case:
591   * a non-coordinate (and non-scalar) variable that has the same
592   * name as a dimension. */
593  if (var->hdf5_name && strlen(var->hdf5_name) >= strlen(NON_COORD_PREPEND) &&
594      strncmp(var->hdf5_nameNON_COORD_PREPEND, strlen(NON_COORD_PREPEND)) == 0 &&
595      var->ndims)
596    name_to_use = var->hdf5_name;
597  else
598    name_to_use = var->name;
599  if (!var->hdf_datasetid)
600    if ((var->hdf_datasetid = H5Dopen2(grp->hdf_grpidname_to_useH5P_DEFAULT)) < 0)
601      return NC_ENOTVAR;
602
603  /* Get file space of data. */
604  if ((file_spaceid = H5Dget_space(var->hdf_datasetid)) < 0)
605    BAIL(NC_EHDFERR);
606#ifdef EXTRA_TESTS
607  num_spaces++;
608#endif
609
610  /* Check to ensure the user selection is
611   * valid. H5Sget_simple_extent_dims gets the sizes of all the dims
612   * and put them in fdims. */
613  if (H5Sget_simple_extent_dims(file_spaceidfdimsfmaxdims) < 0)
614    BAIL(NC_EHDFERR);
615
616#ifdef LOGGING
617  log_dim_info(varfdimsfmaxdimsstartcount);
618#endif
619
620  /* Check dimension bounds. Remember that unlimited dimensions can
621   * put data beyond their current length. */
622  for (d2 = 0; d2 < var->ndimsd2++)
623    {
624      dim = var->dim[d2];
625      assert(dim && dim->dimid == var->dimids[d2]);
626      if (!dim->unlimited)
627        {
628          if (start[d2] > (hssize_t)fdims[d2] ||
629              (start[d2] == (hssize_t)fdims[d2] && count[d2] > 0))
630            BAIL_QUIET(NC_EINVALCOORDS);
631          if (start[d2] + count[d2] > fdims[d2])
632            BAIL_QUIET(NC_EEDGE);
633        }
634    }
635
636  /* Now you would think that no one would be crazy enough to write
637     a scalar dataspace with one of the array function calls, but you
638     would be wrong. So let's check to see if the dataset is
639     scalar. If it is, we won't try to set up a hyperslab. */
640  if (H5Sget_simple_extent_type(file_spaceid) == H5S_SCALAR)
641    {
642      if ((mem_spaceid = H5Screate(H5S_SCALAR)) < 0)
643        BAIL(NC_EHDFERR);
644#ifdef EXTRA_TESTS
645      num_spaces++;
646#endif
647    }
648  else
649    {
650      if (H5Sselect_hyperslab(file_spaceidH5S_SELECT_SETstartNULL,
651                              countNULL) < 0)
652        BAIL(NC_EHDFERR);
653
654      /* Create a space for the memory, just big enough to hold the slab
655         we want. */
656      if ((mem_spaceid = H5Screate_simple(var->ndimscountNULL)) < 0)
657        BAIL(NC_EHDFERR);
658#ifdef EXTRA_TESTS
659      num_spaces++;
660#endif
661    }
662
663#ifndef HDF5_CONVERT
664  /* Are we going to convert any data? (No converting of compound or
665   * opaque types.) */
666  if ((mem_nc_type != var->type_info->nc_typeid || (var->type_info->nc_typeid == NC_INT && is_long)) &&
667      mem_nc_type != NC_COMPOUND && mem_nc_type != NC_OPAQUE)
668    {
669      size_t file_type_size;
670
671      /* We must convert - allocate a buffer. */
672      need_to_convert++;
673      if (var->ndims)
674        for (d2=0; d2<var->ndimsd2++)
675          len *= countp[d2];
676      LOG((4, "converting data for var %s type=%d len=%d", var->name,
677           var->type_info->nc_typeidlen));
678
679      /* Later on, we will need to know the size of this type in the
680       * file. */
681      assert(var->type_info->size);
682      file_type_size = var->type_info->size;
683
684      /* If we're reading, we need bufr to have enough memory to store
685       * the data in the file. If we're writing, we need bufr to be
686       * big enough to hold all the data in the file's type. */
687      if(len > 0)
688        if (!(bufr = malloc(len * file_type_size)))
689          BAIL(NC_ENOMEM);
690    }
691  else
692#endif /* ifndef HDF5_CONVERT */
693    bufr = data;
694
695#ifdef HDF5_CONVERT
696  /* Get the HDF type of the data in memory. */
697  if ((retval = nc4_get_hdf_typeid(h5mem_nc_type, &mem_typeid,
698                                   var->type_info->endianness)))
699    BAIL(retval);
700#endif
701
702  /* Create the data transfer property list. */
703  if ((xfer_plistid = H5Pcreate(H5P_DATASET_XFER)) < 0)
704    BAIL(NC_EHDFERR);
705#ifdef EXTRA_TESTS
706  num_plists++;
707#endif
708
709  /* Apply the callback function which will detect range
710   * errors. Which one to call depends on the length of the
711   * destination buffer type. */
712#ifdef HDF5_CONVERT
713  if (H5Pset_type_conv_cb(xfer_plistidexcept_func, &range_error) < 0)
714    BAIL(NC_EHDFERR);
715#endif
716
717#ifdef USE_PARALLEL4
718  /* Set up parallel I/O, if needed. */
719  if ((retval = set_par_access(h5varxfer_plistid)))
720    BAIL(retval);
721#endif
722
723  /* Read/write this hyperslab into memory. */
724  /* Does the dataset have to be extended? If it's already
725     extended to the required size, it will do no harm to reextend
726     it to that size. */
727  if (var->ndims)
728    {
729      for (d2 = 0; d2 < var->ndimsd2++)
730        {
731          dim = var->dim[d2];
732   assert(dim && dim->dimid == var->dimids[d2]);
733          if (dim->unlimited)
734            {
735              if (start[d2] + count[d2] > fdims[d2])
736                {
737                  xtend_size[d2] = (long long unsigned)(start[d2] + count[d2]);
738                  need_to_extend++;
739                }
740              else
741                xtend_size[d2] = (long long unsigned)fdims[d2];
742
743              if (start[d2] + count[d2] > dim->len)
744                {
745                  dim->len = start[d2] + count[d2];
746                  dim->extended = NC_TRUE;
747                }
748            }
749          else
750            {
751              xtend_size[d2] = (long long unsigned)dim->len;
752            }
753        }
754
755#ifdef USE_PARALLEL4
756      /* Check if anyone wants to extend */
757      if (h5->parallel && NC_COLLECTIVE == var->parallel_access)
758        {
759          /* Form consensus opinion among all processes about whether to perform
760           * collective I/O
761           */
762          if(MPI_SUCCESS != MPI_Allreduce(MPI_IN_PLACE, &need_to_extend, 1, MPI_INTMPI_BORh5->comm))
763            BAIL(NC_EMPI);
764        }
765#endif /* USE_PARALLEL4 */
766
767      /* If we need to extend it, we also need a new file_spaceid
768         to reflect the new size of the space. */
769      if (need_to_extend)
770        {
771          LOG((4, "extending dataset"));
772#ifdef USE_PARALLEL4
773          if (h5->parallel)
774            {
775              if(NC_COLLECTIVE != var->parallel_access)
776                BAIL(NC_ECANTEXTEND);
777
778              /* Reach consensus about dimension sizes to extend to */
779              if(MPI_SUCCESS != MPI_Allreduce(MPI_IN_PLACExtend_sizevar->ndimsMPI_UNSIGNED_LONG_LONGMPI_MAXh5->comm))
780                BAIL(NC_EMPI);
781            }
782#endif /* USE_PARALLEL4 */
783          /* Convert xtend_size back to hsize_t for use with H5Dset_extent */
784          for (d2 = 0; d2 < var->ndimsd2++)
785            fdims[d2] = (hsize_t)xtend_size[d2];
786
787          if (H5Dset_extent(var->hdf_datasetidfdims) < 0)
788            BAIL(NC_EHDFERR);
789          if (file_spaceid > 0 && H5Sclose(file_spaceid) < 0)
790            BAIL2(NC_EHDFERR);
791          if ((file_spaceid = H5Dget_space(var->hdf_datasetid)) < 0)
792            BAIL(NC_EHDFERR);
793#ifdef EXTRA_TESTS
794          num_spaces++;
795#endif
796          if (H5Sselect_hyperslab(file_spaceidH5S_SELECT_SET,
797                                  startNULLcountNULL) < 0)
798            BAIL(NC_EHDFERR);
799        }
800    }
801
802#ifndef HDF5_CONVERT
803  /* Do we need to convert the data? */
804  if (need_to_convert)
805    {
806      if ((retval = nc4_convert_type(databufrmem_nc_typevar->type_info->nc_typeid,
807                                     len, &range_errorvar->fill_value,
808                                     (h5->cmode & NC_CLASSIC_MODEL), is_long, 0)))
809        BAIL(retval);
810    }
811#endif
812
813  /* Write the data. At last! */
814  LOG((4, "about to H5Dwrite datasetid 0x%x mem_spaceid 0x%x "
815       "file_spaceid 0x%x", var->hdf_datasetidmem_spaceidfile_spaceid));
816  if (H5Dwrite(var->hdf_datasetidvar->type_info->hdf_typeid,
817               mem_spaceidfile_spaceidxfer_plistidbufr) < 0)
818    BAIL(NC_EHDFERR);
819
820  /* Remember that we have written to this var so that Fill Value
821   * can't be set for it. */
822  if (!var->written_to)
823    var->written_to = NC_TRUE;
824
825  /* For strict netcdf-3 rules, ignore erange errors between UBYTE
826   * and BYTE types. */
827  if ((h5->cmode & NC_CLASSIC_MODEL) &&
828      (var->type_info->nc_typeid == NC_UBYTE || var->type_info->nc_typeid == NC_BYTE) &&
829      (mem_nc_type == NC_UBYTE || mem_nc_type == NC_BYTE) &&
830      range_error)
831    range_error = 0;
832
833 exit:
834#ifdef HDF5_CONVERT
835  if (mem_typeid > 0 && H5Tclose(mem_typeid) < 0)
836    BAIL2(NC_EHDFERR);
837#endif
838  if (file_spaceid > 0 && H5Sclose(file_spaceid) < 0)
839    BAIL2(NC_EHDFERR);
840#ifdef EXTRA_TESTS
841  num_spaces--;
842#endif
843  if (mem_spaceid > 0 && H5Sclose(mem_spaceid) < 0)
844    BAIL2(NC_EHDFERR);
845#ifdef EXTRA_TESTS
846  num_spaces--;
847#endif
848  if (xfer_plistid && (H5Pclose(xfer_plistid) < 0))
849    BAIL2(NC_EPARINIT);
850#ifdef EXTRA_TESTS
851  num_plists--;
852#endif
853#ifndef HDF5_CONVERT
854  if (need_to_convert && bufr) free(bufr);
855#endif
856
857  /* If there was an error return it, otherwise return any potential
858     range error value. If none, return NC_NOERR as usual.*/
859  if (retval)
860    return retval;
861  if (range_error)
862    return NC_ERANGE;
863  return NC_NOERR;
864}
865
866int
867nc4_get_vara(NC *nc, int ncid, int varid, const size_t *startp,
868             const size_t *countpnc_type mem_nc_type, int is_long, void *data)
869{
870  NC_GRP_INFO_T *grp, *g;
871  NC_HDF5_FILE_INFO_T *h5;
872  NC_VAR_INFO_T *var;
873  NC_DIM_INFO_T *dim;
874  hid_t file_spaceid = 0, mem_spaceid = 0;
875  hid_t xfer_plistid = 0;
876  size_t file_type_size;
877  hsize_t *xtend_size = NULLcount[NC_MAX_VAR_DIMS];
878  hsize_t fdims[NC_MAX_VAR_DIMS], fmaxdims[NC_MAX_VAR_DIMS];
879  hsize_t start[NC_MAX_VAR_DIMS];
880  char *name_to_use;
881  void *fillvalue = NULL;
882  int no_read = 0, provide_fill = 0;
883  int fill_value_size[NC_MAX_VAR_DIMS];
884  int scalar = 0, retval = NC_NOERRrange_error = 0, id2;
885  void *bufr = NULL;
886#ifdef HDF5_CONVERT
887  hid_t mem_typeid = 0;
888#endif
889#ifndef HDF5_CONVERT
890  int need_to_convert = 0;
891  size_t len = 1;
892#endif
893
894  /* Find our metadata for this file, group, and var. */
895  assert(nc);
896  if ((retval = nc4_find_g_var_nc(ncncidvarid, &grp, &var)))
897    return retval;
898  h5 = NC4_DATA(nc);
899  assert(grp && h5 && var && var->name);
900
901  LOG((3, "%s: var->name %s mem_nc_type %d is_long %d",
902       __func__var->namemem_nc_typeis_long));
903
904  /* Check some stuff about the type and the file. */
905  if ((retval = check_for_vara(&mem_nc_typevarh5)))
906    return retval;
907
908  /* Convert from size_t and ptrdiff_t to hssize_t, and hsize_t. */
909  for (i = 0; i < var->ndimsi++)
910    {
911      start[i] = startp[i];
912      count[i] = countp[i];
913    }
914
915  /* Open this dataset if necessary, also checking for a weird case:
916   * a non-coordinate (and non-scalar) variable that has the same
917   * name as a dimension. */
918  if (var->hdf5_name && strlen(var->hdf5_name) >= strlen(NON_COORD_PREPEND) &&
919      strncmp(var->hdf5_nameNON_COORD_PREPEND, strlen(NON_COORD_PREPEND)) == 0 &&
920      var->ndims)
921    name_to_use = var->hdf5_name;
922  else
923    name_to_use = var->name;
924  if (!var->hdf_datasetid)
925    if ((var->hdf_datasetid = H5Dopen2(grp->hdf_grpidname_to_useH5P_DEFAULT)) < 0)
926      return NC_ENOTVAR;
927
928  /* Get file space of data. */
929  if ((file_spaceid = H5Dget_space(var->hdf_datasetid)) < 0)
930    BAIL(NC_EHDFERR);
931#ifdef EXTRA_TESTS
932  num_spaces++;
933#endif
934
935  /* Check to ensure the user selection is
936   * valid. H5Sget_simple_extent_dims gets the sizes of all the dims
937   * and put them in fdims. */
938  if (H5Sget_simple_extent_dims(file_spaceidfdimsfmaxdims) < 0)
939    BAIL(NC_EHDFERR);
940
941#ifdef LOGGING
942  log_dim_info(varfdimsfmaxdimsstartcount);
943#endif
944
945  /* Check dimension bounds. Remember that unlimited dimensions can
946   * put data beyond their current length. */
947  for (d2 = 0; d2 < var->ndimsd2++) {
948    dim = var->dim[d2];
949    assert(dim && dim->dimid == var->dimids[d2]);
950    if (dim->unlimited)
951      {
952        size_t ulen;
953
954        /* We can't go beyond the largest current extent of
955           the unlimited dim. */
956 if ((retval = NC4_inq_dim(nciddim->dimidNULL, &ulen)))
957   BAIL(retval);
958
959        /* Check for out of bound requests. */
960        if (start[d2] > (hssize_t)ulen ||
961            (start[d2] == (hssize_t)ulen && count[d2] > 0))
962          BAIL_QUIET(NC_EINVALCOORDS);
963        if (start[d2] + count[d2] > ulen)
964          BAIL_QUIET(NC_EEDGE);
965
966        /* Things get a little tricky here. If we're getting
967           a GET request beyond the end of this var's
968           current length in an unlimited dimension, we'll
969           later need to return the fill value for the
970           variable. */
971        if (start[d2] >= (hssize_t)fdims[d2])
972          fill_value_size[d2] = count[d2];
973        else if (start[d2] + count[d2] > fdims[d2])
974          fill_value_size[d2] = count[d2] - (fdims[d2] - start[d2]);
975        else
976          fill_value_size[d2] = 0;
977        count[d2] -= fill_value_size[d2];
978        if (fill_value_size[d2])
979          provide_fill++;
980      }
981    else
982      {
983        /* Check for out of bound requests. */
984        if (start[d2] > (hssize_t)fdims[d2] ||
985            (start[d2] == (hssize_t)fdims[d2] && count[d2] > 0))
986          BAIL_QUIET(NC_EINVALCOORDS);
987        if (start[d2] + count[d2] > fdims[d2])
988          BAIL_QUIET(NC_EEDGE);
989
990        /* Set the fill value boundary */
991        fill_value_size[d2] = count[d2];
992      }
993  }
994
995  /* A little quirk: if any of the count values are zero, don't
996   * read. */
997  for (d2 = 0; d2 < var->ndimsd2++)
998    if (count[d2] == 0)
999      no_read++;
1000
1001  /* Later on, we will need to know the size of this type in the
1002   * file. */
1003  assert(var->type_info->size);
1004  file_type_size = var->type_info->size;
1005
1006  if (!no_read)
1007    {
1008      /* Now you would think that no one would be crazy enough to write
1009         a scalar dataspace with one of the array function calls, but you
1010         would be wrong. So let's check to see if the dataset is
1011         scalar. If it is, we won't try to set up a hyperslab. */
1012      if (H5Sget_simple_extent_type(file_spaceid) == H5S_SCALAR)
1013        {
1014          if ((mem_spaceid = H5Screate(H5S_SCALAR)) < 0)
1015            BAIL(NC_EHDFERR);
1016          scalar++;
1017#ifdef EXTRA_TESTS
1018          num_spaces++;
1019#endif
1020        }
1021      else
1022        {
1023          if (H5Sselect_hyperslab(file_spaceidH5S_SELECT_SET,
1024                                  startNULLcountNULL) < 0)
1025            BAIL(NC_EHDFERR);
1026          /* Create a space for the memory, just big enough to hold the slab
1027             we want. */
1028          if ((mem_spaceid = H5Screate_simple(var->ndimscountNULL)) < 0)
1029            BAIL(NC_EHDFERR);
1030#ifdef EXTRA_TESTS
1031          num_spaces++;
1032#endif
1033        }
1034
1035      /* Fix bug when reading HDF5 files with variable of type
1036       * fixed-length string.  We need to make it look like a
1037       * variable-length string, because that's all netCDF-4 data
1038       * model supports, lacking anonymous dimensions.  So
1039       * variable-length strings are in allocated memory that user has
1040       * to free, which we allocate here. */
1041      if(var->type_info->nc_type_class == NC_STRING &&
1042         H5Tget_size(var->type_info->hdf_typeid) > 1 &&
1043         !H5Tis_variable_str(var->type_info->hdf_typeid)) {
1044        hsize_t fstring_len;
1045
1046        if ((fstring_len = H5Tget_size(var->type_info->hdf_typeid)) == 0)
1047       BAIL(NC_EHDFERR);
1048        if (!(*(char **)data = malloc(1 + fstring_len)))
1049          BAIL(NC_ENOMEM);
1050        bufr = *(char **)data;
1051      }
1052
1053#ifndef HDF5_CONVERT
1054      /* Are we going to convert any data? (No converting of compound or
1055       * opaque types.) */
1056      if ((mem_nc_type != var->type_info->nc_typeid || (var->type_info->nc_typeid == NC_INT && is_long)) &&
1057          mem_nc_type != NC_COMPOUND && mem_nc_type != NC_OPAQUE)
1058        {
1059          /* We must convert - allocate a buffer. */
1060          need_to_convert++;
1061          if (var->ndims)
1062            for (d2 = 0; d2 < var->ndimsd2++)
1063              len *= countp[d2];
1064          LOG((4, "converting data for var %s type=%d len=%d", var->name,
1065               var->type_info->nc_typeidlen));
1066
1067          /* If we're reading, we need bufr to have enough memory to store
1068           * the data in the file. If we're writing, we need bufr to be
1069           * big enough to hold all the data in the file's type. */
1070          if(len > 0)
1071            if (!(bufr = malloc(len * file_type_size)))
1072              BAIL(NC_ENOMEM);
1073        }
1074      else
1075#endif /* ifndef HDF5_CONVERT */
1076        if(!bufr)
1077       bufr = data;
1078
1079      /* Get the HDF type of the data in memory. */
1080#ifdef HDF5_CONVERT
1081      if ((retval = nc4_get_hdf_typeid(h5mem_nc_type, &mem_typeid,
1082                                       var->type_info->endianness)))
1083        BAIL(retval);
1084#endif
1085
1086      /* Create the data transfer property list. */
1087      if ((xfer_plistid = H5Pcreate(H5P_DATASET_XFER)) < 0)
1088        BAIL(NC_EHDFERR);
1089#ifdef EXTRA_TESTS
1090      num_plists++;
1091#endif
1092
1093#ifdef HDF5_CONVERT
1094      /* Apply the callback function which will detect range
1095       * errors. Which one to call depends on the length of the
1096       * destination buffer type. */
1097      if (H5Pset_type_conv_cb(xfer_plistidexcept_func, &range_error) < 0)
1098        BAIL(NC_EHDFERR);
1099#endif
1100
1101#ifdef USE_PARALLEL4
1102      /* Set up parallel I/O, if needed. */
1103      if ((retval = set_par_access(h5varxfer_plistid)))
1104        BAIL(retval);
1105#endif
1106
1107      /* Read this hyperslab into memory. */
1108      LOG((5, "About to H5Dread some data..."));
1109      if (H5Dread(var->hdf_datasetidvar->type_info->native_hdf_typeid,
1110                  mem_spaceidfile_spaceidxfer_plistidbufr) < 0)
1111        BAIL(NC_EHDFERR);
1112
1113#ifndef HDF5_CONVERT
1114      /* Eventually the block below will go away. Right now it's
1115         needed to support conversions between int/float, and range
1116         checking converted data in the netcdf way. These features are
1117         being added to HDF5 at the HDF5 World Hall of Coding right
1118         now, by a staff of thousands of programming gnomes. */
1119      if (need_to_convert)
1120        {
1121          if ((retval = nc4_convert_type(bufrdatavar->type_info->nc_typeidmem_nc_type,
1122                                         len, &range_errorvar->fill_value,
1123                                         (h5->cmode & NC_CLASSIC_MODEL), 0, is_long)))
1124            BAIL(retval);
1125
1126          /* For strict netcdf-3 rules, ignore erange errors between UBYTE
1127           * and BYTE types. */
1128          if ((h5->cmode & NC_CLASSIC_MODEL) &&
1129              (var->type_info->nc_typeid == NC_UBYTE || var->type_info->nc_typeid == NC_BYTE) &&
1130              (mem_nc_type == NC_UBYTE || mem_nc_type == NC_BYTE) &&
1131              range_error)
1132            range_error = 0;
1133        }
1134#endif
1135
1136      /* For strict netcdf-3 rules, ignore erange errors between UBYTE
1137       * and BYTE types. */
1138      if ((h5->cmode & NC_CLASSIC_MODEL) &&
1139          (var->type_info->nc_typeid == NC_UBYTE || var->type_info->nc_typeid == NC_BYTE) &&
1140          (mem_nc_type == NC_UBYTE || mem_nc_type == NC_BYTE) &&
1141          range_error)
1142        range_error = 0;
1143
1144    } /* endif ! no_read */
1145
1146    else {
1147#ifdef USE_PARALLEL4 /* Start block contributed by HDF group. */
1148        /* For collective IO read, some processes may not have any element for reading.
1149           Collective requires all processes to participate, so we use H5Sselect_none
1150           for these processes. */
1151        if(var->parallel_access == NC_COLLECTIVE) {
1152
1153           /* Create the data transfer property list. */
1154           if ((xfer_plistid = H5Pcreate(H5P_DATASET_XFER)) < 0)
1155                BAIL(NC_EHDFERR);
1156#ifdef EXTRA_TESTS
1157           num_plists++;
1158#endif
1159
1160           if ((retval = set_par_access(h5varxfer_plistid)))
1161                BAIL(retval);
1162
1163           if (H5Sselect_none(file_spaceid)<0)
1164              BAIL(NC_EHDFERR);
1165
1166           /* Since no element will be selected, we just get the memory space the same as the file space.
1167           */
1168           if((mem_spaceid = H5Dget_space(var->hdf_datasetid))<0)
1169             BAIL(NC_EHDFERR);
1170           if (H5Sselect_none(mem_spaceid)<0)
1171              BAIL(NC_EHDFERR);
1172
1173#ifdef EXTRA_TESTS
1174             num_spaces++;
1175#endif
1176            /* Read this hyperslab into memory. */
1177            LOG((5, "About to H5Dread some data..."));
1178            if (H5Dread(var->hdf_datasetidvar->type_info->native_hdf_typeid,
1179                  mem_spaceidfile_spaceidxfer_plistidbufr) < 0)
1180                BAIL(NC_EHDFERR);
1181        }
1182#endif /* End ifdef USE_PARALLEL4 */
1183    }
1184  /* Now we need to fake up any further data that was asked for,
1185     using the fill values instead. First skip past the data we
1186     just read, if any. */
1187  if (!scalar && provide_fill)
1188    {
1189      void *filldata;
1190      size_t real_data_size = 0;
1191      size_t fill_len;
1192
1193      /* Skip past the real data we've already read. */
1194      if (!no_read)
1195        for (real_data_size = file_type_sized2 = 0; d2 < var->ndimsd2++)
1196          real_data_size *= (count[d2] - start[d2]);
1197
1198      /* Get the fill value from the HDF5 variable. Memory will be
1199       * allocated. */
1200      if (get_fill_value(h5var, &fillvalue) < 0)
1201        BAIL(NC_EHDFERR);
1202
1203      /* How many fill values do we need? */
1204      for (fill_len = 1, d2 = 0; d2 < var->ndimsd2++)
1205        fill_len *= (fill_value_size[d2] ? fill_value_size[d2] : 1);
1206
1207      /* Copy the fill value into the rest of the data buffer. */
1208      filldata = (char *)data + real_data_size;
1209      for (i = 0; i < fill_leni++)
1210        {
1211
1212          if (var->type_info->nc_type_class == NC_STRING)
1213            {
1214              if (*(char **)fillvalue)
1215                {
1216                  if (!(*(char **)filldata = strdup(*(char **)fillvalue)))
1217                    BAIL(NC_ENOMEM);
1218                }
1219              else
1220                *(char **)filldata = NULL;
1221            }
1222          else if(var->type_info->nc_type_class == NC_VLEN) {
1223            if(fillvalue) {
1224              memcpy(filldata,fillvalue,file_type_size);
1225            } else {
1226              *(char **)filldata = NULL;
1227            }
1228          } else
1229            memcpy(filldatafillvaluefile_type_size);
1230          filldata = (char *)filldata + file_type_size;
1231        }
1232    }
1233
1234 exit:
1235#ifdef HDF5_CONVERT
1236  if (mem_typeid > 0 && H5Tclose(mem_typeid) < 0)
1237    BAIL2(NC_EHDFERR);
1238#endif
1239  if (file_spaceid > 0)
1240    {
1241      if (H5Sclose(file_spaceid) < 0)
1242        BAIL2(NC_EHDFERR);
1243#ifdef EXTRA_TESTS
1244      num_spaces--;
1245#endif
1246    }
1247  if (mem_spaceid > 0)
1248    {
1249      if (H5Sclose(mem_spaceid) < 0)
1250        BAIL2(NC_EHDFERR);
1251#ifdef EXTRA_TESTS
1252      num_spaces--;
1253#endif
1254    }
1255  if (xfer_plistid > 0)
1256    {
1257      if (H5Pclose(xfer_plistid) < 0)
1258        BAIL2(NC_EHDFERR);
1259#ifdef EXTRA_TESTS
1260      num_plists--;
1261#endif
1262    }
1263#ifndef HDF5_CONVERT
1264  if (need_to_convert && bufr != NULL)
1265    free(bufr);
1266#endif
1267  if (xtend_size)
1268    free(xtend_size);
1269  if (fillvalue)
1270    {
1271      if (var->type_info->nc_type_class == NC_VLEN)
1272        nc_free_vlen((nc_vlen_t *)fillvalue);
1273      else if (var->type_info->nc_type_class == NC_STRING && *(char **)fillvalue)
1274        free(*(char **)fillvalue);
1275      free(fillvalue);
1276    }
1277
1278  /* If there was an error return it, otherwise return any potential
1279     range error value. If none, return NC_NOERR as usual.*/
1280  if (retval)
1281    return retval;
1282  if (range_error)
1283    return NC_ERANGE;
1284  return NC_NOERR;
1285}
1286
1287/* Read or write an attribute. */
1288static int
1289put_att_grpa(NC_GRP_INFO_T *grp, int varidNC_ATT_INFO_T *att)
1290{
1291  hid_t datasetid = 0, locid;
1292  hid_t attid = 0, spaceid = 0, file_typeid = 0;
1293  hsize_t dims[1]; /* netcdf attributes always 1-D. */
1294  htri_t attr_exists;
1295  int retval = NC_NOERR;
1296  void *data;
1297  int phoney_data = 99;
1298
1299  assert(att->name);
1300  LOG((3, "%s: varid %d att->attnum %d att->name %s att->nc_typeid %d att->len %d",
1301       __func__varidatt->attnumatt->name,
1302       att->nc_typeidatt->len));
1303
1304  /* If the file is read-only, return an error. */
1305  if (grp->nc4_info->no_write)
1306    BAIL(NC_EPERM);
1307
1308  /* Get the hid to attach the attribute to, or read it from. */
1309  if (varid == NC_GLOBAL)
1310    locid = grp->hdf_grpid;
1311  else
1312    {
1313      if ((retval = nc4_open_var_grp2(grpvarid, &datasetid)))
1314        BAIL(retval);
1315      locid = datasetid;
1316    }
1317
1318  /* Delete the att if it exists already. */
1319  if ((attr_exists = H5Aexists(locidatt->name)) < 0)
1320    BAIL(NC_EHDFERR);
1321  if (attr_exists)
1322    {
1323      if (H5Adelete(locidatt->name) < 0)
1324        BAIL(NC_EHDFERR);
1325    }
1326
1327  /* Get the length ready, and find the HDF type we'll be
1328   * writing. */
1329  dims[0] = att->len;
1330  if ((retval = nc4_get_hdf_typeid(grp->nc4_infoatt->nc_typeid,
1331                                   &file_typeid, 0)))
1332    BAIL(retval);
1333
1334  /* Even if the length is zero, HDF5 won't let me write with a
1335   * NULL pointer. So if the length of the att is zero, point to
1336   * some phoney data (which won't be written anyway.)*/
1337  if (!dims[0])
1338    data = &phoney_data;
1339  else if (att->data)
1340    data = att->data;
1341  else if (att->stdata)
1342    data = att->stdata;
1343  else
1344    data = att->vldata;
1345
1346  /* NC_CHAR types require some extra work. The space ID is set to
1347   * scalar, and the type is told how long the string is. If it's
1348   * really zero length, set the size to 1. (The fact that it's
1349   * really zero will be marked by the NULL dataspace, but HDF5
1350   * doesn't allow me to set the size of the type to zero.)*/
1351  if (att->nc_typeid == NC_CHAR)
1352    {
1353      size_t string_size = dims[0];
1354      if (!string_size)
1355        {
1356          string_size = 1;
1357          if ((spaceid = H5Screate(H5S_NULL)) < 0)
1358            BAIL(NC_EATTMETA);
1359#ifdef EXTRA_TESTS
1360          num_spaces++;
1361#endif
1362        }
1363      else
1364        {
1365          if ((spaceid = H5Screate(H5S_SCALAR)) < 0)
1366            BAIL(NC_EATTMETA);
1367#ifdef EXTRA_TESTS
1368          num_spaces++;
1369#endif
1370        }
1371      if (H5Tset_size(file_typeidstring_size) < 0)
1372        BAIL(NC_EATTMETA);
1373      if (H5Tset_strpad(file_typeidH5T_STR_NULLTERM) < 0)
1374        BAIL(NC_EATTMETA);
1375    }
1376  else
1377    {
1378      if (!att->len)
1379        {
1380          if ((spaceid = H5Screate(H5S_NULL)) < 0)
1381            BAIL(NC_EATTMETA);
1382#ifdef EXTRA_TESTS
1383          num_spaces++;
1384#endif
1385        }
1386      else
1387        {
1388          if ((spaceid = H5Screate_simple(1, dimsNULL)) < 0)
1389            BAIL(NC_EATTMETA);
1390#ifdef EXTRA_TESTS
1391          num_spaces++;
1392#endif
1393        }
1394    }
1395  if ((attid = H5Acreate(locidatt->namefile_typeidspaceid,
1396                         H5P_DEFAULT)) < 0)
1397    BAIL(NC_EATTMETA);
1398
1399  /* Write the values, (even if length is zero). */
1400  if (H5Awrite(attidfile_typeiddata) < 0)
1401    BAIL(NC_EATTMETA);
1402
1403 exit:
1404  if (file_typeid && H5Tclose(file_typeid))
1405    BAIL2(NC_EHDFERR);
1406  if (attid > 0 && H5Aclose(attid) < 0)
1407    BAIL2(NC_EHDFERR);
1408  if (spaceid > 0 && H5Sclose(spaceid) < 0)
1409    BAIL2(NC_EHDFERR);
1410#ifdef EXTRA_TESTS
1411  num_spaces--;
1412#endif
1413  return retval;
1414}
1415
1416/* Write all the dirty atts in an attlist. */
1417static int
1418write_attlist(NC_ATT_INFO_T *attlist, int varidNC_GRP_INFO_T *grp)
1419{
1420  NC_ATT_INFO_T *att;
1421  int retval;
1422
1423  for (att = attlistattatt = att->l.next)
1424    {
1425      if (att->dirty)
1426        {
1427          LOG((4, "%s: writing att %s to varid %d", __func__att->namevarid));
1428          if ((retval = put_att_grpa(grpvaridatt)))
1429            return retval;
1430          att->dirty = NC_FALSE;
1431          att->created = NC_TRUE;
1432        }
1433    }
1434  return NC_NOERR;
1435}
1436
1437
1438/* This function is a bit of a hack. Turns out that HDF5 dimension
1439 * scales cannot themselves have scales attached. This leaves
1440 * multidimensional coordinate variables hosed. So this function
1441 * writes a special attribute for such a variable, which has the ids
1442 * of all the dimensions for that coordinate variable. This sucks,
1443 * really. But that's the way the cookie crumbles. Better luck next
1444 * time. This function also contains a new way of dealing with HDF5
1445 * error handling, abandoning the BAIL macros for a more organic and
1446 * natural approach, made with whole grains, and locally-grown
1447 * vegetables. */
1448static int
1449write_coord_dimids(NC_VAR_INFO_T *var)
1450{
1451  hsize_t coords_len[1];
1452  hid_t c_spaceid = -1, c_attid = -1;
1453  int ret = 0;
1454
1455  /* Write our attribute. */
1456  coords_len[0] = var->ndims;
1457  if ((c_spaceid = H5Screate_simple(1, coords_lencoords_len)) < 0) ret++;
1458#ifdef EXTRA_TESTS
1459  num_spaces++;
1460#endif
1461  if (!ret && (c_attid = H5Acreate(var->hdf_datasetidCOORDINATESH5T_NATIVE_INT,
1462                                   c_spaceidH5P_DEFAULT)) < 0) ret++;
1463  if (!ret && H5Awrite(c_attidH5T_NATIVE_INTvar->dimids) < 0) ret++;
1464
1465  /* Close up shop. */
1466  if (c_spaceid > 0 && H5Sclose(c_spaceid) < 0) ret++;
1467#ifdef EXTRA_TESTS
1468  num_spaces--;
1469#endif
1470  if (c_attid > 0 && H5Aclose(c_attid) < 0) ret++;
1471  return ret ? NC_EHDFERR : 0;
1472}
1473
1474/* Write a special attribute for the netCDF-4 dimension ID. */
1475static int
1476write_netcdf4_dimid(hid_t datasetid, int dimid)
1477{
1478  hid_t dimid_spaceiddimid_attid;
1479  htri_t attr_exists;
1480
1481  /* Create the space. */
1482  if ((dimid_spaceid = H5Screate(H5S_SCALAR)) < 0)
1483    return NC_EHDFERR;
1484#ifdef EXTRA_TESTS
1485  num_spaces++;
1486#endif
1487
1488  /* Does the attribute already exist? If so, don't try to create it. */
1489  if ((attr_exists = H5Aexists(datasetidNC_DIMID_ATT_NAME)) < 0)
1490    return NC_EHDFERR;
1491  if (attr_exists)
1492    dimid_attid = H5Aopen_by_name(datasetid, ".", NC_DIMID_ATT_NAME,
1493                                  H5P_DEFAULTH5P_DEFAULT);
1494  else
1495    /* Create the attribute if needed. */
1496    dimid_attid = H5Acreate(datasetidNC_DIMID_ATT_NAME,
1497                            H5T_NATIVE_INTdimid_spaceidH5P_DEFAULT);
1498  if (dimid_attid  < 0)
1499    return NC_EHDFERR;
1500
1501
1502  /* Write it. */
1503  LOG((4, "%s: writing secret dimid %d", __func__dimid));
1504  if (H5Awrite(dimid_attidH5T_NATIVE_INT, &dimid) < 0)
1505    return NC_EHDFERR;
1506
1507  /* Close stuff*/
1508  if (H5Sclose(dimid_spaceid) < 0)
1509    return NC_EHDFERR;
1510#ifdef EXTRA_TESTS
1511  num_spaces--;
1512#endif
1513  if (H5Aclose(dimid_attid) < 0)
1514    return NC_EHDFERR;
1515
1516  return NC_NOERR;
1517}
1518
1519/* This function creates the HDF5 dataset for a variable. */
1520static int
1521var_create_dataset(NC_GRP_INFO_T *grpNC_VAR_INFO_T *varnc_bool_t write_dimid)
1522{
1523  NC_GRP_INFO_T *g;
1524  hid_t plistid = 0, access_plistid = 0, typeid = 0, spaceid = 0;
1525  hsize_t chunksize[H5S_MAX_RANK], dimsize[H5S_MAX_RANK], maxdimsize[H5S_MAX_RANK];
1526  int d;
1527  void *fillp = NULL;
1528  NC_DIM_INFO_T *dim = NULL;
1529  int dims_found = 0;
1530  char *name_to_use;
1531  int retval = NC_NOERR;
1532
1533  LOG((3, "%s:: name %s", __func__var->name));
1534
1535  /* Scalar or not, we need a creation property list. */
1536  if ((plistid = H5Pcreate(H5P_DATASET_CREATE)) < 0)
1537    BAIL(NC_EHDFERR);
1538#ifdef EXTRA_TESTS
1539  num_plists++;
1540#endif
1541  if ((access_plistid = H5Pcreate(H5P_DATASET_ACCESS)) < 0)
1542    BAIL(NC_EHDFERR);
1543#ifdef EXTRA_TESTS
1544  num_plists++;
1545#endif
1546
1547  /* RJ: this suppose to be FALSE that is defined in H5 private.h as 0 */
1548  if (H5Pset_obj_track_times(plistid,0)<0)
1549    BAIL(NC_EHDFERR);
1550
1551  /* Find the HDF5 type of the dataset. */
1552  if ((retval = nc4_get_hdf_typeid(grp->nc4_infovar->type_info->nc_typeid, &typeid,
1553                                   var->type_info->endianness)))
1554    BAIL(retval);
1555
1556  /* Figure out what fill value to set, if any. */
1557  if (var->no_fill)
1558    {
1559      /* Required to truly turn HDF5 fill values off */
1560      if (H5Pset_fill_time(plistidH5D_FILL_TIME_NEVER) < 0)
1561        BAIL(NC_EHDFERR);
1562    }
1563  else
1564    {
1565      if ((retval = get_fill_value(grp->nc4_infovar, &fillp)))
1566        BAIL(retval);
1567
1568      /* If there is a fill value, set it. */
1569      if (fillp)
1570        {
1571          if (var->type_info->nc_type_class == NC_STRING)
1572            {
1573              if (H5Pset_fill_value(plistidtypeidfillp) < 0)
1574                BAIL(NC_EHDFERR);
1575            }
1576          else
1577            {
1578              /* The fill value set in HDF5 must always be presented as
1579               * a native type, even if the endianness for this dataset
1580               * is non-native. HDF5 will translate the fill value to
1581               * the target endiannesss. */
1582              hid_t fill_typeid = 0;
1583
1584              if ((retval = nc4_get_hdf_typeid(grp->nc4_infovar->type_info->nc_typeid, &fill_typeid,
1585                                               NC_ENDIAN_NATIVE)))
1586                BAIL(retval);
1587              if (H5Pset_fill_value(plistidfill_typeidfillp) < 0)
1588                {
1589                  if (H5Tclose(fill_typeid) < 0)
1590                    BAIL(NC_EHDFERR);
1591                  BAIL(NC_EHDFERR);
1592                }
1593              if (H5Tclose(fill_typeid) < 0)
1594                BAIL(NC_EHDFERR);
1595            }
1596        }
1597    }
1598
1599  /* If the user wants to shuffle the data, set that up now. */
1600  if (var->shuffle)
1601    if (H5Pset_shuffle(plistid) < 0)
1602      BAIL(NC_EHDFERR);
1603
1604  /* If the user wants to deflate the data, set that up now. */
1605  if (var->deflate)
1606    if (H5Pset_deflate(plistidvar->deflate_level) < 0)
1607      BAIL(NC_EHDFERR);
1608
1609  /* Szip? NO! We don't want anyone to produce szipped netCDF files! */
1610  /* #ifdef USE_SZIP */
1611  /*    if (var->options_mask) */
1612  /*       if (H5Pset_szip(plistid, var->options_mask, var->bits_per_pixel) < 0) */
1613  /*          BAIL(NC_EHDFERR); */
1614  /* #endif */
1615
1616  /* If the user wants to fletcher error correcton, set that up now. */
1617  if (var->fletcher32)
1618    if (H5Pset_fletcher32(plistid) < 0)
1619      BAIL(NC_EHDFERR);
1620
1621  /* If ndims non-zero, get info for all dimensions. We look up the
1622     dimids and get the len of each dimension. We need this to create
1623     the space for the dataset. In netCDF a dimension length of zero
1624     means an unlimited dimension. */
1625  if (var->ndims)
1626    {
1627      int unlimdim = 0;
1628
1629      /* Check to see if any unlimited dimensions are used in this var. */
1630      for (d = 0; d < var->ndimsd++) {
1631 dim = var->dim[d];
1632 assert(dim && dim->dimid == var->dimids[d]);
1633 if (dim->unlimited)
1634   unlimdim++;
1635      }
1636
1637      /* If there are no unlimited dims, and no filters, and the user
1638       * has not specified chunksizes, use contiguous variable for
1639       * better performance. */
1640
1641      if(!var->shuffle && !var->deflate && !var->options_mask &&
1642         !var->fletcher32 && (var->chunksizes == NULL || !var->chunksizes[0])) {
1643#ifdef USE_HDF4
1644        NC_HDF5_FILE_INFO_T *h5 = grp->nc4_info;
1645        if(h5->hdf4 || !unlimdim)
1646#else
1647          if(!unlimdim)
1648#endif
1649            var->contiguous = NC_TRUE;
1650      }
1651
1652      /* Gather current & maximum dimension sizes, along with chunk sizes */
1653      for (d = 0; d < var->ndimsd++)
1654        {
1655          dim = var->dim[d];
1656   assert(dim && dim->dimid == var->dimids[d]);
1657          dimsize[d] = dim->unlimited ? NC_HDF5_UNLIMITED_DIMSIZE : dim->len;
1658          maxdimsize[d] = dim->unlimited ? H5S_UNLIMITED : (hsize_t)dim->len;
1659          if (!var->contiguous) {
1660            if (var->chunksizes[d])
1661              chunksize[d] = var->chunksizes[d];
1662            else
1663              {
1664                size_t type_size;
1665                if (var->type_info->nc_type_class == NC_STRING)
1666                  type_size = sizeof(char *);
1667                else
1668                  type_size = var->type_info->size;
1669
1670                /* Unlimited dim always gets chunksize of 1. */
1671                if (dim->unlimited)
1672                  chunksize[d] = 1;
1673                else
1674                  chunksize[d] = pow((double)DEFAULT_CHUNK_SIZE/type_size,
1675                                     1/(double)(var->ndims - unlimdim));
1676
1677                /* If the chunksize is greater than the dim
1678                 * length, make it the dim length. */
1679                if (!dim->unlimited && chunksize[d] > dim->len)
1680                  chunksize[d] = dim->len;
1681
1682                /* Remember the computed chunksize */
1683                var->chunksizes[d] = chunksize[d];
1684              }
1685          }
1686        }
1687
1688      if (var->contiguous)
1689        {
1690          if (H5Pset_layout(plistidH5D_CONTIGUOUS) < 0)
1691            BAIL(NC_EHDFERR);
1692        }
1693      else
1694        {
1695          if (H5Pset_chunk(plistidvar->ndimschunksize) < 0)
1696            BAIL(NC_EHDFERR);
1697        }
1698
1699      /* Create the dataspace. */
1700      if ((spaceid = H5Screate_simple(var->ndimsdimsizemaxdimsize)) < 0)
1701        BAIL(NC_EHDFERR);
1702#ifdef EXTRA_TESTS
1703      num_spaces++;
1704#endif
1705    }
1706  else
1707    {
1708      if ((spaceid = H5Screate(H5S_SCALAR)) < 0)
1709        BAIL(NC_EHDFERR);
1710#ifdef EXTRA_TESTS
1711      num_spaces++;
1712#endif
1713    }
1714
1715  /* Turn on creation order tracking. */
1716  if (H5Pset_attr_creation_order(plistidH5P_CRT_ORDER_TRACKED|
1717                                 H5P_CRT_ORDER_INDEXED) < 0)
1718    BAIL(NC_EHDFERR);
1719
1720  /* Set per-var chunk cache, for chunked datasets. */
1721  if (!var->contiguous && var->chunk_cache_size)
1722    if (H5Pset_chunk_cache(access_plistidvar->chunk_cache_nelems,
1723                           var->chunk_cache_sizevar->chunk_cache_preemption) < 0)
1724      BAIL(NC_EHDFERR);
1725
1726  /* At long last, create the dataset. */
1727  name_to_use = var->hdf5_name ? var->hdf5_name : var->name;
1728  LOG((4, "%s: about to H5Dcreate2 dataset %s of type 0x%x", __func__,
1729       name_to_usetypeid));
1730  if ((var->hdf_datasetid = H5Dcreate2(grp->hdf_grpidname_to_usetypeid,
1731                                       spaceidH5P_DEFAULTplistidaccess_plistid)) < 0)
1732    BAIL(NC_EHDFERR);
1733  var->created = NC_TRUE;
1734  var->is_new_var = NC_FALSE;
1735
1736  /* If this is a dimscale, mark it as such in the HDF5 file. Also
1737   * find the dimension info and store the dataset id of the dimscale
1738   * dataset. */
1739  if (var->dimscale)
1740    {
1741      if (H5DSset_scale(var->hdf_datasetidvar->name) < 0)
1742        BAIL(NC_EHDFERR);
1743
1744      /* If this is a multidimensional coordinate variable, write a
1745       * coordinates attribute. */
1746      if (var->ndims > 1)
1747        if ((retval = write_coord_dimids(var)))
1748          BAIL(retval);
1749
1750      /* If desired, write the netCDF dimid. */
1751      if (write_dimid)
1752        if ((retval = write_netcdf4_dimid(var->hdf_datasetidvar->dimids[0])))
1753          BAIL(retval);
1754    }
1755
1756
1757  /* Write attributes for this var. */
1758  if ((retval = write_attlist(var->attvar->varidgrp)))
1759    BAIL(retval);
1760  var->attr_dirty = NC_FALSE;
1761
1762 exit:
1763  if (typeid > 0 && H5Tclose(typeid) < 0)
1764    BAIL2(NC_EHDFERR);
1765  if (plistid > 0 && H5Pclose(plistid) < 0)
1766    BAIL2(NC_EHDFERR);
1767#ifdef EXTRA_TESTS
1768  num_plists--;
1769#endif
1770  if (access_plistid > 0 && H5Pclose(access_plistid) < 0)
1771    BAIL2(NC_EHDFERR);
1772#ifdef EXTRA_TESTS
1773  num_plists--;
1774#endif
1775  if (spaceid > 0 && H5Sclose(spaceid) < 0)
1776    BAIL2(NC_EHDFERR);
1777#ifdef EXTRA_TESTS
1778  num_spaces--;
1779#endif
1780  if (fillp)
1781    {
1782      if (var->type_info->nc_type_class == NC_VLEN)
1783        nc_free_vlen((nc_vlen_t *)fillp);
1784      else if (var->type_info->nc_type_class == NC_STRING && *(char **)fillp)
1785        free(*(char **)fillp);
1786      free(fillp);
1787    }
1788
1789  return retval;
1790}
1791
1792/* Adjust the chunk cache of a var for better performance. */
1793int
1794nc4_adjust_var_cache(NC_GRP_INFO_T *grpNC_VAR_INFO_T * var)
1795{
1796  size_t chunk_size_bytes = 1;
1797  int d;
1798  int retval;
1799
1800  /* Nothing to be done. */
1801  if (var->contiguous)
1802    return NC_NOERR;
1803#ifdef USE_PARALLEL4
1804  return NC_NOERR;
1805#endif
1806
1807  /* How many bytes in the chunk? */
1808  for (d = 0; d < var->ndimsd++)
1809    chunk_size_bytes *= var->chunksizes[d];
1810  if (var->type_info->size)
1811    chunk_size_bytes *= var->type_info->size;
1812  else
1813    chunk_size_bytes *= sizeof(char *);
1814
1815  /* If the chunk cache is too small, and the user has not changed
1816   * the default value of the chunk cache size, then increase the
1817   * size of the cache. */
1818  if (var->chunk_cache_size == CHUNK_CACHE_SIZE)
1819    if (chunk_size_bytes > var->chunk_cache_size)
1820      {
1821        var->chunk_cache_size = chunk_size_bytes * DEFAULT_CHUNKS_IN_CACHE;
1822        if (var->chunk_cache_size > MAX_DEFAULT_CACHE_SIZE)
1823          var->chunk_cache_size = MAX_DEFAULT_CACHE_SIZE;
1824        if ((retval = nc4_reopen_dataset(grpvar)))
1825          return retval;
1826      }
1827
1828  return NC_NOERR;
1829}
1830
1831/* Create a HDF5 defined type from a NC_TYPE_INFO_T struct, and commit
1832 * it to the file. */
1833static int
1834commit_type(NC_GRP_INFO_T *grpNC_TYPE_INFO_T *type)
1835{
1836  int retval;
1837
1838  assert(grp && type);
1839
1840  /* Did we already record this type? */
1841  if (type->committed)
1842    return NC_NOERR;
1843
1844  /* Is this a compound type? */
1845  if (type->nc_type_class == NC_COMPOUND)
1846    {
1847      NC_FIELD_INFO_T *field;
1848      hid_t hdf_base_typeidhdf_typeid;
1849
1850      if ((type->hdf_typeid = H5Tcreate(H5T_COMPOUNDtype->size)) < 0)
1851        return NC_EHDFERR;
1852      LOG((4, "creating compound type %s hdf_typeid 0x%x", type->name,
1853           type->hdf_typeid));
1854
1855      for (field = type->u.c.fieldfieldfield = field->l.next)
1856        {
1857          if ((retval = nc4_get_hdf_typeid(grp->nc4_infofield->nc_typeid,
1858                                           &hdf_base_typeidtype->endianness)))
1859            return retval;
1860
1861          /* If this is an array, create a special array type. */
1862          if (field->ndims)
1863            {
1864              int d;
1865              hsize_t dims[NC_MAX_VAR_DIMS];
1866
1867              for (d = 0; d < field->ndimsd++)
1868                dims[d] = field->dim_size[d];
1869              if ((hdf_typeid = H5Tarray_create(hdf_base_typeidfield->ndims,
1870                                                dimsNULL)) < 0)
1871                {
1872                  if (H5Tclose(hdf_base_typeid) < 0)
1873                    return NC_EHDFERR;
1874                  return NC_EHDFERR;
1875                }
1876              if (H5Tclose(hdf_base_typeid) < 0)
1877                return NC_EHDFERR;
1878            }
1879          else
1880            hdf_typeid = hdf_base_typeid;
1881          LOG((4, "inserting field %s offset %d hdf_typeid 0x%x", field->name,
1882               field->offsethdf_typeid));
1883          if (H5Tinsert(type->hdf_typeidfield->namefield->offset,
1884                        hdf_typeid) < 0)
1885            return NC_EHDFERR;
1886          if (H5Tclose(hdf_typeid) < 0)
1887            return NC_EHDFERR;
1888        }
1889    }
1890  else if (type->nc_type_class == NC_VLEN)
1891    {
1892      /* Find the HDF typeid of the base type of this vlen. */
1893      if ((retval = nc4_get_hdf_typeid(grp->nc4_infotype->u.v.base_nc_typeid,
1894                                       &type->u.v.base_hdf_typeidtype->endianness)))
1895        return retval;
1896
1897      /* Create a vlen type. */
1898      if ((type->hdf_typeid = H5Tvlen_create(type->u.v.base_hdf_typeid)) < 0)
1899        return NC_EHDFERR;
1900    }
1901  else if (type->nc_type_class == NC_OPAQUE)
1902    {
1903      /* Create the opaque type. */
1904      if ((type->hdf_typeid = H5Tcreate(H5T_OPAQUEtype->size)) < 0)
1905        return NC_EHDFERR;
1906    }
1907  else if (type->nc_type_class == NC_ENUM)
1908    {
1909      NC_ENUM_MEMBER_INFO_T *enum_m;
1910
1911      if (!type->u.e.enum_member)
1912        return NC_EINVAL;
1913
1914      /* Find the HDF typeid of the base type of this enum. */
1915      if ((retval = nc4_get_hdf_typeid(grp->nc4_infotype->u.e.base_nc_typeid,
1916                                       &type->u.e.base_hdf_typeidtype->endianness)))
1917        return retval;
1918
1919      /* Create an enum type. */
1920      if ((type->hdf_typeid =  H5Tenum_create(type->u.e.base_hdf_typeid)) < 0)
1921        return NC_EHDFERR;
1922
1923      /* Add all the members to the HDF5 type. */
1924      for (enum_m = type->u.e.enum_memberenum_menum_m = enum_m->l.next)
1925        if (H5Tenum_insert(type->hdf_typeidenum_m->nameenum_m->value) < 0)
1926          return NC_EHDFERR;
1927    }
1928  else
1929    {
1930      LOG((0, "Unknown class: %d", type->nc_type_class));
1931      return NC_EBADTYPE;
1932    }
1933
1934  /* Commit the type. */
1935  if (H5Tcommit(grp->hdf_grpidtype->nametype->hdf_typeid) < 0)
1936    return NC_EHDFERR;
1937  type->committed = NC_TRUE;
1938  LOG((4, "just committed type %s, HDF typeid: 0x%x", type->name,
1939       type->hdf_typeid));
1940
1941  /* Later we will always use the native typeid. In this case, it is
1942   * a copy of the same type pointed to by hdf_typeid, but it's
1943   * easier to maintain a copy. */
1944  if ((type->native_hdf_typeid = H5Tget_native_type(type->hdf_typeid,
1945                                                    H5T_DIR_DEFAULT)) < 0)
1946    return NC_EHDFERR;
1947
1948  return NC_NOERR;
1949}
1950
1951/* Write an attribute, with value 1, to indicate that strict NC3 rules
1952 * apply to this file. */
1953static int
1954write_nc3_strict_att(hid_t hdf_grpid)
1955{
1956  hid_t attid = 0, spaceid = 0;
1957  int one = 1, numa;
1958  char att_name[NC_MAX_HDF5_NAME + 1];
1959  int retval = NC_NOERR;
1960  htri_t attr_exists;
1961
1962  /* If the attribute already exists, call that a success and return
1963   * NC_NOERR. */
1964  if ((attr_exists = H5Aexists(hdf_grpidNC3_STRICT_ATT_NAME)) < 0)
1965    return NC_EHDFERR;
1966  if (attr_exists)
1967    return NC_NOERR;
1968
1969  /* Create the attribute to mark this as a file that needs to obey
1970   * strict netcdf-3 rules. */
1971  if ((spaceid = H5Screate(H5S_SCALAR)) < 0)
1972    BAIL(NC_EFILEMETA);
1973#ifdef EXTRA_TESTS
1974  num_spaces++;
1975#endif
1976  if ((attid = H5Acreate(hdf_grpidNC3_STRICT_ATT_NAME,
1977                         H5T_NATIVE_INTspaceidH5P_DEFAULT)) < 0)
1978    BAIL(NC_EFILEMETA);
1979  if (H5Awrite(attidH5T_NATIVE_INT, &one) < 0)
1980    BAIL(NC_EFILEMETA);
1981
1982 exit:
1983  if (spaceid > 0 && (H5Sclose(spaceid) < 0))
1984    BAIL2(NC_EFILEMETA);
1985#ifdef EXTRA_TESTS
1986  num_spaces--;
1987#endif
1988  if (attid > 0 && (H5Aclose(attid) < 0))
1989    BAIL2(NC_EFILEMETA);
1990  return retval;
1991}
1992
1993static int
1994create_group(NC_GRP_INFO_T *grp)
1995{
1996  hid_t gcpl_id = 0;
1997  int retval = NC_NOERR;;
1998
1999  assert(grp);
2000
2001  /* If this is not the root group, create it in the HDF5 file. */
2002  if (grp->parent)
2003    {
2004      /* Create group, with link_creation_order set in the group
2005       * creation property list. */
2006      if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0)
2007        return NC_EHDFERR;
2008#ifdef EXTRA_TESTS
2009      num_plists++;
2010#endif
2011
2012      /* RJ: this suppose to be FALSE that is defined in H5 private.h as 0 */
2013      if (H5Pset_obj_track_times(gcpl_id,0)<0)
2014        BAIL(NC_EHDFERR);
2015
2016      if (H5Pset_link_creation_order(gcpl_idH5P_CRT_ORDER_TRACKED|H5P_CRT_ORDER_INDEXED) < 0)
2017        BAIL(NC_EHDFERR);
2018      if (H5Pset_attr_creation_order(gcpl_idH5P_CRT_ORDER_TRACKED|H5P_CRT_ORDER_INDEXED) < 0)
2019        BAIL(NC_EHDFERR);
2020      if ((grp->hdf_grpid = H5Gcreate2(grp->parent->hdf_grpidgrp->name,
2021                                       H5P_DEFAULTgcpl_idH5P_DEFAULT)) < 0)
2022        BAIL(NC_EHDFERR);
2023      if (H5Pclose(gcpl_id) < 0)
2024        BAIL(NC_EHDFERR);
2025#ifdef EXTRA_TESTS
2026      num_plists--;
2027#endif
2028    }
2029  else
2030    {
2031      /* Since this is the root group, we have to open it. */
2032      if ((grp->hdf_grpid = H5Gopen2(grp->nc4_info->hdfid, "/", H5P_DEFAULT)) < 0)
2033        BAIL(NC_EFILEMETA);
2034    }
2035  return NC_NOERR;
2036
2037 exit:
2038  if (gcpl_id > 0 && H5Pclose(gcpl_id) < 0)
2039    BAIL2(NC_EHDFERR);
2040#ifdef EXTRA_TESTS
2041  num_plists--;
2042#endif
2043  if (grp->hdf_grpid > 0 && H5Gclose(grp->hdf_grpid) < 0)
2044    BAIL2(NC_EHDFERR);
2045  return retval;
2046}
2047
2048/* After all the datasets of the file have been read, it's time to
2049 * sort the wheat from the chaff. Which of the datasets are netCDF
2050 * dimensions, and which are coordinate variables, and which are
2051 * non-coordinate variables. */
2052static int
2053attach_dimscales(NC_GRP_INFO_T *grp)
2054{
2055  NC_VAR_INFO_T *var;
2056  NC_DIM_INFO_T *dim1;
2057  NC_GRP_INFO_T *g;
2058  int d;
2059  int retval = NC_NOERR;
2060
2061  /* Attach dimension scales. */
2062  for (var = grp->varvarvar = var->l.next)
2063    {
2064      /* Scales themselves do not attach. But I really wish they
2065       * would. */
2066      if (var->dimscale)
2067        {
2068          /* If this is a multidimensional coordinate variable, it will
2069           * have a special coords attribute (read earlier) with a list
2070           * of the dimensions for this variable. */
2071        }
2072      else /* not a dimscale... */
2073        {
2074          /* Find the scale for each dimension and attach it. */
2075          for (d = 0; d < var->ndimsd++)
2076            {
2077              /* Is there a dimscale for this dimension? */
2078              if (var->dimscale_attached)
2079                {
2080                  if (!var->dimscale_attached[d])
2081                    {
2082                      hid_t dim_datasetid;  /* Dataset ID for dimension */
2083                      dim1 = var->dim[d];
2084       assert(dim1 && dim1->dimid == var->dimids[d]);
2085
2086                      LOG((2, "%s: attaching scale for dimid %d to var %s",
2087                           __func__var->dimids[d], var->name));
2088
2089                      /* Find dataset ID for dimension */
2090                      if (dim1->coord_var)
2091                        dim_datasetid = dim1->coord_var->hdf_datasetid;
2092                      else
2093                        dim_datasetid = dim1->hdf_dimscaleid;
2094                      assert(dim_datasetid > 0);
2095                      if (H5DSattach_scale(var->hdf_datasetiddim_datasetidd) < 0)
2096                        BAIL(NC_EHDFERR);
2097                      var->dimscale_attached[d] = NC_TRUE;
2098                    }
2099
2100   /* If we didn't find a dimscale to attach, that's a problem! */
2101   if (!var->dimscale_attached[d])
2102     {
2103       LOG((0, "no dimscale found!"));
2104       return NC_EDIMSCALE;
2105     }
2106                }
2107            }
2108        }
2109    }
2110
2111 exit:
2112  return retval;
2113}
2114
2115static int
2116var_exists(hid_t grpid, char *namenc_bool_t *exists)
2117{
2118  htri_t link_exists;
2119
2120  /* Reset the boolean */
2121  *exists = NC_FALSE;
2122
2123  /* Check if the object name exists in the group */
2124  if ((link_exists = H5Lexists(grpidnameH5P_DEFAULT)) < 0)
2125    return NC_EHDFERR;
2126  if (link_exists)
2127    {
2128      H5G_stat_t statbuf;
2129
2130      /* Get info about the object */
2131      if (H5Gget_objinfo(grpidname, 1, &statbuf) < 0)
2132        return NC_EHDFERR;
2133
2134      if (H5G_DATASET == statbuf.type)
2135        *exists = NC_TRUE;
2136    }
2137
2138  return NC_NOERR;
2139}
2140
2141/* This function writes a variable. The principle difficulty comes
2142 * from the possibility that this is a coordinate variable, and was
2143 * already written to the file as a dimension-only dimscale. If this
2144 * occurs, then it must be deleted and recreated. */
2145static int
2146write_var(NC_VAR_INFO_T *varNC_GRP_INFO_T *grpnc_bool_t write_dimid)
2147{
2148  nc_bool_t replace_existing_var = NC_FALSE;
2149  int retval;
2150
2151  LOG((4, "%s: writing var %s", __func__var->name));
2152
2153  /* If the variable has already been created & the fill value changed,
2154   * indicate that the existing variable should be replaced. */
2155  if (var->created && var->fill_val_changed)
2156    {
2157      replace_existing_var = NC_TRUE;
2158      var->fill_val_changed = NC_FALSE;
2159      /* If the variable is going to be replaced,
2160         we need to flag any other attributes associated
2161         with the variable as 'dirty', or else
2162         *only* the fill value attribute will be copied over
2163         and the rest will be lost.  See:
2164
2165         * https://github.com/Unidata/netcdf-c/issues/239 */
2166
2167      flag_atts_dirty(&var->att);
2168    }
2169
2170  /* Is this a coordinate var that has already been created in
2171   * the HDF5 file as a dimscale dataset? Check for dims with the
2172   * same name in this group. If there is one, check to see if
2173   * this object exists in the HDF group. */
2174  if (var->became_coord_var)
2175    {
2176      NC_DIM_INFO_T *d1;
2177
2178      for (d1 = grp->dimd1d1 = d1->l.next)
2179        if (!strcmp(d1->namevar->name))
2180          {
2181            nc_bool_t exists;
2182
2183            if ((retval = var_exists(grp->hdf_grpidvar->name, &exists)))
2184              return retval;
2185            if (exists)
2186              {
2187                /* Indicate that the variable already exists, and should be replaced */
2188                replace_existing_var = NC_TRUE;
2189                flag_atts_dirty(&var->att);
2190                break;
2191              }
2192          }
2193    }
2194
2195  /* Check dims if the variable will be replaced, so that the dimensions
2196   * will be de-attached and re-attached correctly. */
2197  /* (Note: There's a temptation to merge this loop over the dimensions with
2198   *        the prior loop over dimensions, but that blurs the line over the
2199   *        purpose of them, so they are currently separate.  If performance
2200   *        becomes an issue here, it would be possible to merge them. -QAK)
2201   */
2202  if (replace_existing_var)
2203    {
2204      NC_DIM_INFO_T *d1;
2205
2206      for (d1 = grp->dimd1d1 = d1->l.next)
2207        if (!strcmp(d1->namevar->name))
2208          {
2209            nc_bool_t exists;
2210
2211            if ((retval = var_exists(grp->hdf_grpidvar->name, &exists)))
2212              return retval;
2213            if (exists)
2214              {
2215                hid_t dim_datasetid;  /* Dataset ID for dimension */
2216
2217                /* Find dataset ID for dimension */
2218                if (d1->coord_var)
2219                  dim_datasetid = d1->coord_var->hdf_datasetid;
2220                else
2221                  dim_datasetid = d1->hdf_dimscaleid;
2222                assert(dim_datasetid > 0);
2223
2224                /* If we're replacing an existing dimscale dataset, go to
2225                 * every var in the file and detach this dimension scale,
2226                 * because we have to delete it. */
2227                if ((retval = rec_detach_scales(grp->nc4_info->root_grp,
2228                                                var->dimids[0], dim_datasetid)))
2229                  return retval;
2230                break;
2231              }
2232          }
2233    }
2234
2235  /* If this is not a dimension scale, do this stuff. */
2236  if (var->was_coord_var && var->dimscale_attached)
2237    {
2238      /* If the variable already exists in the file, Remove any dimension scale
2239       * attributes from it, if they exist. */
2240      /* (The HDF5 Dimension Scale API should really have an API routine
2241       * for making a dataset not a scale. -QAK) */
2242      if (var->created)
2243        {
2244          htri_t attr_exists;
2245
2246          /* (We could do a better job here and verify that the attributes are
2247           * really dimension scale 'CLASS' & 'NAME' attributes, but that would be
2248           * poking about in the HDF5 DimScale internal data) */
2249          if ((attr_exists = H5Aexists(var->hdf_datasetid, "CLASS")) < 0)
2250            BAIL(NC_EHDFERR);
2251          if (attr_exists)
2252            {
2253              if (H5Adelete(var->hdf_datasetid, "CLASS") < 0)
2254                BAIL(NC_EHDFERR);
2255            }
2256          if ((attr_exists = H5Aexists(var->hdf_datasetid, "NAME")) < 0)
2257            BAIL(NC_EHDFERR);
2258          if (attr_exists)
2259            {
2260              if (H5Adelete(var->hdf_datasetid, "NAME") < 0)
2261                BAIL(NC_EHDFERR);
2262            }
2263        }
2264
2265      if (var->dimscale_attached)
2266        {
2267          int d;
2268
2269          /* If this is a regular var, detach all its dim scales. */
2270          for (d = 0; d < var->ndimsd++)
2271            if (var->dimscale_attached[d])
2272              {
2273                hid_t dim_datasetid;  /* Dataset ID for dimension */
2274                NC_DIM_INFO_T *dim1 = var->dim[d];
2275 assert(dim1 && dim1->dimid == var->dimids[d]);
2276
2277                /* Find dataset ID for dimension */
2278                if (dim1->coord_var)
2279                  dim_datasetid = dim1->coord_var->hdf_datasetid;
2280                else
2281                  dim_datasetid = dim1->hdf_dimscaleid;
2282                assert(dim_datasetid > 0);
2283
2284                if (H5DSdetach_scale(var->hdf_datasetiddim_datasetidd) < 0)
2285                  BAIL(NC_EHDFERR);
2286                var->dimscale_attached[d] = NC_FALSE;
2287              }
2288        }
2289    }
2290
2291  /* Delete the HDF5 dataset that is to be replaced. */
2292  if (replace_existing_var)
2293    {
2294      /* Free the HDF5 dataset id. */
2295      if (var->hdf_datasetid && H5Dclose(var->hdf_datasetid) < 0)
2296        BAIL(NC_EHDFERR);
2297      var->hdf_datasetid = 0;
2298
2299      /* Now delete the variable. */
2300      if (H5Gunlink(grp->hdf_grpidvar->name) < 0)
2301        return NC_EDIMMETA;
2302    }
2303
2304  /* Create the dataset. */
2305  if (var->is_new_var || replace_existing_var)
2306    {
2307      if ((retval = var_create_dataset(grpvarwrite_dimid)))
2308        return retval;
2309    }
2310  else
2311    {
2312      if (write_dimid && var->ndims)
2313        if ((retval = write_netcdf4_dimid(var->hdf_datasetidvar->dimids[0])))
2314          BAIL(retval);
2315    }
2316
2317  if (replace_existing_var)
2318    {
2319      /* If this is a dimension scale, reattach the scale everywhere it
2320       * is used. (Recall that netCDF dimscales are always 1-D). */
2321      if(var->dimscale)
2322        {
2323          if ((retval = rec_reattach_scales(grp->nc4_info->root_grp,
2324                                            var->dimids[0], var->hdf_datasetid)))
2325            return retval;
2326        }
2327      /* If it's not a dimension scale, clear the dimscale attached flags,
2328       * so the dimensions are re-attached. */
2329      else
2330        {
2331          if (var->dimscale_attached)
2332            memset(var->dimscale_attached, 0, sizeof(nc_bool_t) * var->ndims);
2333        }
2334    }
2335
2336  /* Clear coord. var state transition flags */
2337  var->was_coord_var = NC_FALSE;
2338  var->became_coord_var = NC_FALSE;
2339
2340  /* Now check the attributes for this var. */
2341  if (var->attr_dirty)
2342    {
2343      /* Write attributes for this var. */
2344      if ((retval = write_attlist(var->attvar->varidgrp)))
2345        BAIL(retval);
2346      var->attr_dirty = NC_FALSE;
2347    }
2348
2349  return NC_NOERR;
2350 exit:
2351  return retval;
2352}
2353
2354static int
2355write_dim(NC_DIM_INFO_T *dimNC_GRP_INFO_T *grpnc_bool_t write_dimid)
2356{
2357  int retval;
2358
2359  /* If there's no dimscale dataset for this dim, create one,
2360   * and mark that it should be hidden from netCDF as a
2361   * variable. (That is, it should appear as a dimension
2362   * without an associated variable.) */
2363  if (0 == dim->hdf_dimscaleid)
2364    {
2365      hid_t spaceidcreate_propid;
2366      hsize_t dims[1], max_dims[1], chunk_dims[1] = {1};
2367      char dimscale_wo_var[NC_MAX_NAME];
2368
2369      LOG((4, "%s: creating dim %s", __func__dim->name));
2370
2371      /* Sanity check */
2372      assert(NULL == dim->coord_var);
2373
2374      /* Create a property list. If this dimension scale is
2375       * unlimited (i.e. it's an unlimited dimension), then set
2376       * up chunking, with a chunksize of 1. */
2377      if ((create_propid = H5Pcreate(H5P_DATASET_CREATE)) < 0)
2378        BAIL(NC_EHDFERR);
2379#ifdef EXTRA_TESTS
2380      num_plists++;
2381#endif
2382
2383      /* RJ: this suppose to be FALSE that is defined in H5 private.h as 0 */
2384      if (H5Pset_obj_track_times(create_propid,0)<0)
2385        BAIL(NC_EHDFERR);
2386
2387      dims[0] = dim->len;
2388      max_dims[0] = dim->len;
2389      if (dim->unlimited)
2390        {
2391          max_dims[0] = H5S_UNLIMITED;
2392          if (H5Pset_chunk(create_propid, 1, chunk_dims) < 0)
2393            BAIL(NC_EHDFERR);
2394        }
2395
2396      /* Set up space. */
2397      if ((spaceid = H5Screate_simple(1, dimsmax_dims)) < 0)
2398        BAIL(NC_EHDFERR);
2399#ifdef EXTRA_TESTS
2400      num_spaces++;
2401#endif
2402
2403      if (H5Pset_attr_creation_order(create_propidH5P_CRT_ORDER_TRACKED|
2404                                     H5P_CRT_ORDER_INDEXED) < 0)
2405        BAIL(NC_EHDFERR);
2406
2407      /* Create the dataset that will be the dimension scale. */
2408      LOG((4, "%s: about to H5Dcreate1 a dimscale dataset %s", __func__dim->name));
2409      if ((dim->hdf_dimscaleid = H5Dcreate1(grp->hdf_grpiddim->nameH5T_IEEE_F32BE,
2410                                            spaceidcreate_propid)) < 0)
2411        BAIL(NC_EHDFERR);
2412
2413      /* Close the spaceid and create_propid. */
2414      if (H5Sclose(spaceid) < 0)
2415        BAIL(NC_EHDFERR);
2416#ifdef EXTRA_TESTS
2417      num_spaces--;
2418#endif
2419      if (H5Pclose(create_propid) < 0)
2420        BAIL(NC_EHDFERR);
2421#ifdef EXTRA_TESTS
2422      num_plists--;
2423#endif
2424
2425      /* Indicate that this is a scale. Also indicate that not
2426       * be shown to the user as a variable. It is hidden. It is
2427       * a DIM WITHOUT A VARIABLE! */
2428      sprintf(dimscale_wo_var, "%s%10d", DIM_WITHOUT_VARIABLE, (int)dim->len);
2429      if (H5DSset_scale(dim->hdf_dimscaleiddimscale_wo_var) < 0)
2430        BAIL(NC_EHDFERR);
2431    }
2432
2433  /* Did we extend an unlimited dimension? */
2434  if (dim->extended)
2435    {
2436      NC_VAR_INFO_T *v1;
2437
2438      assert(dim->unlimited);
2439      /* If this is a dimension without a variable, then update
2440       * the secret length information at the end of the NAME
2441       * attribute. */
2442      for (v1 = grp->varv1v1 = v1->l.next)
2443        if (!strcmp(v1->namedim->name))
2444          break;
2445
2446      if (v1)
2447        {
2448          hsize_t *new_size = NULL;
2449          NC_DIM_INFO_T *dim1;
2450          int d1;
2451
2452          /* Extend the dimension scale dataset to reflect the new
2453           * length of the dimension. */
2454          if (!(new_size = malloc(v1->ndims * sizeof(hsize_t))))
2455            BAIL(NC_ENOMEM);
2456          for (d1 = 0; d1 < v1->ndimsd1++)
2457            {
2458       assert(v1->dim[d1] && v1->dim[d1]->dimid == v1->dimids[d1]);
2459       new_size[d1] = v1->dim[d1]->len;
2460            }
2461          if (H5Dset_extent(v1->hdf_datasetidnew_size) < 0) {
2462            free(new_size);
2463            BAIL(NC_EHDFERR);
2464          }
2465          free(new_size);
2466        }
2467    }
2468
2469  /* If desired, write the secret dimid. This will be used instead of
2470   * the dimid that the dimension would otherwise receive based on
2471   * creation order. This can be necessary when dims and their
2472   * coordinate variables were created in different order. */
2473  if (write_dimid && dim->hdf_dimscaleid)
2474    if ((retval = write_netcdf4_dimid(dim->hdf_dimscaleiddim->dimid)))
2475      BAIL(retval);
2476
2477  return NC_NOERR;
2478 exit:
2479
2480  return retval;
2481}
2482
2483/* Recursively determine if there is a mismatch between order of
2484 * coordinate creation and associated dimensions in this group or any
2485 * subgroups, to find out if we have to handle that situation.  Also
2486 * check if there are any multidimensional coordinate variables
2487 * defined, which require the same treatment to fix a potential bug
2488 * when such variables occur in subgroups. */
2489int
2490nc4_rec_detect_need_to_preserve_dimids(NC_GRP_INFO_T *grpnc_bool_t *bad_coord_orderp)
2491{
2492  NC_VAR_INFO_T *var;
2493  NC_GRP_INFO_T *child_grp;
2494  int last_dimid = -1;
2495  int retval;
2496
2497  /* Iterate over variables in this group */
2498  for (var = grp->varvarvar = var->l.next)
2499    {
2500      /* Only matters for dimension scale variables, with non-scalar dimensionality */
2501      if (var->dimscale && var->ndims)
2502        {
2503          /* If the user writes coord vars in a different order then he
2504           * defined their dimensions, then, when the file is reopened, the
2505           * order of the dimids will change to match the order of the coord
2506           * vars. Detect if this is about to happen. */
2507          if (var->dimids[0] < last_dimid)
2508            {
2509              LOG((5, "%s: %s is out of order coord var", __func__var->name));
2510              *bad_coord_orderp = NC_TRUE;
2511              return NC_NOERR;
2512            }
2513          last_dimid = var->dimids[0];
2514
2515          /* If there are multidimensional coordinate variables defined, then
2516           * it's also necessary to preserve dimension IDs when the file is
2517           * reopened ... */
2518          if (var->ndims > 1)
2519            {
2520              LOG((5, "%s: %s is multidimensional coord var", __func__var->name));
2521              *bad_coord_orderp = NC_TRUE;
2522              return NC_NOERR;
2523            }
2524
2525          /* Did the user define a dimension, end define mode, reenter define
2526           * mode, and then define a coordinate variable for that dimension?
2527           * If so, dimensions will be out of order. */
2528          if (var->is_new_var || var->became_coord_var)
2529            {
2530              LOG((5, "%s: coord var defined after enddef/redef", __func__));
2531              *bad_coord_orderp = NC_TRUE;
2532              return NC_NOERR;
2533            }
2534        }
2535    }
2536
2537  /* If there are any child groups, check them also for this condition. */
2538  for (child_grp = grp->childrenchild_grpchild_grp = child_grp->l.next)
2539    if ((retval = nc4_rec_detect_need_to_preserve_dimids(child_grpbad_coord_orderp)))
2540      return retval;
2541
2542  return NC_NOERR;
2543}
2544
2545
2546/* Recursively write all the metadata in a group. Groups and types
2547 * have all already been written.  Propagate bad cooordinate order to
2548 * subgroups, if detected. */
2549int
2550nc4_rec_write_metadata(NC_GRP_INFO_T *grpnc_bool_t bad_coord_order)
2551{
2552  NC_DIM_INFO_T *dim;
2553  NC_VAR_INFO_T *var;
2554  NC_GRP_INFO_T *child_grp;
2555  int coord_varid = -1;
2556
2557  int retval;
2558  assert(grp && grp->name && grp->hdf_grpid);
2559  LOG((3, "%s: grp->name %s, bad_coord_order %d", __func__grp->namebad_coord_order));
2560
2561  /* Write global attributes for this group. */
2562  if ((retval = write_attlist(grp->attNC_GLOBALgrp)))
2563    return retval;
2564  /* Set the pointers to the beginning of the list of dims & vars in this
2565   * group. */
2566  dim = grp->dim;
2567  var = grp->var;
2568
2569  /* Because of HDF5 ordering the dims and vars have to be stored in
2570   * this way to ensure that the dims and coordinate vars come out in
2571   * the correct order. */
2572  while (dim || var)
2573    {
2574      nc_bool_t found_coordwrote_coord;
2575
2576      /* Write non-coord dims in order, stopping at the first one that
2577       * has an associated coord var. */
2578      for (found_coord = NC_FALSEdim && !found_coorddim = dim->l.next)
2579        {
2580          if (!dim->coord_var)
2581            {
2582              if ((retval = write_dim(dimgrpbad_coord_order)))
2583                return retval;
2584            }
2585          else
2586            {
2587              coord_varid = dim->coord_var->varid;
2588              found_coord = NC_TRUE;
2589            }
2590        }
2591
2592      /* Write each var. When we get to the coord var we are waiting
2593       * for (if any), then we break after writing it. */
2594      for (wrote_coord = NC_FALSEvar && !wrote_coordvar = var->l.next)
2595        {
2596          if ((retval = write_var(vargrpbad_coord_order)))
2597            return retval;
2598          if (found_coord && var->varid == coord_varid)
2599            wrote_coord = NC_TRUE;
2600        }
2601    } /* end while */
2602
2603  if ((retval = attach_dimscales(grp)))
2604    return retval;
2605
2606  /* If there are any child groups, write their metadata. */
2607  for (child_grp = grp->childrenchild_grpchild_grp = child_grp->l.next)
2608    if ((retval = nc4_rec_write_metadata(child_grpbad_coord_order)))
2609      return retval;
2610
2611  return NC_NOERR;
2612}
2613
2614/* Recursively write all groups and types. */
2615int
2616nc4_rec_write_groups_types(NC_GRP_INFO_T *grp)
2617{
2618  NC_GRP_INFO_T *child_grp;
2619  NC_TYPE_INFO_T *type;
2620  int retval;
2621
2622  assert(grp && grp->name);
2623  LOG((3, "%s: grp->name %s", __func__grp->name));
2624
2625  /* Create the group in the HDF5 file if it doesn't exist. */
2626  if (!grp->hdf_grpid)
2627    if ((retval = create_group(grp)))
2628      return retval;
2629
2630  /* If this is the root group of a file with strict NC3 rules, write
2631   * an attribute. But don't leave the attribute open. */
2632  if (!grp->parent && (grp->nc4_info->cmode & NC_CLASSIC_MODEL))
2633    if ((retval = write_nc3_strict_att(grp->hdf_grpid)))
2634      return retval;
2635
2636  /* If there are any user-defined types, write them now. */
2637  for (type = grp->typetypetype = type->l.next)
2638    if ((retval = commit_type(grptype)))
2639      return retval;
2640
2641  /* If there are any child groups, write their groups and types. */
2642  for (child_grp = grp->childrenchild_grpchild_grp = child_grp->l.next)
2643    if ((retval = nc4_rec_write_groups_types(child_grp)))
2644      return retval;
2645
2646  return NC_NOERR;
2647}
2648
2649/*! Copy data from one buffer to another, performing appropriate data conversion.
2650
2651  This function will copy data from one buffer to another, in
2652  accordance with the types. Range errors will be noted, and the fill
2653  value used (or the default fill value if none is supplied) for
2654  values that overflow the type.
2655
2656  I should be able to take this out when HDF5 does the right thing
2657  with data type conversion.
2658
2659  Ed Hartnett, 11/15/3
2660*/
2661int
2662nc4_convert_type(const void *src, void *dest,
2663                 const nc_type src_type, const nc_type dest_type,
2664                 const size_t len, int *range_error,
2665                 const void *fill_value, int strict_nc3, int src_long,
2666                 int dest_long)
2667{
2668  char *cp, *cp1;
2669  float *fp, *fp1;
2670  double *dp, *dp1;
2671  int *ip, *ip1;
2672  signed long *lp, *lp1;
2673  short *sp, *sp1;
2674  signed char *bp, *bp1;
2675  unsigned char *ubp, *ubp1;
2676  unsigned short *usp, *usp1;
2677  unsigned int *uip, *uip1;
2678  long long *lip, *lip1;
2679  unsigned long long *ulip, *ulip1;
2680  size_t count = 0;
2681
2682  *range_error = 0;
2683  LOG((3, "%s: len %d src_type %d dest_type %d src_long %d dest_long %d",
2684       __func__lensrc_typedest_typesrc_longdest_long));
2685
2686  /* OK, this is ugly. If you can think of anything better, I'm open
2687     to suggestions!
2688
2689     Note that we don't use a default fill value for type
2690     NC_BYTE. This is because Lord Voldemort cast a nofilleramous spell
2691     at Harry Potter, but it bounced off his scar and hit the netcdf-4
2692     code.
2693  */
2694  switch (src_type)
2695    {
2696    case NC_CHAR:
2697      switch (dest_type)
2698        {
2699        case NC_CHAR:
2700          for (cp = (char *)srccp1 = destcount < lencount++)
2701            *cp1++ = *cp++;
2702          break;
2703        default:
2704          LOG((0, "%s: Uknown destination type.", __func__));
2705        }
2706      break;
2707
2708    case NC_BYTE:
2709      switch (dest_type)
2710        {
2711        case NC_BYTE:
2712          for (bp = (signed char *)srcbp1 = destcount < lencount++)
2713            *bp1++ = *bp++;
2714          break;
2715        case NC_UBYTE:
2716          for (bp = (signed char *)srcubp = destcount < lencount++)
2717            {
2718              if (*bp < 0)
2719                (*range_error)++;
2720              *ubp++ = *bp++;
2721            }
2722          break;
2723        case NC_SHORT:
2724          for (bp = (signed char *)srcsp = destcount < lencount++)
2725            *sp++ = *bp++;
2726          break;
2727        case NC_USHORT:
2728          for (bp = (signed char *)srcusp = destcount < lencount++)
2729            {
2730              if (*bp < 0)
2731                (*range_error)++;
2732              *usp++ = *bp++;
2733            }
2734          break;
2735        case NC_INT:
2736          if (dest_long)
2737            {
2738              for (bp = (signed char *)srclp = destcount < lencount++)
2739                *lp++ = *bp++;
2740              break;
2741            }
2742          else
2743            {
2744              for (bp = (signed char *)srcip = destcount < lencount++)
2745                *ip++ = *bp++;
2746              break;
2747            }
2748        case NC_UINT:
2749          for (bp = (signed char *)srcuip = destcount < lencount++)
2750            {
2751              if (*bp < 0)
2752                (*range_error)++;
2753              *uip++ = *bp++;
2754            }
2755          break;
2756        case NC_INT64:
2757          for (bp = (signed char *)srclip = destcount < lencount++)
2758            *lip++ = *bp++;
2759          break;
2760        case NC_UINT64:
2761          for (bp = (signed char *)srculip = destcount < lencount++)
2762            {
2763              if (*bp < 0)
2764                (*range_error)++;
2765              *ulip++ = *bp++;
2766            }
2767          break;
2768        case NC_FLOAT:
2769          for (bp = (signed char *)srcfp = destcount < lencount++)
2770            *fp++ = *bp++;
2771          break;
2772        case NC_DOUBLE:
2773          for (bp = (signed char *)srcdp = destcount < lencount++)
2774            *dp++ = *bp++;
2775          break;
2776        default:
2777          LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d",
2778               __func__src_typedest_type));
2779          return NC_EBADTYPE;
2780        }
2781      break;
2782
2783    case NC_UBYTE:
2784      switch (dest_type)
2785        {
2786        case NC_BYTE:
2787          for (ubp = (unsigned char *)srcbp = destcount < lencount++)
2788            {
2789              if (!strict_nc3 && *ubp > X_SCHAR_MAX)
2790                (*range_error)++;
2791              *bp++ = *ubp++;
2792            }
2793          break;
2794        case NC_SHORT:
2795          for (ubp = (unsigned char *)srcsp = destcount < lencount++)
2796            *sp++ = *ubp++;
2797          break;
2798        case NC_UBYTE:
2799          for (ubp = (unsigned char *)srcubp1 = destcount < lencount++)
2800            *ubp1++ = *ubp++;
2801          break;
2802        case NC_USHORT:
2803          for (ubp = (unsigned char *)srcusp = destcount < lencount++)
2804            *usp++ = *ubp++;
2805          break;
2806        case NC_INT:
2807          if (dest_long)
2808            {
2809              for (ubp = (unsigned char *)srclp = destcount < lencount++)
2810                *lp++ = *ubp++;
2811              break;
2812            }
2813          else
2814            {
2815              for (ubp = (unsigned char *)srcip = destcount < lencount++)
2816                *ip++ = *ubp++;
2817              break;
2818            }
2819        case NC_UINT:
2820          for (ubp = (unsigned char *)srcuip = destcount < lencount++)
2821            *uip++ = *ubp++;
2822          break;
2823        case NC_INT64:
2824          for (ubp = (unsigned char *)srclip = destcount < lencount++)
2825            *lip++ = *ubp++;
2826          break;
2827        case NC_UINT64:
2828          for (ubp = (unsigned char *)srculip = destcount < lencount++)
2829            *ulip++ = *ubp++;
2830          break;
2831        case NC_FLOAT:
2832          for (ubp = (unsigned char *)srcfp = destcount < lencount++)
2833            *fp++ = *ubp++;
2834          break;
2835        case NC_DOUBLE:
2836          for (ubp = (unsigned char *)srcdp = destcount < lencount++)
2837            *dp++ = *ubp++;
2838          break;
2839        default:
2840          LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d",
2841               __func__src_typedest_type));
2842          return NC_EBADTYPE;
2843        }
2844      break;
2845
2846    case NC_SHORT:
2847      switch (dest_type)
2848        {
2849        case NC_UBYTE:
2850          for (sp = (short *)srcubp = destcount < lencount++)
2851            {
2852              if (*sp > X_UCHAR_MAX || *sp < 0)
2853                (*range_error)++;
2854              *ubp++ = *sp++;
2855            }
2856          break;
2857        case NC_BYTE:
2858          for (sp = (short *)srcbp = destcount < lencount++)
2859            {
2860              if (*sp > X_SCHAR_MAX || *sp < X_SCHAR_MIN)
2861                (*range_error)++;
2862              *bp++ = *sp++;
2863            }
2864          break;
2865        case NC_SHORT:
2866          for (sp = (short *)srcsp1 = destcount < lencount++)
2867            *sp1++ = *sp++;
2868          break;
2869        case NC_USHORT:
2870          for (sp = (short *)srcusp = destcount < lencount++)
2871            {
2872              if (*sp < 0)
2873                (*range_error)++;
2874              *usp++ = *sp++;
2875            }
2876          break;
2877        case NC_INT:
2878          if (dest_long)
2879            for (sp = (short *)srclp = destcount < lencount++)
2880              *lp++ = *sp++;
2881          else
2882            for (sp = (short *)srcip = destcount < lencount++)
2883              *ip++ = *sp++;
2884          break;
2885        case NC_UINT:
2886          for (sp = (short *)srcuip = destcount < lencount++)
2887            {
2888              if (*sp < 0)
2889                (*range_error)++;
2890              *uip++ = *sp++;
2891            }
2892          break;
2893        case NC_INT64:
2894          for (sp = (short *)srclip = destcount < lencount++)
2895            *lip++ = *sp++;
2896          break;
2897        case NC_UINT64:
2898          for (sp = (short *)srculip = destcount < lencount++)
2899            {
2900              if (*sp < 0)
2901                (*range_error)++;
2902              *ulip++ = *sp++;
2903            }
2904          break;
2905        case NC_FLOAT:
2906          for (sp = (short *)srcfp = destcount < lencount++)
2907            *fp++ = *sp++;
2908          break;
2909        case NC_DOUBLE:
2910          for (sp = (short *)srcdp = destcount < lencount++)
2911            *dp++ = *sp++;
2912          break;
2913        default:
2914          LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d",
2915               __func__src_typedest_type));
2916          return NC_EBADTYPE;
2917        }
2918      break;
2919
2920    case NC_USHORT:
2921      switch (dest_type)
2922        {
2923        case NC_UBYTE:
2924          for (usp = (unsigned short *)srcubp = destcount < lencount++)
2925            {
2926              if (*usp > X_UCHAR_MAX)
2927                (*range_error)++;
2928              *ubp++ = *usp++;
2929            }
2930          break;
2931        case NC_BYTE:
2932          for (usp = (unsigned short *)srcbp = destcount < lencount++)
2933            {
2934              if (*usp > X_SCHAR_MAX)
2935                (*range_error)++;
2936              *bp++ = *usp++;
2937            }
2938          break;
2939        case NC_SHORT:
2940          for (usp = (unsigned short *)srcsp = destcount < lencount++)
2941            {
2942              if (*usp > X_SHORT_MAX)
2943                (*range_error)++;
2944              *sp++ = *usp++;
2945            }
2946          break;
2947        case NC_USHORT:
2948          for (usp = (unsigned short *)srcusp1 = destcount < lencount++)
2949            *usp1++ = *usp++;
2950          break;
2951        case NC_INT:
2952          if (dest_long)
2953            for (usp = (unsigned short *)srclp = destcount < lencount++)
2954              *lp++ = *usp++;
2955          else
2956            for (usp = (unsigned short *)srcip = destcount < lencount++)
2957              *ip++ = *usp++;
2958          break;
2959        case NC_UINT:
2960          for (usp = (unsigned short *)srcuip = destcount < lencount++)
2961            *uip++ = *usp++;
2962          break;
2963        case NC_INT64:
2964          for (usp = (unsigned short *)srclip = destcount < lencount++)
2965            *lip++ = *usp++;
2966          break;
2967        case NC_UINT64:
2968          for (usp = (unsigned short *)srculip = destcount < lencount++)
2969            *ulip++ = *usp++;
2970          break;
2971        case NC_FLOAT:
2972          for (usp = (unsigned short *)srcfp = destcount < lencount++)
2973            *fp++ = *usp++;
2974          break;
2975        case NC_DOUBLE:
2976          for (usp = (unsigned short *)srcdp = destcount < lencount++)
2977            *dp++ = *usp++;
2978          break;
2979        default:
2980          LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d",
2981               __func__src_typedest_type));
2982          return NC_EBADTYPE;
2983        }
2984      break;
2985
2986    case NC_INT:
2987      if (src_long)
2988        {
2989          switch (dest_type)
2990            {
2991            case NC_UBYTE:
2992              for (lp = (long *)srcubp = destcount < lencount++)
2993                {
2994                  if (*lp > X_UCHAR_MAX || *lp < 0)
2995                    (*range_error)++;
2996                  *ubp++ = *lp++;
2997                }
2998              break;
2999            case NC_BYTE:
3000              for (lp = (long *)srcbp = destcount < lencount++)
3001                {
3002                  if (*lp > X_SCHAR_MAX || *lp < X_SCHAR_MIN)
3003                    (*range_error)++;
3004                  *bp++ = *lp++;
3005                }
3006              break;
3007            case NC_SHORT:
3008              for (lp = (long *)srcsp = destcount < lencount++)
3009                {
3010                  if (*lp > X_SHORT_MAX || *lp < X_SHORT_MIN)
3011                    (*range_error)++;
3012                  *sp++ = *lp++;
3013                }
3014              break;
3015            case NC_USHORT:
3016              for (lp = (long *)srcusp = destcount < lencount++)
3017                {
3018                  if (*lp > X_USHORT_MAX || *lp < 0)
3019                    (*range_error)++;
3020                  *usp++ = *lp++;
3021                }
3022              break;
3023            case NC_INT: /* src is long */
3024              if (dest_long)
3025                {
3026                  for (lp = (long *)srclp1 = destcount < lencount++)
3027                    {
3028                      if (*lp > X_LONG_MAX || *lp < X_LONG_MIN)
3029                        (*range_error)++;
3030                      *lp1++ = *lp++;
3031                    }
3032                }
3033              else /* dest is int */
3034                {
3035                  for (lp = (long *)srcip = destcount < lencount++)
3036                    {
3037                      if (*lp > X_INT_MAX || *lp < X_INT_MIN)
3038                        (*range_error)++;
3039                      *ip++ = *lp++;
3040                    }
3041                }
3042              break;
3043            case NC_UINT:
3044              for (lp = (long *)srcuip = destcount < lencount++)
3045                {
3046                  if (*lp > X_UINT_MAX || *lp < 0)
3047                    (*range_error)++;
3048                  *uip++ = *lp++;
3049                }
3050              break;
3051            case NC_INT64:
3052              for (lp = (long *)srclip = destcount < lencount++)
3053                *lip++ = *lp++;
3054              break;
3055            case NC_UINT64:
3056              for (lp = (long *)srculip = destcount < lencount++)
3057                {
3058                  if (*lp < 0)
3059                    (*range_error)++;
3060                  *ulip++ = *lp++;
3061                }
3062              break;
3063            case NC_FLOAT:
3064              for (lp = (long *)srcfp = destcount < lencount++)
3065                *fp++ = *lp++;
3066              break;
3067            case NC_DOUBLE:
3068              for (lp = (long *)srcdp = destcount < lencount++)
3069                *dp++ = *lp++;
3070              break;
3071            default:
3072              LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d",
3073                   __func__src_typedest_type));
3074              return NC_EBADTYPE;
3075            }
3076        }
3077      else
3078        {
3079          switch (dest_type)
3080            {
3081            case NC_UBYTE:
3082              for (ip = (int *)srcubp = destcount < lencount++)
3083                {
3084                  if (*ip > X_UCHAR_MAX || *ip < 0)
3085                    (*range_error)++;
3086                  *ubp++ = *ip++;
3087                }
3088              break;
3089            case NC_BYTE:
3090              for (ip = (int *)srcbp = destcount < lencount++)
3091                {
3092                  if (*ip > X_SCHAR_MAX || *ip < X_SCHAR_MIN)
3093                    (*range_error)++;
3094                  *bp++ = *ip++;
3095                }
3096              break;
3097            case NC_SHORT:
3098              for (ip = (int *)srcsp = destcount < lencount++)
3099                {
3100                  if (*ip > X_SHORT_MAX || *ip < X_SHORT_MIN)
3101                    (*range_error)++;
3102                  *sp++ = *ip++;
3103                }
3104              break;
3105            case NC_USHORT:
3106              for (ip = (int *)srcusp = destcount < lencount++)
3107                {
3108                  if (*ip > X_USHORT_MAX || *ip < 0)
3109                    (*range_error)++;
3110                  *usp++ = *ip++;
3111                }
3112              break;
3113            case NC_INT: /* src is int */
3114              if (dest_long)
3115                {
3116                  for (ip = (int *)srclp1 = destcount < lencount++)
3117                    {
3118                      if (*ip > X_LONG_MAX || *ip < X_LONG_MIN)
3119                        (*range_error)++;
3120                      *lp1++ = *ip++;
3121                    }
3122                }
3123              else /* dest is int */
3124                {
3125                  for (ip = (int *)srcip1 = destcount < lencount++)
3126                    {
3127                      if (*ip > X_INT_MAX || *ip < X_INT_MIN)
3128                        (*range_error)++;
3129                      *ip1++ = *ip++;
3130                    }
3131                }
3132              break;
3133            case NC_UINT:
3134              for (ip = (int *)srcuip = destcount < lencount++)
3135                {
3136                  if (*ip > X_UINT_MAX || *ip < 0)
3137                    (*range_error)++;
3138                  *uip++ = *ip++;
3139                }
3140              break;
3141            case NC_INT64:
3142              for (ip = (int *)srclip = destcount < lencount++)
3143                *lip++ = *ip++;
3144              break;
3145            case NC_UINT64:
3146              for (ip = (int *)srculip = destcount < lencount++)
3147                {
3148                  if (*ip < 0)
3149                    (*range_error)++;
3150                  *ulip++ = *ip++;
3151                }
3152              break;
3153            case NC_FLOAT:
3154              for (ip = (int *)srcfp = destcount < lencount++)
3155                *fp++ = *ip++;
3156              break;
3157            case NC_DOUBLE:
3158              for (ip = (int *)srcdp = destcount < lencount++)
3159                *dp++ = *ip++;
3160              break;
3161            default:
3162              LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d",
3163                   __func__src_typedest_type));
3164              return NC_EBADTYPE;
3165            }
3166        }
3167      break;
3168
3169    case NC_UINT:
3170      switch (dest_type)
3171        {
3172        case NC_UBYTE:
3173          for (uip = (unsigned int *)srcubp = destcount < lencount++)
3174            {
3175              if (*uip > X_UCHAR_MAX)
3176                (*range_error)++;
3177              *ubp++ = *uip++;
3178            }
3179          break;
3180        case NC_BYTE:
3181          for (uip = (unsigned int *)srcbp = destcount < lencount++)
3182            {
3183              if (*uip > X_SCHAR_MAX)
3184                (*range_error)++;
3185              *bp++ = *uip++;
3186            }
3187          break;
3188        case NC_SHORT:
3189          for (uip = (unsigned int *)srcsp = destcount < lencount++)
3190            {
3191              if (*uip > X_SHORT_MAX)
3192                (*range_error)++;
3193              *sp++ = *uip++;
3194            }
3195          break;
3196        case NC_USHORT:
3197          for (uip = (unsigned int *)srcusp = destcount < lencount++)
3198            {
3199              if (*uip > X_USHORT_MAX)
3200                (*range_error)++;
3201              *usp++ = *uip++;
3202            }
3203          break;
3204        case NC_INT:
3205          if (dest_long)
3206            for (uip = (unsigned int *)srclp = destcount < lencount++)
3207              {
3208                if (*uip > X_LONG_MAX)
3209                  (*range_error)++;
3210                *lp++ = *uip++;
3211              }
3212          else
3213            for (uip = (unsigned int *)srcip = destcount < lencount++)
3214              {
3215                if (*uip > X_INT_MAX)
3216                  (*range_error)++;
3217                *ip++ = *uip++;
3218              }
3219          break;
3220        case NC_UINT:
3221          for (uip = (unsigned int *)srcuip1 = destcount < lencount++)
3222            {
3223              if (*uip > X_UINT_MAX)
3224                (*range_error)++;
3225              *uip1++ = *uip++;
3226            }
3227          break;
3228        case NC_INT64:
3229          for (uip = (unsigned int *)srclip = destcount < lencount++)
3230            *lip++ = *uip++;
3231          break;
3232        case NC_UINT64:
3233          for (uip = (unsigned int *)srculip = destcount < lencount++)
3234            *ulip++ = *uip++;
3235          break;
3236        case NC_FLOAT:
3237          for (uip = (unsigned int *)srcfp = destcount < lencount++)
3238            *fp++ = *uip++;
3239          break;
3240        case NC_DOUBLE:
3241          for (uip = (unsigned int *)srcdp = destcount < lencount++)
3242            *dp++ = *uip++;
3243          break;
3244        default:
3245          LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d",
3246               __func__src_typedest_type));
3247          return NC_EBADTYPE;
3248        }
3249      break;
3250
3251    case NC_INT64:
3252      switch (dest_type)
3253        {
3254        case NC_UBYTE:
3255          for (lip = (long long *)srcubp = destcount < lencount++)
3256            {
3257              if (*lip > X_UCHAR_MAX || *lip < 0)
3258                (*range_error)++;
3259              *ubp++ = *lip++;
3260            }
3261          break;
3262        case NC_BYTE:
3263          for (lip = (long long *)srcbp = destcount < lencount++)
3264            {
3265              if (*lip > X_SCHAR_MAX || *lip < X_SCHAR_MIN)
3266                (*range_error)++;
3267              *bp++ = *lip++;
3268            }
3269          break;
3270        case NC_SHORT:
3271          for (lip = (long long *)srcsp = destcount < lencount++)
3272            {
3273              if (*lip > X_SHORT_MAX || *lip < X_SHORT_MIN)
3274                (*range_error)++;
3275              *sp++ = *lip++;
3276            }
3277          break;
3278        case NC_USHORT:
3279          for (lip = (long long *)srcusp = destcount < lencount++)
3280            {
3281              if (*lip > X_USHORT_MAX || *lip < 0)
3282                (*range_error)++;
3283              *usp++ = *lip++;
3284            }
3285          break;
3286        case NC_UINT:
3287          for (lip = (long long *)srcuip = destcount < lencount++)
3288            {
3289              if (*lip > X_UINT_MAX || *lip < 0)
3290                (*range_error)++;
3291              *uip++ = *lip++;
3292            }
3293          break;
3294        case NC_INT:
3295          if (dest_long)
3296            for (lip = (long long *)srclp = destcount < lencount++)
3297              {
3298                if (*lip > X_LONG_MAX || *lip < X_LONG_MIN)
3299                  (*range_error)++;
3300                *lp++ = *lip++;
3301              }
3302          else
3303            for (lip = (long long *)srcip = destcount < lencount++)
3304              {
3305                if (*lip > X_INT_MAX || *lip < X_INT_MIN)
3306                  (*range_error)++;
3307                *ip++ = *lip++;
3308              }
3309          break;
3310        case NC_INT64:
3311          for (lip = (long long *)srclip1 = destcount < lencount++)
3312            *lip1++ = *lip++;
3313          break;
3314        case NC_UINT64:
3315          for (lip = (long long *)srculip = destcount < lencount++)
3316            {
3317              if (*lip < 0)
3318                (*range_error)++;
3319              *ulip++ = *lip++;
3320            }
3321          break;
3322        case NC_FLOAT:
3323          for (lip = (long long *)srcfp = destcount < lencount++)
3324            *fp++ = *lip++;
3325          break;
3326        case NC_DOUBLE:
3327          for (lip = (long long *)srcdp = destcount < lencount++)
3328            *dp++ = *lip++;
3329          break;
3330        default:
3331          LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d",
3332               __func__src_typedest_type));
3333          return NC_EBADTYPE;
3334        }
3335      break;
3336
3337    case NC_UINT64:
3338      switch (dest_type)
3339        {
3340        case NC_UBYTE:
3341          for (ulip = (unsigned long long *)srcubp = destcount < lencount++)
3342            {
3343              if (*ulip > X_UCHAR_MAX)
3344                (*range_error)++;
3345              *ubp++ = *ulip++;
3346            }
3347          break;
3348        case NC_BYTE:
3349          for (ulip = (unsigned long long *)srcbp = destcount < lencount++)
3350            {
3351              if (*ulip > X_SCHAR_MAX)
3352                (*range_error)++;
3353              *bp++ = *ulip++;
3354            }
3355          break;
3356        case NC_SHORT:
3357          for (ulip = (unsigned long long *)srcsp = destcount < lencount++)
3358            {
3359              if (*ulip > X_SHORT_MAX)
3360                (*range_error)++;
3361              *sp++ = *ulip++;
3362            }
3363          break;
3364        case NC_USHORT:
3365          for (ulip = (unsigned long long *)srcusp = destcount < lencount++)
3366            {
3367              if (*ulip > X_USHORT_MAX)
3368                (*range_error)++;
3369              *usp++ = *ulip++;
3370            }
3371          break;
3372        case NC_UINT:
3373          for (ulip = (unsigned long long *)srcuip = destcount < lencount++)
3374            {
3375              if (*ulip > X_UINT_MAX)
3376                (*range_error)++;
3377              *uip++ = *ulip++;
3378            }
3379          break;
3380        case NC_INT:
3381          if (dest_long)
3382            for (ulip = (unsigned long long *)srclp = destcount < lencount++)
3383              {
3384                if (*ulip > X_LONG_MAX)
3385                  (*range_error)++;
3386                *lp++ = *ulip++;
3387              }
3388          else
3389            for (ulip = (unsigned long long *)srcip = destcount < lencount++)
3390              {
3391                if (*ulip > X_INT_MAX)
3392                  (*range_error)++;
3393                *ip++ = *ulip++;
3394              }
3395          break;
3396        case NC_INT64:
3397          for (ulip = (unsigned long long *)srclip = destcount < lencount++)
3398            {
3399              if (*ulip > X_INT64_MAX)
3400                (*range_error)++;
3401              *lip++ = *ulip++;
3402            }
3403          break;
3404        case NC_UINT64:
3405          for (ulip = (unsigned long long *)srculip1 = destcount < lencount++)
3406            *ulip1++ = *ulip++;
3407          break;
3408        case NC_FLOAT:
3409          for (ulip = (unsigned long long *)srcfp = destcount < lencount++)
3410            *fp++ = *ulip++;
3411          break;
3412        case NC_DOUBLE:
3413          for (ulip = (unsigned long long *)srcdp = destcount < lencount++)
3414            *dp++ = *ulip++;
3415          break;
3416        default:
3417          LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d",
3418               __func__src_typedest_type));
3419          return NC_EBADTYPE;
3420        }
3421      break;
3422
3423    case NC_FLOAT:
3424      switch (dest_type)
3425        {
3426        case NC_UBYTE:
3427          for (fp = (float *)srcubp = destcount < lencount++)
3428            {
3429              if (*fp > X_UCHAR_MAX || *fp < 0)
3430                (*range_error)++;
3431              *ubp++ = *fp++;
3432            }
3433          break;
3434        case NC_BYTE:
3435          for (fp = (float *)srcbp = destcount < lencount++)
3436            {
3437              if (*fp > (double)X_SCHAR_MAX || *fp < (double)X_SCHAR_MIN)
3438                (*range_error)++;
3439              *bp++ = *fp++;
3440            }
3441          break;
3442        case NC_SHORT:
3443          for (fp = (float *)srcsp = destcount < lencount++)
3444            {
3445              if (*fp > (double)X_SHORT_MAX || *fp < (double)X_SHORT_MIN)
3446                (*range_error)++;
3447              *sp++ = *fp++;
3448            }
3449          break;
3450        case NC_USHORT:
3451          for (fp = (float *)srcusp = destcount < lencount++)
3452            {
3453              if (*fp > X_USHORT_MAX || *fp < 0)
3454                (*range_error)++;
3455              *usp++ = *fp++;
3456            }
3457          break;
3458        case NC_UINT:
3459          for (fp = (float *)srcuip = destcount < lencount++)
3460            {
3461              if (*fp > X_UINT_MAX || *fp < 0)
3462                (*range_error)++;
3463              *uip++ = *fp++;
3464            }
3465          break;
3466        case NC_INT:
3467          if (dest_long)
3468            for (fp = (float *)srclp = destcount < lencount++)
3469              {
3470                if (*fp > (double)X_LONG_MAX || *fp < (double)X_LONG_MIN)
3471                  (*range_error)++;
3472                *lp++ = *fp++;
3473              }
3474          else
3475            for (fp = (float *)srcip = destcount < lencount++)
3476              {
3477                if (*fp > (double)X_INT_MAX || *fp < (double)X_INT_MIN)
3478                  (*range_error)++;
3479                *ip++ = *fp++;
3480              }
3481          break;
3482        case NC_INT64:
3483          for (fp = (float *)srclip = destcount < lencount++)
3484            {
3485              if (*fp > X_INT64_MAX || *fp <X_INT64_MIN)
3486                (*range_error)++;
3487              *lip++ = *fp++;
3488            }
3489          break;
3490        case NC_UINT64:
3491          for (fp = (float *)srclip = destcount < lencount++)
3492            {
3493              if (*fp > X_UINT64_MAX || *fp < 0)
3494                (*range_error)++;
3495              *lip++ = *fp++;
3496            }
3497          break;
3498        case NC_FLOAT:
3499          for (fp = (float *)srcfp1 = destcount < lencount++)
3500            {
3501              /*                if (*fp > X_FLOAT_MAX || *fp < X_FLOAT_MIN)
3502                                (*range_error)++;*/
3503              *fp1++ = *fp++;
3504            }
3505          break;
3506        case NC_DOUBLE:
3507          for (fp = (float *)srcdp = destcount < lencount++)
3508            *dp++ = *fp++;
3509          break;
3510        default:
3511          LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d",
3512               __func__src_typedest_type));
3513          return NC_EBADTYPE;
3514        }
3515      break;
3516
3517    case NC_DOUBLE:
3518      switch (dest_type)
3519        {
3520        case NC_UBYTE:
3521          for (dp = (double *)srcubp = destcount < lencount++)
3522            {
3523              if (*dp > X_UCHAR_MAX || *dp < 0)
3524                (*range_error)++;
3525              *ubp++ = *dp++;
3526            }
3527          break;
3528        case NC_BYTE:
3529          for (dp = (double *)srcbp = destcount < lencount++)
3530            {
3531              if (*dp > X_SCHAR_MAX || *dp < X_SCHAR_MIN)
3532                (*range_error)++;
3533              *bp++ = *dp++;
3534            }
3535          break;
3536        case NC_SHORT:
3537          for (dp = (double *)srcsp = destcount < lencount++)
3538            {
3539              if (*dp > X_SHORT_MAX || *dp < X_SHORT_MIN)
3540                (*range_error)++;
3541              *sp++ = *dp++;
3542            }
3543          break;
3544        case NC_USHORT:
3545          for (dp = (double *)srcusp = destcount < lencount++)
3546            {
3547              if (*dp > X_USHORT_MAX || *dp < 0)
3548                (*range_error)++;
3549              *usp++ = *dp++;
3550            }
3551          break;
3552        case NC_UINT:
3553          for (dp = (double *)srcuip = destcount < lencount++)
3554            {
3555              if (*dp > X_UINT_MAX || *dp < 0)
3556                (*range_error)++;
3557              *uip++ = *dp++;
3558            }
3559          break;
3560        case NC_INT:
3561          if (dest_long)
3562            for (dp = (double *)srclp = destcount < lencount++)
3563              {
3564                if (*dp > X_LONG_MAX || *dp < X_LONG_MIN)
3565                  (*range_error)++;
3566                *lp++ = *dp++;
3567              }
3568          else
3569            for (dp = (double *)srcip = destcount < lencount++)
3570              {
3571                if (*dp > X_INT_MAX || *dp < X_INT_MIN)
3572                  (*range_error)++;
3573                *ip++ = *dp++;
3574              }
3575          break;
3576        case NC_INT64:
3577          for (dp = (double *)srclip = destcount < lencount++)
3578            {
3579              if (*dp > X_INT64_MAX || *dp < X_INT64_MIN)
3580                (*range_error)++;
3581              *lip++ = *dp++;
3582            }
3583          break;
3584        case NC_UINT64:
3585          for (dp = (double *)srclip = destcount < lencount++)
3586            {
3587              if (*dp > X_UINT64_MAX || *dp < 0)
3588                (*range_error)++;
3589              *lip++ = *dp++;
3590            }
3591          break;
3592        case NC_FLOAT:
3593          for (dp = (double *)srcfp = destcount < lencount++)
3594            {
3595              if (*dp > X_FLOAT_MAX || *dp < X_FLOAT_MIN)
3596                (*range_error)++;
3597              *fp++ = *dp++;
3598            }
3599          break;
3600        case NC_DOUBLE:
3601          for (dp = (double *)srcdp1 = destcount < lencount++)
3602            {
3603              /* if (*dp > X_DOUBLE_MAX || *dp < X_DOUBLE_MIN) */
3604              /*    (*range_error)++; */
3605              *dp1++ = *dp++;
3606            }
3607          break;
3608        default:
3609          LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d",
3610               __func__src_typedest_type));
3611          return NC_EBADTYPE;
3612        }
3613      break;
3614
3615    default:
3616      LOG((0, "%s: unexpected src type. src_type %d, dest_type %d",
3617           __func__src_typedest_type));
3618      return NC_EBADTYPE;
3619    }
3620  return NC_NOERR;
3621}
3622
3623/* In our first pass through the data, we may have encountered
3624 * variables before encountering their dimscales, so go through the
3625 * vars in this file and make sure we've got a dimid for each. */
3626int
3627nc4_rec_match_dimscales(NC_GRP_INFO_T *grp)
3628{
3629  NC_GRP_INFO_T *g;
3630  NC_VAR_INFO_T *var;
3631  NC_DIM_INFO_T *dim;
3632  int retval = NC_NOERR;
3633
3634  assert(grp && grp->name);
3635  LOG((4, "%s: grp->name %s", __func__grp->name));
3636
3637  /* Perform var dimscale match for child groups. */
3638  for (g = grp->childrengg = g->l.next)
3639    if ((retval = nc4_rec_match_dimscales(g)))
3640      return retval;
3641
3642  /* Check all the vars in this group. If they have dimscale info,
3643   * try and find a dimension for them. */
3644  for (var = grp->varvarvar = var->l.next)
3645    {
3646      /* Check all vars and see if dim[i] != NULL if dimids[i] valid. */
3647      int ndims = var->ndims;
3648      int d;
3649      for (d = 0; d < ndimsd++)
3650 {
3651   if (var->dim[d] == NULL) {
3652     nc4_find_dim(grpvar->dimids[d], &var->dim[d], NULL);
3653   }
3654   /*   assert(var->dim[d] && var->dim[d]->dimid == var->dimids[d]); */
3655 }
3656
3657      /* Skip dimension scale variables */
3658      if (!var->dimscale)
3659        {
3660          int d;
3661
3662          /* Are there dimscales for this variable? */
3663          if (var->dimscale_hdf5_objids)
3664            {
3665              for (d = 0; d < var->ndimsd++)
3666                {
3667                  nc_bool_t finished = NC_FALSE;
3668
3669                  LOG((5, "%s: var %s has dimscale info...", __func__var->name));
3670                  /* Look at all the dims in this group to see if they
3671                   * match. */
3672                  for (g = grpg && !finishedg = g->parent)
3673                    {
3674                      for (dim = g->dimdimdim = dim->l.next)
3675                        {
3676                          if (var->dimscale_hdf5_objids[d].fileno[0] == dim->hdf5_objid.fileno[0] &&
3677                              var->dimscale_hdf5_objids[d].objno[0] == dim->hdf5_objid.objno[0] &&
3678                              var->dimscale_hdf5_objids[d].fileno[1] == dim->hdf5_objid.fileno[1] &&
3679                              var->dimscale_hdf5_objids[d].objno[1] == dim->hdf5_objid.objno[1])
3680                            {
3681                              LOG((4, "%s: for dimension %d, found dim %s",
3682                                   __func__ddim->name));
3683                              var->dimids[d] = dim->dimid;
3684                              var->dim[d] = dim;
3685                              finished = NC_TRUE;
3686                              break;
3687                            }
3688                        } /* next dim */
3689                    } /* next grp */
3690                  LOG((5, "%s: dimid for this dimscale is %d", __func__var->type_info->nc_typeid));
3691                } /* next var->dim */
3692            }
3693          /* No dimscales for this var! Invent phony dimensions. */
3694          else
3695            {
3696              hid_t spaceid = 0;
3697              hsize_t *h5dimlen = NULL, *h5dimlenmax = NULL;
3698              int dataset_ndims;
3699
3700              /* Find the space information for this dimension. */
3701              if ((spaceid = H5Dget_space(var->hdf_datasetid)) < 0)
3702                return NC_EHDFERR;
3703#ifdef EXTRA_TESTS
3704              num_spaces++;
3705#endif
3706
3707              /* Get the len of each dim in the space. */
3708              if (var->ndims)
3709                {
3710                  if (!(h5dimlen = malloc(var->ndims * sizeof(hsize_t))))
3711                    return NC_ENOMEM;
3712                  if (!(h5dimlenmax = malloc(var->ndims * sizeof(hsize_t))))
3713                    {
3714                      free(h5dimlen);
3715                      return NC_ENOMEM;
3716                    }
3717                  if ((dataset_ndims = H5Sget_simple_extent_dims(spaceidh5dimlen,
3718                                                                 h5dimlenmax)) < 0) {
3719                    free(h5dimlenmax);
3720                    free(h5dimlen);
3721                    return NC_EHDFERR;
3722                  }
3723                  if (dataset_ndims != var->ndims) {
3724                    free(h5dimlenmax);
3725                    free(h5dimlen);
3726                    return NC_EHDFERR;
3727                  }
3728                }
3729              else
3730                {
3731                  /* Make sure it's scalar. */
3732                  if (H5Sget_simple_extent_type(spaceid) != H5S_SCALAR)
3733                    return NC_EHDFERR;
3734                }
3735
3736              /* Release the space object. */
3737              if (H5Sclose(spaceid) < 0) {
3738                free(h5dimlen);
3739                free(h5dimlenmax);
3740                return NC_EHDFERR;
3741              }
3742#ifdef EXTRA_TESTS
3743              num_spaces--;
3744#endif
3745
3746              /* Create a phony dimension for each dimension in the
3747               * dataset, unless there already is one the correct
3748               * size. */
3749              for (d = 0; d < var->ndimsd++)
3750                {
3751                  /* Is there already a phony dimension of the correct size? */
3752                  for (dim = grp->dimdimdim = dim->l.next)
3753                    if ((dim->len == h5dimlen[d]) &&
3754                        ((h5dimlenmax[d] == H5S_UNLIMITED && dim->unlimited) ||
3755                         (h5dimlenmax[d] != H5S_UNLIMITED && !dim->unlimited)))
3756                      break;
3757
3758                  /* Didn't find a phony dim? Then create one. */
3759                  if (!dim)
3760                    {
3761                      char phony_dim_name[NC_MAX_NAME + 1];
3762
3763                      LOG((3, "%s: creating phony dim for var %s", __func__var->name));
3764                      if ((retval = nc4_dim_list_add(&grp->dim, &dim))) {
3765                        free(h5dimlenmax);
3766                        free(h5dimlen);
3767                        return retval;
3768                      }
3769                      grp->ndims++;
3770                      dim->dimid = grp->nc4_info->next_dimid++;
3771                      sprintf(phony_dim_name, "phony_dim_%d", dim->dimid);
3772                      if (!(dim->name = strdup(phony_dim_name))) {
3773                        free(h5dimlenmax);
3774                        free(h5dimlen);
3775                        return NC_ENOMEM;
3776                      }
3777                      dim->len = h5dimlen[d];
3778                      dim->hash = hash_fast(phony_dim_name, strlen(phony_dim_name));
3779                      if (h5dimlenmax[d] == H5S_UNLIMITED)
3780                        dim->unlimited = NC_TRUE;
3781                    }
3782
3783                  /* The variable must remember the dimid. */
3784                  var->dimids[d] = dim->dimid;
3785                  var->dim[d] = dim;
3786                } /* next dim */
3787
3788              /* Free the memory we malloced. */
3789              free(h5dimlen);
3790              free(h5dimlenmax);
3791            }
3792        }
3793    }
3794
3795  return retval;
3796}
3797
3798/* Get the length, in bytes, of one element of a type in memory. */
3799int
3800nc4_get_typelen_mem(NC_HDF5_FILE_INFO_T *h5nc_type xtype, int is_long,
3801                    size_t *len)
3802{
3803  NC_TYPE_INFO_T *type;
3804  int retval;
3805
3806  LOG((4, "%s xtype: %d", __func__xtype));
3807  assert(len);
3808
3809  /* If this is an atomic type, the answer is easy. */
3810  switch (xtype)
3811    {
3812    case NC_BYTE:
3813    case NC_CHAR:
3814    case NC_UBYTE:
3815      *len = sizeof(char);
3816      return NC_NOERR;
3817    case NC_SHORT:
3818    case NC_USHORT:
3819      *len = sizeof(short);
3820      return NC_NOERR;
3821    case NC_INT:
3822    case NC_UINT:
3823      if (is_long)
3824        *len = sizeof(long);
3825      else
3826        *len = sizeof(int);
3827      return NC_NOERR;
3828    case NC_FLOAT:
3829      *len = sizeof(float);
3830      return NC_NOERR;
3831    case NC_DOUBLE:
3832      *len = sizeof(double);
3833      return NC_NOERR;
3834    case NC_INT64:
3835    case NC_UINT64:
3836      *len = sizeof(long long);
3837      return NC_NOERR;
3838    case NC_STRING:
3839      *len = sizeof(char *);
3840      return NC_NOERR;
3841    }
3842
3843  /* See if var is compound type. */
3844  if ((retval = nc4_find_type(h5xtype, &type)))
3845    return retval;
3846
3847  if (!type)
3848    return NC_EBADTYPE;
3849
3850  *len = type->size;
3851
3852  LOG((5, "type->size: %d", type->size));
3853
3854  return NC_NOERR;
3855}
3856
3857/* Get the class of a type */
3858int
3859nc4_get_typeclass(const NC_HDF5_FILE_INFO_T *h5nc_type xtype, int *type_class)
3860{
3861  int retval = NC_NOERR;
3862
3863  LOG((4, "%s xtype: %d", __func__xtype));
3864  assert(type_class);
3865
3866  /* If this is an atomic type, the answer is easy. */
3867  if (xtype <= NC_STRING)
3868    {
3869      switch (xtype)
3870        {
3871        case NC_BYTE:
3872        case NC_UBYTE:
3873        case NC_SHORT:
3874        case NC_USHORT:
3875        case NC_INT:
3876        case NC_UINT:
3877        case NC_INT64:
3878        case NC_UINT64:
3879          /* NC_INT is class used for all integral types */
3880          *type_class = NC_INT;
3881          break;
3882
3883        case NC_FLOAT:
3884        case NC_DOUBLE:
3885          /* NC_FLOAT is class used for all floating-point types */
3886          *type_class = NC_FLOAT;
3887          break;
3888
3889        case NC_CHAR:
3890          *type_class = NC_CHAR;
3891          break;
3892
3893        case NC_STRING:
3894          *type_class = NC_STRING;
3895          break;
3896
3897        default:
3898          BAIL(NC_EBADTYPE);
3899        }
3900    }
3901  else
3902    {
3903      NC_TYPE_INFO_T *type;
3904
3905      /* See if it's a used-defined type */
3906      if ((retval = nc4_find_type(h5xtype, &type)))
3907        BAIL(retval);
3908      if (!type)
3909        BAIL(NC_EBADTYPE);
3910
3911      *type_class = type->nc_type_class;
3912    }
3913
3914 exit:
3915  return retval;
3916}
3917
3918int
3919NC4_test_netcdf4(void)
3920{
3921    return NC_NOERR;
3922}
3923void
3924reportobject(int log, hid_t id, unsigned int type)
3925{
3926#   define MAXNAME 1024
3927    char name[MAXNAME];
3928    ssize_t len;
3929    const char* typename = NULL;
3930
3931    len = H5Iget_name(idnameMAXNAME);
3932    if(len < 0) return;
3933    name[len] = '\0';
3934
3935    switch (type) {
3936    case H5F_OBJ_FILEtypename = "File"; break;
3937    case H5F_OBJ_DATASETtypename = "Dataset"; break;
3938    case H5F_OBJ_GROUPtypename = "Group"; break;
3939    case H5F_OBJ_DATATYPEtypename = "Datatype"; break;
3940    case H5F_OBJ_ATTR:
3941 typename = "Attribute";
3942 len = H5Aget_name(idMAXNAMEname);
3943        if(len < 0) len = 0;
3944 name[len] = '\0';
3945 break;
3946    default: typename = "<unknown>"; break;
3947    }
3948    if(log) {
3949#ifdef LOGGING
3950 LOG((0,"Type = %s(%8u) name='%s'",typename,id,name));
3951#endif
3952    } else {
3953 fprintf(stderr,"Type = %s(%8u) name='%s'",typename,id,name);
3954    }
3955}
3956
3957static unsigned int OTYPES[5] = {H5F_OBJ_FILEH5F_OBJ_DATASETH5F_OBJ_GROUPH5F_OBJ_DATATYPEH5F_OBJ_ATTR};
3958
3959static void
3960reportopenobjectsT(int log, hid_t fid, int ntypes, unsigned int* otypes)
3961{
3962    int t,i;
3963    ssize_t ocount;
3964    size_t maxobjs = -1;
3965    hid_tidlist = NULL;
3966
3967    if(log) {
3968#ifdef LOGGING
3969        LOG((0,"\nReport: open objects on %d\n",fid));
3970#endif
3971    } else {
3972        fprintf(stdout,"\nReport: open objects on %d\n",fid);
3973    }
3974    maxobjs = H5Fget_obj_count(fid,H5F_OBJ_ALL);
3975    if(idlist != NULL) free(idlist);
3976    idlist = (hid_t*)malloc(sizeof(hid_t)*maxobjs);
3977    for(t=0;t<ntypes;t++) {
3978 unsigned int ot = otypes[t];
3979 if(ot < 0) break;
3980        ocount = H5Fget_obj_ids(fid,ot,maxobjs,idlist);
3981 for(i=0;i<ocount;i++) {
3982     hid_t o = idlist[i];
3983     reportobject(log,o,ot);
3984 }
3985    }
3986    if(idlist != NULL) free(idlist);
3987}
3988
3989void
3990reportopenobjects(int log, hid_t fid)
3991{
3992    reportopenobjectsT(log, fid,5,OTYPES);
3993}
3994
3995
3996int
3997NC4_hdf5get_libversion(unsigned* major,unsigned* minor,unsigned* release)
3998{
3999    if(H5get_libversion(major,minor,release) < 0)
4000 return NC_EHDFERR;
4001    return NC_NOERR;
4002}
4003
4004int
4005NC4_hdf5get_superblock(struct NC_HDF5_FILE_INFOh5, int* idp)
4006{
4007    int stat = NC_NOERR;
4008    unsigned super;
4009    hid_t plist = -1;
4010    if((plist = H5Fget_create_plist(h5->hdfid)) < 0)
4011 {stat = NC_EHDFERR; goto done;}
4012    if(H5Pget_version(plist, &superNULLNULLNULL) < 0)
4013 {stat = NC_EHDFERR; goto done;}
4014    if(idp) *idp = (int)super;
4015done:
4016    if(plist >= 0) H5Pclose(plist);
4017    return stat;
4018}
4019
4020/* We define a file as being from netcdf-4 if any of the following
4021are true:
40221. NCPROPS attribute exists in root group
40232. NC3_STRICT_ATT_NAME exists in root group
40243. any of NC_ATT_REFERENCE_LIST, NC_ATT_CLASS,
4025   NC_ATT_DIMENSION_LIST, NC_ATT_NAME,
4026   NC_ATT_COORDINATES, NC_DIMID_ATT_NAME
4027   exist anywhere in the file; note that this
4028   requires walking the file.
4029WARNINGS:
40301. False negatives are possible for a small subset of netcdf-4
4031   created files.
40322. Deliberate falsification in the file can be used to cause
4033   a false positive.
4034*/
4035
4036static int NC4_get_strict_att(NC_HDF5_FILE_INFO_T*);
4037static int NC4_walk(hid_t, int*);
4038
4039int
4040NC4_isnetcdf4(struct NC_HDF5_FILE_INFOh5)
4041{
4042    int stat;
4043    int isnc4 = 0;
4044    int count;
4045
4046    /* Look for NC3_STRICT_ATT_NAME */
4047    isnc4 = NC4_get_strict_att(h5);
4048    if(isnc4 > 0)
4049 goto done;
4050    /* attribute did not exist */
4051    /* => last resort: walk the HDF5 file looking for markers */
4052    count = 0;
4053    stat = NC4_walk(h5->root_grp->hdf_grpid, &count);
4054    if(stat != NC_NOERR)
4055 isnc4 = 0;
4056    else /* Threshold is at least two matches */
4057 isnc4 = (count >= 2);
4058
4059done:
4060    return isnc4;
4061}
4062
4063static int
4064NC4_get_strict_att(NC_HDF5_FILE_INFO_Th5)
4065{
4066    int ncstat = NC_NOERR;
4067    size_t size;
4068    hid_t grp = -1;
4069    hid_t attid = -1;
4070    herr_t herr = 0;
4071
4072    /* Get root group */
4073    grp = h5->root_grp->hdf_grpid; /* get root group */
4074    /* Try to extract the NC3_STRICT_ATT_NAME attribute */
4075    attid = H5Aopen_name(grpNC3_STRICT_ATT_NAME);
4076    H5Aclose(attid);
4077    return attid;
4078}
4079
4080static int
4081NC4_walk(hid_t gid, int* countp)
4082{
4083    int ncstat = NC_NOERR;
4084    int i,j,na;
4085    ssize_t len;
4086    hsize_t nobj;
4087    herr_t err;
4088    int otype;
4089    hid_t grpiddsid;
4090    char name[NC_HDF5_MAX_NAME];
4091
4092    /* walk group members of interest */
4093    err = H5Gget_num_objs(gid, &nobj);
4094    if(err < 0) return err;
4095
4096    for(i = 0; i < nobji++) {
4097        /* Get name & kind of object in the group */
4098        len = H5Gget_objname_by_idx(gid,(hsize_t)i,name,(size_t)NC_HDF5_MAX_NAME);
4099        if(len < 0) return len;
4100
4101        otype =  H5Gget_objtype_by_idx(gid,(size_t)i);
4102        switch(otype) {
4103        case H5G_GROUP:
4104            grpid = H5Gopen(gid,name);
4105            NC4_walk(grpid,countp);
4106            H5Gclose(grpid);
4107            break;
4108        case H5G_DATASET: /* variables */
4109     /* Check for phony_dim */
4110     if(strcmp(name,"phony_dim")==0)
4111 *countp = *countp + 1;
4112            dsid = H5Dopen(gid,name);
4113            na = H5Aget_num_attrs(dsid);
4114            for(j = 0; j < naj++) {
4115                hid_t aid =  H5Aopen_idx(dsid,(unsigned int)    j);
4116                if(aid >= 0) {
4117                    const char** p;
4118                    ssize_t len = H5Aget_name(aidNC_HDF5_MAX_NAMEname);
4119                    if(len < 0) return len;
4120                    /* Is this a netcdf-4 marker attribute */
4121                        for(p=NC_RESERVED_VARATT_LIST;*p;p++) {
4122                            if(strcmp(name,*p) ==     0) {
4123                                *countp = *countp + 1;
4124                            }
4125                        }
4126                }
4127                H5Aclose(aid);
4128            }
4129            H5Dclose(dsid);
4130            break;
4131        default:/* ignore */
4132            break;
4133            }
4134    }
4135    return ncstat;
4136}


HyperKWIC - Version 7.20DA executed at 11:37 on 27 Oct 2017 | Polyhedron Solutions - INTERNAL USE | COMMERCIAL (Any O/S) SN 4AKIed