NetCDF  4.6.2
nc4hdf.c
Go to the documentation of this file.
1 /* Copyright 2003, University Corporation for Atmospheric
2  * Research. See the COPYRIGHT file for copying and redistribution
3  * conditions. */
17 #include "config.h"
18 #include "hdf5internal.h"
19 #include <math.h>
20 
21 #ifdef HAVE_INTTYPES_H
22 #define __STDC_FORMAT_MACROS
23 #include <inttypes.h>
24 #endif
25 
26 #define NC_HDF5_MAX_NAME 1024
36 static int
37 flag_atts_dirty(NCindex *attlist) {
38 
39  NC_ATT_INFO_T *att = NULL;
40  int i;
41 
42  if(attlist == NULL) {
43  return NC_NOERR;
44  }
45 
46  for(i=0;i<ncindexsize(attlist);i++) {
47  att = (NC_ATT_INFO_T*)ncindexith(attlist,i);
48  if(att == NULL) continue;
49  att->dirty = NC_TRUE;
50  }
51 
52  return NC_NOERR;
53 }
54 
71 int
72 rec_reattach_scales(NC_GRP_INFO_T *grp, int dimid, hid_t dimscaleid)
73 {
74  NC_VAR_INFO_T *var;
75  NC_GRP_INFO_T *child_grp;
76  int d, i;
77  int retval;
78 
79  assert(grp && grp->hdr.name && dimid >= 0 && dimscaleid >= 0);
80  LOG((3, "%s: grp->hdr.name %s", __func__, grp->hdr.name));
81 
82  /* If there are any child groups, attach dimscale there, if needed. */
83  for(i=0;i<ncindexsize(grp->children);i++) {
84  child_grp = (NC_GRP_INFO_T*)ncindexith(grp->children,i);
85  if(child_grp == NULL) continue;
86  if ((retval = rec_reattach_scales(child_grp, dimid, dimscaleid)))
87  return retval;
88  }
89 
90  /* Find any vars that use this dimension id. */
91  for(i=0;i<ncindexsize(grp->vars);i++)
92  {
93  var = (NC_VAR_INFO_T*)ncindexith(grp->vars,i);
94  if(var == NULL) continue;
95  for (d = 0; d < var->ndims; d++)
96  if (var->dimids[d] == dimid && !var->dimscale)
97  {
98  LOG((2, "%s: attaching scale for dimid %d to var %s",
99  __func__, var->dimids[d], var->hdr.name));
100  if (var->created)
101  {
102  if (H5DSattach_scale(var->hdf_datasetid, dimscaleid, d) < 0)
103  return NC_EHDFERR;
104  var->dimscale_attached[d] = NC_TRUE;
105  }
106  }
107  }
108  return NC_NOERR;
109 }
110 
127 int
128 rec_detach_scales(NC_GRP_INFO_T *grp, int dimid, hid_t dimscaleid)
129 {
130  NC_VAR_INFO_T *var;
131  NC_GRP_INFO_T *child_grp;
132  int d, i;
133  int retval;
134 
135  assert(grp && grp->hdr.name && dimid >= 0 && dimscaleid >= 0);
136  LOG((3, "%s: grp->hdr.name %s", __func__, grp->hdr.name));
137 
138  /* If there are any child groups, detach dimscale there, if needed. */
139  for(i=0;i<ncindexsize(grp->children);i++) {
140  child_grp = (NC_GRP_INFO_T*)ncindexith(grp->children,i);
141  if(child_grp == NULL) continue;
142  if ((retval = rec_detach_scales(child_grp, dimid, dimscaleid)))
143  return retval;
144  }
145 
146  /* Find any vars that use this dimension id. */
147  for(i=0;i<ncindexsize(grp->vars);i++) {
148  var = (NC_VAR_INFO_T*)ncindexith(grp->vars,i);
149  if(var == NULL) continue;
150  for (d = 0; d < var->ndims; d++)
151  if (var->dimids[d] == dimid && !var->dimscale)
152  {
153  LOG((2, "%s: detaching scale for dimid %d to var %s",
154  __func__, var->dimids[d], var->hdr.name));
155  if (var->created)
156  if (var->dimscale_attached && var->dimscale_attached[d])
157  {
158  if (H5DSdetach_scale(var->hdf_datasetid, dimscaleid, d) < 0)
159  return NC_EHDFERR;
160  var->dimscale_attached[d] = NC_FALSE;
161  }
162  }
163  }
164  return NC_NOERR;
165 }
166 
178 int
179 nc4_open_var_grp2(NC_GRP_INFO_T *grp, int varid, hid_t *dataset)
180 {
181  NC_VAR_INFO_T *var;
182 
183  assert(grp && grp->format_grp_info && dataset);
184 
185  /* Find the requested varid. */
186  var = (NC_VAR_INFO_T*)ncindexith(grp->vars,varid);
187  if (!var) return NC_ENOTVAR;
188  assert(var->hdr.id == varid);
189 
190  /* Open this dataset if necessary. */
191  if (!var->hdf_datasetid)
192  {
193  NC_HDF5_GRP_INFO_T *hdf5_grp;
194  hdf5_grp = (NC_HDF5_GRP_INFO_T *)grp->format_grp_info;
195 
196  if ((var->hdf_datasetid = H5Dopen2(hdf5_grp->hdf_grpid,
197  var->hdr.name, H5P_DEFAULT)) < 0)
198  return NC_ENOTVAR;
199  }
200 
201  *dataset = var->hdf_datasetid;
202 
203  return NC_NOERR;
204 }
205 
217 int
218 nc4_get_default_fill_value(const NC_TYPE_INFO_T *type_info, void *fill_value)
219 {
220  switch (type_info->hdr.id)
221  {
222  case NC_CHAR:
223  *(char *)fill_value = NC_FILL_CHAR;
224  break;
225 
226  case NC_STRING:
227  *(char **)fill_value = strdup(NC_FILL_STRING);
228  break;
229 
230  case NC_BYTE:
231  *(signed char *)fill_value = NC_FILL_BYTE;
232  break;
233 
234  case NC_SHORT:
235  *(short *)fill_value = NC_FILL_SHORT;
236  break;
237 
238  case NC_INT:
239  *(int *)fill_value = NC_FILL_INT;
240  break;
241 
242  case NC_UBYTE:
243  *(unsigned char *)fill_value = NC_FILL_UBYTE;
244  break;
245 
246  case NC_USHORT:
247  *(unsigned short *)fill_value = NC_FILL_USHORT;
248  break;
249 
250  case NC_UINT:
251  *(unsigned int *)fill_value = NC_FILL_UINT;
252  break;
253 
254  case NC_INT64:
255  *(long long *)fill_value = NC_FILL_INT64;
256  break;
257 
258  case NC_UINT64:
259  *(unsigned long long *)fill_value = NC_FILL_UINT64;
260  break;
261 
262  case NC_FLOAT:
263  *(float *)fill_value = NC_FILL_FLOAT;
264  break;
265 
266  case NC_DOUBLE:
267  *(double *)fill_value = NC_FILL_DOUBLE;
268  break;
269 
270  default:
271  return NC_EINVAL;
272  }
273 
274  return NC_NOERR;
275 }
276 
288 int
289 nc4_get_fill_value(NC_FILE_INFO_T *h5, NC_VAR_INFO_T *var, void **fillp)
290 {
291  size_t size;
292  int retval;
293 
294  /* Find out how much space we need for this type's fill value. */
295  if (var->type_info->nc_type_class == NC_VLEN)
296  size = sizeof(nc_vlen_t);
297  else if (var->type_info->nc_type_class == NC_STRING)
298  size = sizeof(char *);
299  else
300  {
301  if ((retval = nc4_get_typelen_mem(h5, var->type_info->hdr.id, &size)))
302  return retval;
303  }
304  assert(size);
305 
306  /* Allocate the space. */
307  if (!((*fillp) = calloc(1, size)))
308  return NC_ENOMEM;
309 
310  /* If the user has set a fill_value for this var, use, otherwise
311  * find the default fill value. */
312  if (var->fill_value)
313  {
314  LOG((4, "Found a fill value for var %s", var->hdr.name));
315  if (var->type_info->nc_type_class == NC_VLEN)
316  {
317  nc_vlen_t *in_vlen = (nc_vlen_t *)(var->fill_value), *fv_vlen = (nc_vlen_t *)(*fillp);
318  size_t basetypesize = 0;
319 
320  if((retval=nc4_get_typelen_mem(h5, var->type_info->u.v.base_nc_typeid, &basetypesize)))
321  return retval;
322 
323  fv_vlen->len = in_vlen->len;
324  if (!(fv_vlen->p = malloc(basetypesize * in_vlen->len)))
325  {
326  free(*fillp);
327  *fillp = NULL;
328  return NC_ENOMEM;
329  }
330  memcpy(fv_vlen->p, in_vlen->p, in_vlen->len * basetypesize);
331  }
332  else if (var->type_info->nc_type_class == NC_STRING)
333  {
334  if (*(char **)var->fill_value)
335  if (!(**(char ***)fillp = strdup(*(char **)var->fill_value)))
336  {
337  free(*fillp);
338  *fillp = NULL;
339  return NC_ENOMEM;
340  }
341  }
342  else
343  memcpy((*fillp), var->fill_value, size);
344  }
345  else
346  {
347  if (nc4_get_default_fill_value(var->type_info, *fillp))
348  {
349  /* Note: release memory, but don't return error on failure */
350  free(*fillp);
351  *fillp = NULL;
352  }
353  }
354 
355  return NC_NOERR;
356 }
357 
375 int
376 nc4_get_hdf_typeid(NC_FILE_INFO_T *h5, nc_type xtype,
377  hid_t *hdf_typeid, int endianness)
378 {
379  NC_TYPE_INFO_T *type;
380  hid_t typeid = 0;
381  int retval = NC_NOERR;
382 
383  assert(hdf_typeid && h5);
384 
385  *hdf_typeid = -1;
386 
387  /* Determine an appropriate HDF5 datatype */
388  if (xtype == NC_NAT)
389  return NC_EBADTYPE;
390  else if (xtype == NC_CHAR || xtype == NC_STRING)
391  {
392  /* NC_CHAR & NC_STRING types create a new HDF5 datatype */
393  if (xtype == NC_CHAR)
394  {
395  if ((typeid = H5Tcopy(H5T_C_S1)) < 0)
396  return NC_EHDFERR;
397  if (H5Tset_strpad(typeid, H5T_STR_NULLTERM) < 0)
398  BAIL(NC_EVARMETA);
399  if(H5Tset_cset(typeid, H5T_CSET_ASCII) < 0)
400  BAIL(NC_EVARMETA);
401 
402  /* Take ownership of the newly created HDF5 datatype */
403  *hdf_typeid = typeid;
404  typeid = 0;
405  }
406  else
407  {
408  if ((typeid = H5Tcopy(H5T_C_S1)) < 0)
409  return NC_EHDFERR;
410  if (H5Tset_size(typeid, H5T_VARIABLE) < 0)
411  BAIL(NC_EVARMETA);
412  if(H5Tset_cset(typeid, H5T_CSET_UTF8) < 0)
413  BAIL(NC_EVARMETA);
414 
415  /* Take ownership of the newly created HDF5 datatype */
416  *hdf_typeid = typeid;
417  typeid = 0;
418  }
419  }
420  else
421  {
422  /* All other types use an existing HDF5 datatype */
423  switch (xtype)
424  {
425  case NC_BYTE: /* signed 1 byte integer */
426  if (endianness == NC_ENDIAN_LITTLE)
427  typeid = H5T_STD_I8LE;
428  else if (endianness == NC_ENDIAN_BIG)
429  typeid = H5T_STD_I8BE;
430  else
431  typeid = H5T_NATIVE_SCHAR;
432  break;
433 
434  case NC_SHORT: /* signed 2 byte integer */
435  if (endianness == NC_ENDIAN_LITTLE)
436  typeid = H5T_STD_I16LE;
437  else if (endianness == NC_ENDIAN_BIG)
438  typeid = H5T_STD_I16BE;
439  else
440  typeid = H5T_NATIVE_SHORT;
441  break;
442 
443  case NC_INT:
444  if (endianness == NC_ENDIAN_LITTLE)
445  typeid = H5T_STD_I32LE;
446  else if (endianness == NC_ENDIAN_BIG)
447  typeid = H5T_STD_I32BE;
448  else
449  typeid = H5T_NATIVE_INT;
450  break;
451 
452  case NC_UBYTE:
453  if (endianness == NC_ENDIAN_LITTLE)
454  typeid = H5T_STD_U8LE;
455  else if (endianness == NC_ENDIAN_BIG)
456  typeid = H5T_STD_U8BE;
457  else
458  typeid = H5T_NATIVE_UCHAR;
459  break;
460 
461  case NC_USHORT:
462  if (endianness == NC_ENDIAN_LITTLE)
463  typeid = H5T_STD_U16LE;
464  else if (endianness == NC_ENDIAN_BIG)
465  typeid = H5T_STD_U16BE;
466  else
467  typeid = H5T_NATIVE_USHORT;
468  break;
469 
470  case NC_UINT:
471  if (endianness == NC_ENDIAN_LITTLE)
472  typeid = H5T_STD_U32LE;
473  else if (endianness == NC_ENDIAN_BIG)
474  typeid = H5T_STD_U32BE;
475  else
476  typeid = H5T_NATIVE_UINT;
477  break;
478 
479  case NC_INT64:
480  if (endianness == NC_ENDIAN_LITTLE)
481  typeid = H5T_STD_I64LE;
482  else if (endianness == NC_ENDIAN_BIG)
483  typeid = H5T_STD_I64BE;
484  else
485  typeid = H5T_NATIVE_LLONG;
486  break;
487 
488  case NC_UINT64:
489  if (endianness == NC_ENDIAN_LITTLE)
490  typeid = H5T_STD_U64LE;
491  else if (endianness == NC_ENDIAN_BIG)
492  typeid = H5T_STD_U64BE;
493  else
494  typeid = H5T_NATIVE_ULLONG;
495  break;
496 
497  case NC_FLOAT:
498  if (endianness == NC_ENDIAN_LITTLE)
499  typeid = H5T_IEEE_F32LE;
500  else if (endianness == NC_ENDIAN_BIG)
501  typeid = H5T_IEEE_F32BE;
502  else
503  typeid = H5T_NATIVE_FLOAT;
504  break;
505 
506  case NC_DOUBLE:
507  if (endianness == NC_ENDIAN_LITTLE)
508  typeid = H5T_IEEE_F64LE;
509  else if (endianness == NC_ENDIAN_BIG)
510  typeid = H5T_IEEE_F64BE;
511  else
512  typeid = H5T_NATIVE_DOUBLE;
513  break;
514 
515  default:
516  /* Maybe this is a user defined type? */
517  if (nc4_find_type(h5, xtype, &type))
518  return NC_EBADTYPE;
519  if (!type)
520  return NC_EBADTYPE;
521  typeid = type->hdf_typeid;
522  break;
523  }
524  assert(typeid);
525 
526  /* Copy the HDF5 datatype, so the function operates uniformly */
527  if ((*hdf_typeid = H5Tcopy(typeid)) < 0)
528  return NC_EHDFERR;
529  typeid = 0;
530  }
531  assert(*hdf_typeid != -1);
532 
533 exit:
534  if (typeid > 0 && H5Tclose(typeid) < 0)
535  BAIL2(NC_EHDFERR);
536  return retval;
537 }
538 
553 static int
554 put_att_grpa(NC_GRP_INFO_T *grp, int varid, NC_ATT_INFO_T *att)
555 {
556  NC_HDF5_GRP_INFO_T *hdf5_grp;
557  hid_t datasetid = 0, locid;
558  hid_t attid = 0, spaceid = 0, file_typeid = 0;
559  hid_t existing_att_typeid = 0, existing_attid = 0, existing_spaceid = 0;
560  hsize_t dims[1]; /* netcdf attributes always 1-D. */
561  htri_t attr_exists;
562  int reuse_att = 0; /* Will be true if we can re-use an existing att. */
563  void *data;
564  int phoney_data = 99;
565  int retval = NC_NOERR;
566 
567  assert(att->hdr.name && grp && grp->format_grp_info);
568  LOG((3, "%s: varid %d att->hdr.id %d att->hdr.name %s att->nc_typeid %d "
569  "att->len %d", __func__, varid, att->hdr.id, att->hdr.name,
570  att->nc_typeid, att->len));
571 
572  /* Get HDF5-specific group info. */
573  hdf5_grp = (NC_HDF5_GRP_INFO_T *)grp->format_grp_info;
574 
575  /* If the file is read-only, return an error. */
576  if (grp->nc4_info->no_write)
577  BAIL(NC_EPERM);
578 
579  /* Get the hid to attach the attribute to, or read it from. */
580  if (varid == NC_GLOBAL)
581  locid = hdf5_grp->hdf_grpid;
582  else
583  {
584  if ((retval = nc4_open_var_grp2(grp, varid, &datasetid)))
585  BAIL(retval);
586  locid = datasetid;
587  }
588 
589  /* Get the length ready, and find the HDF type we'll be
590  * writing. */
591  dims[0] = att->len;
592  if ((retval = nc4_get_hdf_typeid(grp->nc4_info, att->nc_typeid,
593  &file_typeid, 0)))
594  BAIL(retval);
595 
596  /* Even if the length is zero, HDF5 won't let me write with a
597  * NULL pointer. So if the length of the att is zero, point to
598  * some phoney data (which won't be written anyway.)*/
599  if (!dims[0])
600  data = &phoney_data;
601  else if (att->data)
602  data = att->data;
603  else if (att->stdata)
604  data = att->stdata;
605  else
606  data = att->vldata;
607 
608  /* NC_CHAR types require some extra work. The space ID is set to
609  * scalar, and the type is told how long the string is. If it's
610  * really zero length, set the size to 1. (The fact that it's
611  * really zero will be marked by the NULL dataspace, but HDF5
612  * doesn't allow me to set the size of the type to zero.)*/
613  if (att->nc_typeid == NC_CHAR)
614  {
615  size_t string_size = dims[0];
616  if (!string_size)
617  {
618  string_size = 1;
619  if ((spaceid = H5Screate(H5S_NULL)) < 0)
620  BAIL(NC_EATTMETA);
621  }
622  else
623  {
624  if ((spaceid = H5Screate(H5S_SCALAR)) < 0)
625  BAIL(NC_EATTMETA);
626  }
627  if (H5Tset_size(file_typeid, string_size) < 0)
628  BAIL(NC_EATTMETA);
629  if (H5Tset_strpad(file_typeid, H5T_STR_NULLTERM) < 0)
630  BAIL(NC_EATTMETA);
631  }
632  else
633  {
634  if (!att->len)
635  {
636  if ((spaceid = H5Screate(H5S_NULL)) < 0)
637  BAIL(NC_EATTMETA);
638  }
639  else
640  {
641  if ((spaceid = H5Screate_simple(1, dims, NULL)) < 0)
642  BAIL(NC_EATTMETA);
643  }
644  }
645 
646  /* Does the att exists already? */
647  if ((attr_exists = H5Aexists(locid, att->hdr.name)) < 0)
648  BAIL(NC_EHDFERR);
649  if (attr_exists)
650  {
651  hssize_t npoints;
652 
653  /* Open the attribute. */
654  if ((existing_attid = H5Aopen(locid, att->hdr.name, H5P_DEFAULT)) < 0)
655  BAIL(NC_EATTMETA);
656 
657  /* Find the type of the existing attribute. */
658  if ((existing_att_typeid = H5Aget_type(existing_attid)) < 0)
659  BAIL(NC_EATTMETA);
660 
661  /* How big is the attribute? */
662  if ((existing_spaceid = H5Aget_space(existing_attid)) < 0)
663  BAIL(NC_EATTMETA);
664  if ((npoints = H5Sget_simple_extent_npoints(existing_spaceid)) < 0)
665  BAIL(NC_EATTMETA);
666 
667  /* Delete the attribute. */
668  if (file_typeid != existing_att_typeid || npoints != att->len)
669  {
670  if (H5Adelete(locid, att->hdr.name) < 0)
671  BAIL(NC_EHDFERR);
672  }
673  else
674  {
675  reuse_att++;
676  }
677  }
678 
679  /* Create the attribute. */
680  if ((attid = H5Acreate(locid, att->hdr.name, file_typeid, spaceid,
681  H5P_DEFAULT)) < 0)
682  BAIL(NC_EATTMETA);
683 
684  /* Write the values, (even if length is zero). */
685  if (H5Awrite(attid, file_typeid, data) < 0)
686  BAIL(NC_EATTMETA);
687 
688 exit:
689  if (file_typeid && H5Tclose(file_typeid))
690  BAIL2(NC_EHDFERR);
691  if (attid > 0 && H5Aclose(attid) < 0)
692  BAIL2(NC_EHDFERR);
693  if (existing_att_typeid && H5Tclose(existing_att_typeid))
694  BAIL2(NC_EHDFERR);
695  if (existing_attid > 0 && H5Aclose(existing_attid) < 0)
696  BAIL2(NC_EHDFERR);
697  if (spaceid > 0 && H5Sclose(spaceid) < 0)
698  BAIL2(NC_EHDFERR);
699  if (existing_spaceid > 0 && H5Sclose(existing_spaceid) < 0)
700  BAIL2(NC_EHDFERR);
701  return retval;
702 }
703 
715 static int
716 write_attlist(NCindex *attlist, int varid, NC_GRP_INFO_T *grp)
717 {
718  NC_ATT_INFO_T *att;
719  int retval;
720  int i;
721 
722  for(i = 0; i < ncindexsize(attlist); i++)
723  {
724  att = (NC_ATT_INFO_T *)ncindexith(attlist, i);
725  assert(att);
726  if (att->dirty)
727  {
728  LOG((4, "%s: writing att %s to varid %d", __func__, att->hdr.name, varid));
729  if ((retval = put_att_grpa(grp, varid, att)))
730  return retval;
731  att->dirty = NC_FALSE;
732  att->created = NC_TRUE;
733  }
734  }
735  return NC_NOERR;
736 }
737 
751 static int
752 write_coord_dimids(NC_VAR_INFO_T *var)
753 {
754  hsize_t coords_len[1];
755  hid_t c_spaceid = -1, c_attid = -1;
756  int retval = NC_NOERR;
757 
758  /* Set up space for attribute. */
759  coords_len[0] = var->ndims;
760  if ((c_spaceid = H5Screate_simple(1, coords_len, coords_len)) < 0)
761  BAIL(NC_EHDFERR);
762 
763  /* Create the attribute. */
764  if ((c_attid = H5Acreate(var->hdf_datasetid, COORDINATES, H5T_NATIVE_INT,
765  c_spaceid, H5P_DEFAULT)) < 0)
766  BAIL(NC_EHDFERR);
767 
768  /* Write our attribute. */
769  if (H5Awrite(c_attid, H5T_NATIVE_INT, var->dimids) < 0)
770  BAIL(NC_EHDFERR);
771 
772 exit:
773  if (c_spaceid >= 0 && H5Sclose(c_spaceid) < 0)
774  BAIL2(NC_EHDFERR);
775  if (c_attid >= 0 && H5Aclose(c_attid) < 0)
776  BAIL2(NC_EHDFERR);
777  return retval;
778 }
779 
790 static int
791 write_netcdf4_dimid(hid_t datasetid, int dimid)
792 {
793  hid_t dimid_spaceid, dimid_attid;
794  htri_t attr_exists;
795 
796  /* Create the space. */
797  if ((dimid_spaceid = H5Screate(H5S_SCALAR)) < 0)
798  return NC_EHDFERR;
799 
800  /* Does the attribute already exist? If so, don't try to create it. */
801  if ((attr_exists = H5Aexists(datasetid, NC_DIMID_ATT_NAME)) < 0)
802  return NC_EHDFERR;
803  if (attr_exists)
804  dimid_attid = H5Aopen_by_name(datasetid, ".", NC_DIMID_ATT_NAME,
805  H5P_DEFAULT, H5P_DEFAULT);
806  else
807  /* Create the attribute if needed. */
808  dimid_attid = H5Acreate(datasetid, NC_DIMID_ATT_NAME,
809  H5T_NATIVE_INT, dimid_spaceid, H5P_DEFAULT);
810  if (dimid_attid < 0)
811  return NC_EHDFERR;
812 
813 
814  /* Write it. */
815  LOG((4, "%s: writing secret dimid %d", __func__, dimid));
816  if (H5Awrite(dimid_attid, H5T_NATIVE_INT, &dimid) < 0)
817  return NC_EHDFERR;
818 
819  /* Close stuff*/
820  if (H5Sclose(dimid_spaceid) < 0)
821  return NC_EHDFERR;
822  if (H5Aclose(dimid_attid) < 0)
823  return NC_EHDFERR;
824 
825  return NC_NOERR;
826 }
827 
842 static int
843 var_create_dataset(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, nc_bool_t write_dimid)
844 {
845  NC_HDF5_GRP_INFO_T *hdf5_grp;
846  hid_t plistid = 0, access_plistid = 0, typeid = 0, spaceid = 0;
847  hsize_t chunksize[H5S_MAX_RANK], dimsize[H5S_MAX_RANK], maxdimsize[H5S_MAX_RANK];
848  int d;
849  void *fillp = NULL;
850  NC_DIM_INFO_T *dim = NULL;
851  char *name_to_use;
852  int retval;
853 
854  assert(grp && grp->format_grp_info && var);
855 
856  LOG((3, "%s:: name %s", __func__, var->hdr.name));
857 
858  /* Get HDF5-specific group info. */
859  hdf5_grp = (NC_HDF5_GRP_INFO_T *)grp->format_grp_info;
860 
861  /* Scalar or not, we need a creation property list. */
862  if ((plistid = H5Pcreate(H5P_DATASET_CREATE)) < 0)
863  BAIL(NC_EHDFERR);
864  if ((access_plistid = H5Pcreate(H5P_DATASET_ACCESS)) < 0)
865  BAIL(NC_EHDFERR);
866 
867  /* Turn off object tracking times in HDF5. */
868  if (H5Pset_obj_track_times(plistid, 0) < 0)
869  BAIL(NC_EHDFERR);
870 
871  /* Find the HDF5 type of the dataset. */
872  if ((retval = nc4_get_hdf_typeid(grp->nc4_info, var->type_info->hdr.id, &typeid,
873  var->type_info->endianness)))
874  BAIL(retval);
875 
876  /* Figure out what fill value to set, if any. */
877  if (var->no_fill)
878  {
879  /* Required to truly turn HDF5 fill values off */
880  if (H5Pset_fill_time(plistid, H5D_FILL_TIME_NEVER) < 0)
881  BAIL(NC_EHDFERR);
882  }
883  else
884  {
885  if ((retval = nc4_get_fill_value(grp->nc4_info, var, &fillp)))
886  BAIL(retval);
887 
888  /* If there is a fill value, set it. */
889  if (fillp)
890  {
891  if (var->type_info->nc_type_class == NC_STRING)
892  {
893  if (H5Pset_fill_value(plistid, typeid, fillp) < 0)
894  BAIL(NC_EHDFERR);
895  }
896  else
897  {
898  /* The fill value set in HDF5 must always be presented as
899  * a native type, even if the endianness for this dataset
900  * is non-native. HDF5 will translate the fill value to
901  * the target endiannesss. */
902  hid_t fill_typeid = 0;
903 
904  if ((retval = nc4_get_hdf_typeid(grp->nc4_info, var->type_info->hdr.id, &fill_typeid,
906  BAIL(retval);
907  if (H5Pset_fill_value(plistid, fill_typeid, fillp) < 0)
908  {
909  if (H5Tclose(fill_typeid) < 0)
910  BAIL(NC_EHDFERR);
911  BAIL(NC_EHDFERR);
912  }
913  if (H5Tclose(fill_typeid) < 0)
914  BAIL(NC_EHDFERR);
915  }
916  }
917  }
918 
919  /* If the user wants to shuffle the data, set that up now. */
920  if (var->shuffle) {
921  if (H5Pset_shuffle(plistid) < 0)
922  BAIL(NC_EHDFERR);
923  }
924 
925  /* If the user wants to deflate the data, set that up now. */
926  if (var->deflate) {
927  if (H5Pset_deflate(plistid, var->deflate_level) < 0)
928  BAIL(NC_EHDFERR);
929  } else if(var->filterid) {
930  /* Handle szip case here */
931  if(var->filterid == H5Z_FILTER_SZIP) {
932  int options_mask;
933  int bits_per_pixel;
934  if(var->nparams != 2)
935  BAIL(NC_EFILTER);
936  options_mask = (int)var->params[0];
937  bits_per_pixel = (int)var->params[1];
938  if(H5Pset_szip(plistid, options_mask, bits_per_pixel) < 0)
939  BAIL(NC_EFILTER);
940  } else {
941  herr_t code = H5Pset_filter(plistid, var->filterid, H5Z_FLAG_MANDATORY, var->nparams, var->params);
942  if(code < 0) {
943  BAIL(NC_EFILTER);
944  }
945  }
946  }
947 
948  /* If the user wants to fletcher error correcton, set that up now. */
949  if (var->fletcher32)
950  if (H5Pset_fletcher32(plistid) < 0)
951  BAIL(NC_EHDFERR);
952 
953  /* If ndims non-zero, get info for all dimensions. We look up the
954  dimids and get the len of each dimension. We need this to create
955  the space for the dataset. In netCDF a dimension length of zero
956  means an unlimited dimension. */
957  if (var->ndims)
958  {
959  int unlimdim = 0;
960 
961  /* Check to see if any unlimited dimensions are used in this var. */
962  for (d = 0; d < var->ndims; d++) {
963  dim = var->dim[d];
964  assert(dim && dim->hdr.id == var->dimids[d]);
965  if (dim->unlimited)
966  unlimdim++;
967  }
968 
969  /* If there are no unlimited dims, and no filters, and the user
970  * has not specified chunksizes, use contiguous variable for
971  * better performance. */
972  if (!var->shuffle && !var->deflate && !var->fletcher32 &&
973  (var->chunksizes == NULL || !var->chunksizes[0]) && !unlimdim)
974  var->contiguous = NC_TRUE;
975 
976  /* Gather current & maximum dimension sizes, along with chunk sizes */
977  for (d = 0; d < var->ndims; d++)
978  {
979  dim = var->dim[d];
980  assert(dim && dim->hdr.id == var->dimids[d]);
981  dimsize[d] = dim->unlimited ? NC_HDF5_UNLIMITED_DIMSIZE : dim->len;
982  maxdimsize[d] = dim->unlimited ? H5S_UNLIMITED : (hsize_t)dim->len;
983  if (!var->contiguous) {
984  if (var->chunksizes[d])
985  chunksize[d] = var->chunksizes[d];
986  else
987  {
988  size_t type_size;
989  if (var->type_info->nc_type_class == NC_STRING)
990  type_size = sizeof(char *);
991  else
992  type_size = var->type_info->size;
993 
994  /* Unlimited dim always gets chunksize of 1. */
995  if (dim->unlimited)
996  chunksize[d] = 1;
997  else
998  chunksize[d] = pow((double)DEFAULT_CHUNK_SIZE/type_size,
999  1/(double)(var->ndims - unlimdim));
1000 
1001  /* If the chunksize is greater than the dim
1002  * length, make it the dim length. */
1003  if (!dim->unlimited && chunksize[d] > dim->len)
1004  chunksize[d] = dim->len;
1005 
1006  /* Remember the computed chunksize */
1007  var->chunksizes[d] = chunksize[d];
1008  }
1009  }
1010  }
1011 
1012  if (var->contiguous)
1013  {
1014  if (H5Pset_layout(plistid, H5D_CONTIGUOUS) < 0)
1015  BAIL(NC_EHDFERR);
1016  }
1017  else
1018  {
1019  if (H5Pset_chunk(plistid, var->ndims, chunksize) < 0)
1020  BAIL(NC_EHDFERR);
1021  }
1022 
1023  /* Create the dataspace. */
1024  if ((spaceid = H5Screate_simple(var->ndims, dimsize, maxdimsize)) < 0)
1025  BAIL(NC_EHDFERR);
1026  }
1027  else
1028  {
1029  if ((spaceid = H5Screate(H5S_SCALAR)) < 0)
1030  BAIL(NC_EHDFERR);
1031  }
1032 
1033  /* Turn on creation order tracking. */
1034  if (H5Pset_attr_creation_order(plistid, H5P_CRT_ORDER_TRACKED|
1035  H5P_CRT_ORDER_INDEXED) < 0)
1036  BAIL(NC_EHDFERR);
1037 
1038  /* Set per-var chunk cache, for chunked datasets. */
1039  if (!var->contiguous && var->chunk_cache_size)
1040  if (H5Pset_chunk_cache(access_plistid, var->chunk_cache_nelems,
1041  var->chunk_cache_size, var->chunk_cache_preemption) < 0)
1042  BAIL(NC_EHDFERR);
1043 
1044  /* At long last, create the dataset. */
1045  name_to_use = var->hdf5_name ? var->hdf5_name : var->hdr.name;
1046  LOG((4, "%s: about to H5Dcreate2 dataset %s of type 0x%x", __func__,
1047  name_to_use, typeid));
1048  if ((var->hdf_datasetid = H5Dcreate2(hdf5_grp->hdf_grpid, name_to_use, typeid,
1049  spaceid, H5P_DEFAULT, plistid, access_plistid)) < 0)
1050  BAIL(NC_EHDFERR);
1051  var->created = NC_TRUE;
1052  var->is_new_var = NC_FALSE;
1053 
1054  /* If this is a dimscale, mark it as such in the HDF5 file. Also
1055  * find the dimension info and store the dataset id of the dimscale
1056  * dataset. */
1057  if (var->dimscale)
1058  {
1059  if (H5DSset_scale(var->hdf_datasetid, var->hdr.name) < 0)
1060  BAIL(NC_EHDFERR);
1061 
1062  /* If this is a multidimensional coordinate variable, write a
1063  * coordinates attribute. */
1064  if (var->ndims > 1)
1065  if ((retval = write_coord_dimids(var)))
1066  BAIL(retval);
1067 
1068  /* If desired, write the netCDF dimid. */
1069  if (write_dimid)
1070  if ((retval = write_netcdf4_dimid(var->hdf_datasetid, var->dimids[0])))
1071  BAIL(retval);
1072  }
1073 
1074  /* Write attributes for this var. */
1075  if ((retval = write_attlist(var->att, var->hdr.id, grp)))
1076  BAIL(retval);
1077  var->attr_dirty = NC_FALSE;
1078 
1079 exit:
1080  if (typeid > 0 && H5Tclose(typeid) < 0)
1081  BAIL2(NC_EHDFERR);
1082  if (plistid > 0 && H5Pclose(plistid) < 0)
1083  BAIL2(NC_EHDFERR);
1084  if (access_plistid > 0 && H5Pclose(access_plistid) < 0)
1085  BAIL2(NC_EHDFERR);
1086  if (spaceid > 0 && H5Sclose(spaceid) < 0)
1087  BAIL2(NC_EHDFERR);
1088  if (fillp)
1089  {
1090  if (var->type_info->nc_type_class == NC_VLEN)
1091  nc_free_vlen((nc_vlen_t *)fillp);
1092  else if (var->type_info->nc_type_class == NC_STRING && *(char **)fillp)
1093  free(*(char **)fillp);
1094  free(fillp);
1095  }
1096 
1097  return retval;
1098 }
1099 
1110 int
1111 nc4_adjust_var_cache(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var)
1112 {
1113  size_t chunk_size_bytes = 1;
1114  int d;
1115  int retval;
1116 
1117  /* Nothing to be done. */
1118  if (var->contiguous)
1119  return NC_NOERR;
1120 #ifdef USE_PARALLEL4
1121  return NC_NOERR;
1122 #endif
1123 
1124  /* How many bytes in the chunk? */
1125  for (d = 0; d < var->ndims; d++)
1126  chunk_size_bytes *= var->chunksizes[d];
1127  if (var->type_info->size)
1128  chunk_size_bytes *= var->type_info->size;
1129  else
1130  chunk_size_bytes *= sizeof(char *);
1131 
1132  /* If the chunk cache is too small, and the user has not changed
1133  * the default value of the chunk cache size, then increase the
1134  * size of the cache. */
1135  if (var->chunk_cache_size == CHUNK_CACHE_SIZE)
1136  if (chunk_size_bytes > var->chunk_cache_size)
1137  {
1138  var->chunk_cache_size = chunk_size_bytes * DEFAULT_CHUNKS_IN_CACHE;
1139  if (var->chunk_cache_size > MAX_DEFAULT_CACHE_SIZE)
1140  var->chunk_cache_size = MAX_DEFAULT_CACHE_SIZE;
1141  if ((retval = nc4_reopen_dataset(grp, var)))
1142  return retval;
1143  }
1144 
1145  return NC_NOERR;
1146 }
1147 
1163 static int
1164 commit_type(NC_GRP_INFO_T *grp, NC_TYPE_INFO_T *type)
1165 {
1166  NC_HDF5_GRP_INFO_T *hdf5_grp;
1167  int retval;
1168 
1169  assert(grp && grp->format_grp_info && type);
1170 
1171  /* Get HDF5-specific group info. */
1172  hdf5_grp = (NC_HDF5_GRP_INFO_T *)grp->format_grp_info;
1173 
1174  /* Did we already record this type? */
1175  if (type->committed)
1176  return NC_NOERR;
1177 
1178  /* Is this a compound type? */
1179  if (type->nc_type_class == NC_COMPOUND)
1180  {
1181  NC_FIELD_INFO_T *field;
1182  hid_t hdf_base_typeid, hdf_typeid;
1183  int i;
1184 
1185  if ((type->hdf_typeid = H5Tcreate(H5T_COMPOUND, type->size)) < 0)
1186  return NC_EHDFERR;
1187  LOG((4, "creating compound type %s hdf_typeid 0x%x", type->hdr.name,
1188  type->hdf_typeid));
1189 
1190  for(i=0;i<nclistlength(type->u.c.field);i++)
1191  {
1192  field = (NC_FIELD_INFO_T *)nclistget(type->u.c.field, i);
1193  assert(field);
1194  if ((retval = nc4_get_hdf_typeid(grp->nc4_info, field->nc_typeid,
1195  &hdf_base_typeid, type->endianness)))
1196  return retval;
1197 
1198  /* If this is an array, create a special array type. */
1199  if (field->ndims)
1200  {
1201  int d;
1202  hsize_t dims[NC_MAX_VAR_DIMS];
1203 
1204  for (d = 0; d < field->ndims; d++)
1205  dims[d] = field->dim_size[d];
1206  if ((hdf_typeid = H5Tarray_create(hdf_base_typeid, field->ndims,
1207  dims, NULL)) < 0)
1208  {
1209  if (H5Tclose(hdf_base_typeid) < 0)
1210  return NC_EHDFERR;
1211  return NC_EHDFERR;
1212  }
1213  if (H5Tclose(hdf_base_typeid) < 0)
1214  return NC_EHDFERR;
1215  }
1216  else
1217  hdf_typeid = hdf_base_typeid;
1218  LOG((4, "inserting field %s offset %d hdf_typeid 0x%x", field->hdr.name,
1219  field->offset, hdf_typeid));
1220  if (H5Tinsert(type->hdf_typeid, field->hdr.name, field->offset,
1221  hdf_typeid) < 0)
1222  return NC_EHDFERR;
1223  if (H5Tclose(hdf_typeid) < 0)
1224  return NC_EHDFERR;
1225  }
1226  }
1227  else if (type->nc_type_class == NC_VLEN)
1228  {
1229  /* Find the HDF typeid of the base type of this vlen. */
1230  if ((retval = nc4_get_hdf_typeid(grp->nc4_info, type->u.v.base_nc_typeid,
1231  &type->u.v.base_hdf_typeid, type->endianness)))
1232  return retval;
1233 
1234  /* Create a vlen type. */
1235  if ((type->hdf_typeid = H5Tvlen_create(type->u.v.base_hdf_typeid)) < 0)
1236  return NC_EHDFERR;
1237  }
1238  else if (type->nc_type_class == NC_OPAQUE)
1239  {
1240  /* Create the opaque type. */
1241  if ((type->hdf_typeid = H5Tcreate(H5T_OPAQUE, type->size)) < 0)
1242  return NC_EHDFERR;
1243  }
1244  else if (type->nc_type_class == NC_ENUM)
1245  {
1246  NC_ENUM_MEMBER_INFO_T *enum_m;
1247  int i;
1248 
1249  if (nclistlength(type->u.e.enum_member) == 0)
1250  return NC_EINVAL;
1251 
1252  /* Find the HDF typeid of the base type of this enum. */
1253  if ((retval = nc4_get_hdf_typeid(grp->nc4_info, type->u.e.base_nc_typeid,
1254  &type->u.e.base_hdf_typeid, type->endianness)))
1255  return retval;
1256 
1257  /* Create an enum type. */
1258  if ((type->hdf_typeid = H5Tenum_create(type->u.e.base_hdf_typeid)) < 0)
1259  return NC_EHDFERR;
1260 
1261  /* Add all the members to the HDF5 type. */
1262  for(i=0;i<nclistlength(type->u.e.enum_member);i++) {
1263  enum_m = (NC_ENUM_MEMBER_INFO_T*)nclistget(type->u.e.enum_member,i);
1264  if (H5Tenum_insert(type->hdf_typeid, enum_m->name, enum_m->value) < 0)
1265  return NC_EHDFERR;
1266  }
1267  }
1268  else
1269  {
1270  LOG((0, "Unknown class: %d", type->nc_type_class));
1271  return NC_EBADTYPE;
1272  }
1273 
1274  /* Commit the type. */
1275  if (H5Tcommit(hdf5_grp->hdf_grpid, type->hdr.name, type->hdf_typeid) < 0)
1276  return NC_EHDFERR;
1277  type->committed = NC_TRUE;
1278  LOG((4, "just committed type %s, HDF typeid: 0x%x", type->hdr.name,
1279  type->hdf_typeid));
1280 
1281  /* Later we will always use the native typeid. In this case, it is
1282  * a copy of the same type pointed to by hdf_typeid, but it's
1283  * easier to maintain a copy. */
1284  if ((type->native_hdf_typeid = H5Tget_native_type(type->hdf_typeid,
1285  H5T_DIR_DEFAULT)) < 0)
1286  return NC_EHDFERR;
1287 
1288  return NC_NOERR;
1289 }
1290 
1301 static int
1302 write_nc3_strict_att(hid_t hdf_grpid)
1303 {
1304  hid_t attid = 0, spaceid = 0;
1305  int one = 1;
1306  int retval = NC_NOERR;
1307  htri_t attr_exists;
1308 
1309  /* If the attribute already exists, call that a success and return
1310  * NC_NOERR. */
1311  if ((attr_exists = H5Aexists(hdf_grpid, NC3_STRICT_ATT_NAME)) < 0)
1312  return NC_EHDFERR;
1313  if (attr_exists)
1314  return NC_NOERR;
1315 
1316  /* Create the attribute to mark this as a file that needs to obey
1317  * strict netcdf-3 rules. */
1318  if ((spaceid = H5Screate(H5S_SCALAR)) < 0)
1319  BAIL(NC_EFILEMETA);
1320  if ((attid = H5Acreate(hdf_grpid, NC3_STRICT_ATT_NAME,
1321  H5T_NATIVE_INT, spaceid, H5P_DEFAULT)) < 0)
1322  BAIL(NC_EFILEMETA);
1323  if (H5Awrite(attid, H5T_NATIVE_INT, &one) < 0)
1324  BAIL(NC_EFILEMETA);
1325 
1326 exit:
1327  if (spaceid > 0 && (H5Sclose(spaceid) < 0))
1328  BAIL2(NC_EFILEMETA);
1329  if (attid > 0 && (H5Aclose(attid) < 0))
1330  BAIL2(NC_EFILEMETA);
1331  return retval;
1332 }
1333 
1346 static int
1347 create_group(NC_GRP_INFO_T *grp)
1348 {
1349  NC_HDF5_GRP_INFO_T *hdf5_grp, *parent_hdf5_grp;
1350  hid_t gcpl_id = -1;
1351  int retval = NC_NOERR;;
1352 
1353  assert(grp && grp->format_grp_info && grp->parent &&
1354  grp->parent->format_grp_info);
1355 
1356  /* Get HDF5 specific group info for group and parent. */
1357  hdf5_grp = (NC_HDF5_GRP_INFO_T *)grp->format_grp_info;
1358  parent_hdf5_grp = (NC_HDF5_GRP_INFO_T *)grp->parent->format_grp_info;
1359  assert(parent_hdf5_grp->hdf_grpid);
1360 
1361  /* Create group, with link_creation_order set in the group
1362  * creation property list. */
1363  if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0)
1364  BAIL(NC_EHDFERR);
1365 
1366  /* Set track_times to be FALSE. */
1367  if (H5Pset_obj_track_times(gcpl_id, 0) < 0)
1368  BAIL(NC_EHDFERR);
1369 
1370  /* Tell HDF5 to keep track of objects in creation order. */
1371  if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED|H5P_CRT_ORDER_INDEXED) < 0)
1372  BAIL(NC_EHDFERR);
1373 
1374  /* Tell HDF5 to keep track of attributes in creation order. */
1375  if (H5Pset_attr_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED|H5P_CRT_ORDER_INDEXED) < 0)
1376  BAIL(NC_EHDFERR);
1377 
1378  /* Create the group. */
1379  if ((hdf5_grp->hdf_grpid = H5Gcreate2(parent_hdf5_grp->hdf_grpid, grp->hdr.name,
1380  H5P_DEFAULT, gcpl_id, H5P_DEFAULT)) < 0)
1381  BAIL(NC_EHDFERR);
1382 
1383 exit:
1384  if (gcpl_id > -1 && H5Pclose(gcpl_id) < 0)
1385  BAIL2(NC_EHDFERR);
1386  if (retval)
1387  if (hdf5_grp->hdf_grpid > 0 && H5Gclose(hdf5_grp->hdf_grpid) < 0)
1388  BAIL2(NC_EHDFERR);
1389  return retval;
1390 }
1391 
1403 static int
1404 attach_dimscales(NC_GRP_INFO_T *grp)
1405 {
1406  NC_VAR_INFO_T *var;
1407  NC_DIM_INFO_T *dim1;
1408  int d, i;
1409  int retval = NC_NOERR;
1410 
1411  /* Attach dimension scales. */
1412  for(i=0;i<ncindexsize(grp->vars);i++)
1413  {
1414  var = (NC_VAR_INFO_T*)ncindexith(grp->vars,i);
1415  if (!var) continue;
1416  /* Scales themselves do not attach. But I really wish they
1417  * would. */
1418  if (var->dimscale)
1419  {
1420  /* If this is a multidimensional coordinate variable, it will
1421  * have a special coords attribute (read earlier) with a list
1422  * of the dimensions for this variable. */
1423  }
1424  else /* not a dimscale... */
1425  {
1426  /* Find the scale for each dimension, if any, and attach it. */
1427  for (d = 0; d < var->ndims; d++)
1428  {
1429  /* Is there a dimscale for this dimension? */
1430  if (var->dimscale_attached)
1431  {
1432  if (!var->dimscale_attached[d])
1433  {
1434  NC_HDF5_DIM_INFO_T *hdf5_dim1;
1435  hid_t dim_datasetid; /* Dataset ID for dimension */
1436  dim1 = var->dim[d];
1437  assert(dim1 && dim1->hdr.id == var->dimids[d] && dim1->format_dim_info);
1438  hdf5_dim1 = (NC_HDF5_DIM_INFO_T *)dim1->format_dim_info;
1439 
1440  LOG((2, "%s: attaching scale for dimid %d to var %s",
1441  __func__, var->dimids[d], var->hdr.name));
1442 
1443  /* Find dataset ID for dimension */
1444  if (dim1->coord_var)
1445  dim_datasetid = dim1->coord_var->hdf_datasetid;
1446  else
1447  dim_datasetid = hdf5_dim1->hdf_dimscaleid;
1448  if(!(dim_datasetid > 0))
1449  assert(dim_datasetid > 0);
1450  if (H5DSattach_scale(var->hdf_datasetid, dim_datasetid, d) < 0)
1451  BAIL(NC_EHDFERR);
1452  var->dimscale_attached[d] = NC_TRUE;
1453  }
1454 
1455  /* If we didn't find a dimscale to attach, that's a problem! */
1456  if (!var->dimscale_attached[d])
1457  {
1458  LOG((0, "no dimscale found!"));
1459  return NC_EDIMSCALE;
1460  }
1461  }
1462  }
1463  }
1464  }
1465 
1466 exit:
1467  return retval;
1468 }
1469 
1480 static int
1481 var_exists(hid_t grpid, char *name, nc_bool_t *exists)
1482 {
1483  htri_t link_exists;
1484 
1485  /* Reset the boolean */
1486  *exists = NC_FALSE;
1487 
1488  /* Check if the object name exists in the group */
1489  if ((link_exists = H5Lexists(grpid, name, H5P_DEFAULT)) < 0)
1490  return NC_EHDFERR;
1491  if (link_exists)
1492  {
1493  H5G_stat_t statbuf;
1494 
1495  /* Get info about the object */
1496  if (H5Gget_objinfo(grpid, name, 1, &statbuf) < 0)
1497  return NC_EHDFERR;
1498 
1499  if (H5G_DATASET == statbuf.type)
1500  *exists = NC_TRUE;
1501  }
1502 
1503  return NC_NOERR;
1504 }
1505 
1520 int
1521 remove_coord_atts(hid_t hdf_datasetid)
1522 {
1523  htri_t attr_exists;
1524 
1525  /* If the variable dataset has an optional NC_DIMID_ATT_NAME
1526  * attribute, delete it. */
1527  if ((attr_exists = H5Aexists(hdf_datasetid, NC_DIMID_ATT_NAME)) < 0)
1528  return NC_EHDFERR;
1529  if (attr_exists)
1530  {
1531  if (H5Adelete(hdf_datasetid, NC_DIMID_ATT_NAME) < 0)
1532  return NC_EHDFERR;
1533  }
1534 
1535  /* (We could do a better job here and verify that the attributes are
1536  * really dimension scale 'CLASS' & 'NAME' attributes, but that would be
1537  * poking about in the HDF5 DimScale internal data) */
1538  if ((attr_exists = H5Aexists(hdf_datasetid, HDF5_DIMSCALE_CLASS_ATT_NAME)) < 0)
1539  return NC_EHDFERR;
1540  if (attr_exists)
1541  {
1542  if (H5Adelete(hdf_datasetid, HDF5_DIMSCALE_CLASS_ATT_NAME) < 0)
1543  return NC_EHDFERR;
1544  }
1545  if ((attr_exists = H5Aexists(hdf_datasetid, HDF5_DIMSCALE_NAME_ATT_NAME)) < 0)
1546  return NC_EHDFERR;
1547  if (attr_exists)
1548  {
1549  if (H5Adelete(hdf_datasetid, HDF5_DIMSCALE_NAME_ATT_NAME) < 0)
1550  return NC_EHDFERR;
1551  }
1552  return NC_NOERR;
1553 }
1554 
1569 static int
1570 write_var(NC_VAR_INFO_T *var, NC_GRP_INFO_T *grp, nc_bool_t write_dimid)
1571 {
1572  NC_HDF5_GRP_INFO_T *hdf5_grp;
1573  nc_bool_t replace_existing_var = NC_FALSE;
1574  int retval;
1575 
1576  assert(var && grp && grp->format_grp_info);
1577 
1578  LOG((4, "%s: writing var %s", __func__, var->hdr.name));
1579 
1580  /* Get HDF5-specific group info. */
1581  hdf5_grp = (NC_HDF5_GRP_INFO_T *)grp->format_grp_info;
1582 
1583  /* If the variable has already been created & the fill value changed,
1584  * indicate that the existing variable should be replaced. */
1585  if (var->created && var->fill_val_changed)
1586  {
1587  replace_existing_var = NC_TRUE;
1588  var->fill_val_changed = NC_FALSE;
1589  /* If the variable is going to be replaced,
1590  we need to flag any other attributes associated
1591  with the variable as 'dirty', or else
1592  *only* the fill value attribute will be copied over
1593  and the rest will be lost. See:
1594 
1595  * https://github.com/Unidata/netcdf-c/issues/239 */
1596 
1597  flag_atts_dirty(var->att);
1598  }
1599 
1600  /* Is this a coordinate var that has already been created in
1601  * the HDF5 file as a dimscale dataset? Check for dims with the
1602  * same name in this group. If there is one, check to see if
1603  * this object exists in the HDF group. */
1604  if (var->became_coord_var)
1605  {
1606  NC_DIM_INFO_T *d1;
1607  int i;
1608 
1609  for (i = 0; i < ncindexsize(grp->dim); i++)
1610  {
1611  d1 = (NC_DIM_INFO_T*)ncindexith(grp->dim,i);
1612  assert(d1);
1613  if (!strcmp(d1->hdr.name, var->hdr.name))
1614  {
1615  nc_bool_t exists;
1616 
1617  if ((retval = var_exists(hdf5_grp->hdf_grpid, var->hdr.name, &exists)))
1618  return retval;
1619  if (exists)
1620  {
1621  /* Indicate that the variable already exists, and should be replaced */
1622  replace_existing_var = NC_TRUE;
1623  flag_atts_dirty(var->att);
1624  break;
1625  }
1626  }
1627  }
1628  }
1629 
1630  /* Check dims if the variable will be replaced, so that the
1631  * dimensions will be de-attached and re-attached correctly. (Note:
1632  * There's a temptation to merge this loop over the dimensions with
1633  * the prior loop over dimensions, but that blurs the line over the
1634  * purpose of them, so they are currently separate. If performance
1635  * becomes an issue here, it would be possible to merge them. -QAK)
1636  */
1637  if (replace_existing_var)
1638  {
1639  int i;
1640 
1641  for (i = 0; i < ncindexsize(grp->dim); i++)
1642  {
1643  NC_DIM_INFO_T *d1;
1644  NC_HDF5_DIM_INFO_T *hdf5_d1;
1645 
1646  /* Get info about the dim, including HDF5-specific info. */
1647  d1 = (NC_DIM_INFO_T *)ncindexith(grp->dim, i);
1648  assert(d1 && d1->format_dim_info && d1->hdr.name);
1649  hdf5_d1 = (NC_HDF5_DIM_INFO_T *)d1->format_dim_info;
1650 
1651  if (!strcmp(d1->hdr.name, var->hdr.name))
1652  {
1653  nc_bool_t exists;
1654 
1655  if ((retval = var_exists(hdf5_grp->hdf_grpid, var->hdr.name,
1656  &exists)))
1657  return retval;
1658  if (exists)
1659  {
1660  hid_t dim_datasetid; /* Dataset ID for dimension */
1661 
1662  /* Find dataset ID for dimension */
1663  if (d1->coord_var)
1664  dim_datasetid = d1->coord_var->hdf_datasetid;
1665  else
1666  dim_datasetid = hdf5_d1->hdf_dimscaleid;
1667  assert(dim_datasetid > 0);
1668 
1669  /* If we're replacing an existing dimscale dataset, go to
1670  * every var in the file and detach this dimension scale,
1671  * because we have to delete it. */
1672  if ((retval = rec_detach_scales(grp->nc4_info->root_grp,
1673  var->dimids[0], dim_datasetid)))
1674  return retval;
1675  break;
1676  }
1677  }
1678  }
1679  }
1680 
1681  /* If this is not a dimension scale, do this stuff. */
1682  if (var->was_coord_var && var->dimscale_attached)
1683  {
1684  /* If the variable already exists in the file, Remove any dimension scale
1685  * attributes from it, if they exist. */
1686  /* (The HDF5 Dimension Scale API should really have an API routine
1687  * for making a dataset not a scale. -QAK) */
1688  if (var->created)
1689  {
1690  if ((retval = remove_coord_atts(var->hdf_datasetid)))
1691  BAIL(retval);
1692  }
1693 
1694  if (var->dimscale_attached)
1695  {
1696  int d;
1697 
1698  /* If this is a regular var, detach all its dim scales. */
1699  for (d = 0; d < var->ndims; d++)
1700  {
1701  if (var->dimscale_attached[d])
1702  {
1703  hid_t dim_datasetid; /* Dataset ID for dimension */
1704  NC_DIM_INFO_T *dim1 = var->dim[d];
1705  NC_HDF5_DIM_INFO_T *hdf5_dim1;
1706  assert(dim1 && dim1->hdr.id == var->dimids[d] && dim1->format_dim_info);
1707  hdf5_dim1 = (NC_HDF5_DIM_INFO_T *)dim1->format_dim_info;
1708 
1709  /* Find dataset ID for dimension */
1710  if (dim1->coord_var)
1711  dim_datasetid = dim1->coord_var->hdf_datasetid;
1712  else
1713  dim_datasetid = hdf5_dim1->hdf_dimscaleid;
1714  assert(dim_datasetid > 0);
1715 
1716  if (H5DSdetach_scale(var->hdf_datasetid, dim_datasetid, d) < 0)
1717  BAIL(NC_EHDFERR);
1718  var->dimscale_attached[d] = NC_FALSE;
1719  }
1720  }
1721  }
1722  }
1723 
1724  /* Delete the HDF5 dataset that is to be replaced. */
1725  if (replace_existing_var)
1726  {
1727  /* Free the HDF5 dataset id. */
1728  if (var->hdf_datasetid && H5Dclose(var->hdf_datasetid) < 0)
1729  BAIL(NC_EHDFERR);
1730  var->hdf_datasetid = 0;
1731 
1732  /* Now delete the variable. */
1733  if (H5Gunlink(hdf5_grp->hdf_grpid, var->hdr.name) < 0)
1734  return NC_EDIMMETA;
1735  }
1736 
1737  /* Create the dataset. */
1738  if (var->is_new_var || replace_existing_var)
1739  {
1740  if ((retval = var_create_dataset(grp, var, write_dimid)))
1741  return retval;
1742  }
1743  else
1744  {
1745  if (write_dimid && var->ndims)
1746  if ((retval = write_netcdf4_dimid(var->hdf_datasetid, var->dimids[0])))
1747  BAIL(retval);
1748  }
1749 
1750  if (replace_existing_var)
1751  {
1752  /* If this is a dimension scale, reattach the scale everywhere it
1753  * is used. (Recall that netCDF dimscales are always 1-D). */
1754  if(var->dimscale)
1755  {
1756  if ((retval = rec_reattach_scales(grp->nc4_info->root_grp,
1757  var->dimids[0], var->hdf_datasetid)))
1758  return retval;
1759  }
1760  /* If it's not a dimension scale, clear the dimscale attached flags,
1761  * so the dimensions are re-attached. */
1762  else
1763  {
1764  if (var->dimscale_attached)
1765  memset(var->dimscale_attached, 0, sizeof(nc_bool_t) * var->ndims);
1766  }
1767  }
1768 
1769  /* Clear coord. var state transition flags */
1770  var->was_coord_var = NC_FALSE;
1771  var->became_coord_var = NC_FALSE;
1772 
1773  /* Now check the attributes for this var. */
1774  if (var->attr_dirty)
1775  {
1776  /* Write attributes for this var. */
1777  if ((retval = write_attlist(var->att, var->hdr.id, grp)))
1778  BAIL(retval);
1779  var->attr_dirty = NC_FALSE;
1780  }
1781 
1782  return NC_NOERR;
1783 exit:
1784  return retval;
1785 }
1786 
1799 static int
1800 write_dim(NC_DIM_INFO_T *dim, NC_GRP_INFO_T *grp, nc_bool_t write_dimid)
1801 {
1802  NC_HDF5_GRP_INFO_T *hdf5_grp;
1803  NC_HDF5_DIM_INFO_T *hdf5_dim;
1804  int retval;
1805 
1806  assert(dim && dim->format_dim_info && grp && grp->format_grp_info);
1807 
1808  /* Get HDF5-specific dim and group info. */
1809  hdf5_dim = (NC_HDF5_DIM_INFO_T *)dim->format_dim_info;
1810  hdf5_grp = (NC_HDF5_GRP_INFO_T *)grp->format_grp_info;
1811 
1812  /* If there's no dimscale dataset for this dim, create one,
1813  * and mark that it should be hidden from netCDF as a
1814  * variable. (That is, it should appear as a dimension
1815  * without an associated variable.) */
1816  if (!hdf5_dim->hdf_dimscaleid)
1817  {
1818  hid_t spaceid, create_propid;
1819  hsize_t dims[1], max_dims[1], chunk_dims[1] = {1};
1820  char dimscale_wo_var[NC_MAX_NAME];
1821 
1822  LOG((4, "%s: creating dim %s", __func__, dim->hdr.name));
1823 
1824  /* Sanity check */
1825  assert(NULL == dim->coord_var);
1826 
1827  /* Create a property list. If this dimension scale is
1828  * unlimited (i.e. it's an unlimited dimension), then set
1829  * up chunking, with a chunksize of 1. */
1830  if ((create_propid = H5Pcreate(H5P_DATASET_CREATE)) < 0)
1831  BAIL(NC_EHDFERR);
1832 
1833  /* RJ: this suppose to be FALSE that is defined in H5 private.h as 0 */
1834  if (H5Pset_obj_track_times(create_propid,0)<0)
1835  BAIL(NC_EHDFERR);
1836 
1837  dims[0] = dim->len;
1838  max_dims[0] = dim->len;
1839  if (dim->unlimited)
1840  {
1841  max_dims[0] = H5S_UNLIMITED;
1842  if (H5Pset_chunk(create_propid, 1, chunk_dims) < 0)
1843  BAIL(NC_EHDFERR);
1844  }
1845 
1846  /* Set up space. */
1847  if ((spaceid = H5Screate_simple(1, dims, max_dims)) < 0)
1848  BAIL(NC_EHDFERR);
1849 
1850  if (H5Pset_attr_creation_order(create_propid, H5P_CRT_ORDER_TRACKED|
1851  H5P_CRT_ORDER_INDEXED) < 0)
1852  BAIL(NC_EHDFERR);
1853 
1854  /* Create the dataset that will be the dimension scale. */
1855  LOG((4, "%s: about to H5Dcreate1 a dimscale dataset %s", __func__, dim->hdr.name));
1856  if ((hdf5_dim->hdf_dimscaleid = H5Dcreate1(hdf5_grp->hdf_grpid, dim->hdr.name, H5T_IEEE_F32BE,
1857  spaceid, create_propid)) < 0)
1858  BAIL(NC_EHDFERR);
1859 
1860  /* Close the spaceid and create_propid. */
1861  if (H5Sclose(spaceid) < 0)
1862  BAIL(NC_EHDFERR);
1863  if (H5Pclose(create_propid) < 0)
1864  BAIL(NC_EHDFERR);
1865 
1866  /* Indicate that this is a scale. Also indicate that not
1867  * be shown to the user as a variable. It is hidden. It is
1868  * a DIM WITHOUT A VARIABLE! */
1869  sprintf(dimscale_wo_var, "%s%10d", DIM_WITHOUT_VARIABLE, (int)dim->len);
1870  if (H5DSset_scale(hdf5_dim->hdf_dimscaleid, dimscale_wo_var) < 0)
1871  BAIL(NC_EHDFERR);
1872  }
1873 
1874  /* Did we extend an unlimited dimension? */
1875  if (dim->extended)
1876  {
1877  NC_VAR_INFO_T *v1 = NULL;
1878 
1879  assert(dim->unlimited);
1880  /* If this is a dimension without a variable, then update
1881  * the secret length information at the end of the NAME
1882  * attribute. */
1883  v1 = (NC_VAR_INFO_T*)ncindexlookup(grp->vars,dim->hdr.name);
1884  if (v1)
1885  {
1886  hsize_t *new_size = NULL;
1887  int d1;
1888 
1889  /* Extend the dimension scale dataset to reflect the new
1890  * length of the dimension. */
1891  if (!(new_size = malloc(v1->ndims * sizeof(hsize_t))))
1892  BAIL(NC_ENOMEM);
1893  for (d1 = 0; d1 < v1->ndims; d1++)
1894  {
1895  assert(v1->dim[d1] && v1->dim[d1]->hdr.id == v1->dimids[d1]);
1896  new_size[d1] = v1->dim[d1]->len;
1897  }
1898  if (H5Dset_extent(v1->hdf_datasetid, new_size) < 0) {
1899  free(new_size);
1900  BAIL(NC_EHDFERR);
1901  }
1902  free(new_size);
1903  }
1904  }
1905 
1906  /* If desired, write the secret dimid. This will be used instead of
1907  * the dimid that the dimension would otherwise receive based on
1908  * creation order. This can be necessary when dims and their
1909  * coordinate variables were created in different order. */
1910  if (write_dimid && hdf5_dim->hdf_dimscaleid)
1911  if ((retval = write_netcdf4_dimid(hdf5_dim->hdf_dimscaleid, dim->hdr.id)))
1912  BAIL(retval);
1913 
1914  return NC_NOERR;
1915 exit:
1916 
1917  return retval;
1918 }
1919 
1936 int
1937 nc4_detect_preserve_dimids(NC_GRP_INFO_T *grp, nc_bool_t *bad_coord_orderp)
1938 {
1939  NC_VAR_INFO_T *var;
1940  NC_GRP_INFO_T *child_grp;
1941  int last_dimid = -1;
1942  int retval;
1943  int i;
1944 
1945  /* Iterate over variables in this group */
1946  for (i=0; i < ncindexsize(grp->vars); i++)
1947  {
1948  var = (NC_VAR_INFO_T*)ncindexith(grp->vars,i);
1949  if (var == NULL) continue;
1950  /* Only matters for dimension scale variables, with non-scalar dimensionality */
1951  if (var->dimscale && var->ndims)
1952  {
1953  /* If the user writes coord vars in a different order then he
1954  * defined their dimensions, then, when the file is reopened, the
1955  * order of the dimids will change to match the order of the coord
1956  * vars. Detect if this is about to happen. */
1957  if (var->dimids[0] < last_dimid)
1958  {
1959  LOG((5, "%s: %s is out of order coord var", __func__, var->hdr.name));
1960  *bad_coord_orderp = NC_TRUE;
1961  return NC_NOERR;
1962  }
1963  last_dimid = var->dimids[0];
1964 
1965  /* If there are multidimensional coordinate variables defined, then
1966  * it's also necessary to preserve dimension IDs when the file is
1967  * reopened ... */
1968  if (var->ndims > 1)
1969  {
1970  LOG((5, "%s: %s is multidimensional coord var", __func__, var->hdr.name));
1971  *bad_coord_orderp = NC_TRUE;
1972  return NC_NOERR;
1973  }
1974 
1975  /* Did the user define a dimension, end define mode, reenter define
1976  * mode, and then define a coordinate variable for that dimension?
1977  * If so, dimensions will be out of order. */
1978  if (var->is_new_var || var->became_coord_var)
1979  {
1980  LOG((5, "%s: coord var defined after enddef/redef", __func__));
1981  *bad_coord_orderp = NC_TRUE;
1982  return NC_NOERR;
1983  }
1984  }
1985  }
1986 
1987  /* If there are any child groups, check them also for this condition. */
1988  for (i = 0; i < ncindexsize(grp->children); i++)
1989  {
1990  if (!(child_grp = (NC_GRP_INFO_T *)ncindexith(grp->children, i)))
1991  continue;
1992  if ((retval = nc4_detect_preserve_dimids(child_grp, bad_coord_orderp)))
1993  return retval;
1994  }
1995  return NC_NOERR;
1996 }
1997 
2010 int
2011 nc4_rec_write_metadata(NC_GRP_INFO_T *grp, nc_bool_t bad_coord_order)
2012 {
2013  NC_DIM_INFO_T *dim = NULL;
2014  NC_VAR_INFO_T *var = NULL;
2015  NC_GRP_INFO_T *child_grp = NULL;
2016  int coord_varid = -1;
2017  int var_index = 0;
2018  int dim_index = 0;
2019  int retval;
2020  int i;
2021 
2022  assert(grp && grp->hdr.name &&
2023  ((NC_HDF5_GRP_INFO_T *)(grp->format_grp_info))->hdf_grpid);
2024  LOG((3, "%s: grp->hdr.name %s, bad_coord_order %d", __func__, grp->hdr.name,
2025  bad_coord_order));
2026 
2027  /* Write global attributes for this group. */
2028  if ((retval = write_attlist(grp->att, NC_GLOBAL, grp)))
2029  return retval;
2030 
2031  /* Set the pointers to the beginning of the list of dims & vars in this
2032  * group. */
2033  dim_index = 0;
2034  var_index = 0;
2035  /* prime the loop */
2036  dim = (NC_DIM_INFO_T*)ncindexith(grp->dim,dim_index);
2037  var = (NC_VAR_INFO_T*)ncindexith(grp->vars,var_index);
2038  /* Because of HDF5 ordering the dims and vars have to be stored in
2039  * this way to ensure that the dims and coordinate vars come out in
2040  * the correct order. */
2041  while (dim || var)
2042  {
2043  nc_bool_t found_coord, wrote_coord;
2044 
2045  /* Write non-coord dims in order, stopping at the first one that
2046  * has an associated coord var. */
2047  for (found_coord = NC_FALSE; dim && !found_coord; )
2048  {
2049  if (!dim->coord_var)
2050  {
2051  if ((retval = write_dim(dim, grp, bad_coord_order)))
2052  return retval;
2053  }
2054  else
2055  {
2056  coord_varid = dim->coord_var->hdr.id;
2057  found_coord = NC_TRUE;
2058  }
2059  dim = (NC_DIM_INFO_T*)ncindexith(grp->dim,++dim_index);
2060  }
2061 
2062  /* Write each var. When we get to the coord var we are waiting
2063  * for (if any), then we break after writing it. */
2064  for (wrote_coord = NC_FALSE; var && !wrote_coord; )
2065  {
2066  if ((retval = write_var(var, grp, bad_coord_order)))
2067  return retval;
2068  if (found_coord && var->hdr.id == coord_varid)
2069  wrote_coord = NC_TRUE;
2070  var = (NC_VAR_INFO_T*)ncindexith(grp->vars,++var_index);
2071  }
2072  } /* end while */
2073 
2074  if ((retval = attach_dimscales(grp)))
2075  return retval;
2076 
2077  /* If there are any child groups, write their metadata. */
2078  for(i=0;i<ncindexsize(grp->children);i++) {
2079  if((child_grp = (NC_GRP_INFO_T*)ncindexith(grp->children,i)) == NULL) continue;
2080  if ((retval = nc4_rec_write_metadata(child_grp, bad_coord_order)))
2081  return retval;
2082  }
2083  return NC_NOERR;
2084 }
2085 
2095 int
2096 nc4_rec_write_groups_types(NC_GRP_INFO_T *grp)
2097 {
2098  NC_GRP_INFO_T *child_grp;
2099  NC_HDF5_GRP_INFO_T *hdf5_grp;
2100  NC_TYPE_INFO_T *type;
2101  int retval;
2102  int i;
2103 
2104  assert(grp && grp->hdr.name && grp->format_grp_info);
2105  LOG((3, "%s: grp->hdr.name %s", __func__, grp->hdr.name));
2106 
2107  /* Get HDF5-specific group info. */
2108  hdf5_grp = (NC_HDF5_GRP_INFO_T *)grp->format_grp_info;
2109 
2110  /* Create the group in the HDF5 file if it doesn't exist. */
2111  if (!hdf5_grp->hdf_grpid)
2112  if ((retval = create_group(grp)))
2113  return retval;
2114 
2115  /* If this is the root group of a file with strict NC3 rules, write
2116  * an attribute. But don't leave the attribute open. */
2117  if (!grp->parent && (grp->nc4_info->cmode & NC_CLASSIC_MODEL))
2118  if ((retval = write_nc3_strict_att(hdf5_grp->hdf_grpid)))
2119  return retval;
2120 
2121  /* If there are any user-defined types, write them now. */
2122  for(i=0;i<ncindexsize(grp->type);i++) {
2123  type = (NC_TYPE_INFO_T *)ncindexith(grp->type, i);
2124  assert(type);
2125  if ((retval = commit_type(grp, type)))
2126  return retval;
2127  }
2128 
2129  /* If there are any child groups, write their groups and types. */
2130  for(i=0;i<ncindexsize(grp->children);i++) {
2131  if((child_grp = (NC_GRP_INFO_T*)ncindexith(grp->children,i)) == NULL) continue;
2132  if ((retval = nc4_rec_write_groups_types(child_grp)))
2133  return retval;
2134  }
2135  return NC_NOERR;
2136 }
2137 
2163 int
2164 nc4_convert_type(const void *src, void *dest, const nc_type src_type,
2165  const nc_type dest_type, const size_t len, int *range_error,
2166  const void *fill_value, int strict_nc3)
2167 {
2168  char *cp, *cp1;
2169  float *fp, *fp1;
2170  double *dp, *dp1;
2171  int *ip, *ip1;
2172  short *sp, *sp1;
2173  signed char *bp, *bp1;
2174  unsigned char *ubp, *ubp1;
2175  unsigned short *usp, *usp1;
2176  unsigned int *uip, *uip1;
2177  long long *lip, *lip1;
2178  unsigned long long *ulip, *ulip1;
2179  size_t count = 0;
2180 
2181  *range_error = 0;
2182  LOG((3, "%s: len %d src_type %d dest_type %d", __func__, len, src_type,
2183  dest_type));
2184 
2185  /* OK, this is ugly. If you can think of anything better, I'm open
2186  to suggestions!
2187 
2188  Note that we don't use a default fill value for type
2189  NC_BYTE. This is because Lord Voldemort cast a nofilleramous spell
2190  at Harry Potter, but it bounced off his scar and hit the netcdf-4
2191  code.
2192  */
2193  switch (src_type)
2194  {
2195  case NC_CHAR:
2196  switch (dest_type)
2197  {
2198  case NC_CHAR:
2199  for (cp = (char *)src, cp1 = dest; count < len; count++)
2200  *cp1++ = *cp++;
2201  break;
2202  default:
2203  LOG((0, "%s: Unknown destination type.", __func__));
2204  }
2205  break;
2206 
2207  case NC_BYTE:
2208  switch (dest_type)
2209  {
2210  case NC_BYTE:
2211  for (bp = (signed char *)src, bp1 = dest; count < len; count++)
2212  *bp1++ = *bp++;
2213  break;
2214  case NC_UBYTE:
2215  for (bp = (signed char *)src, ubp = dest; count < len; count++)
2216  {
2217  if (*bp < 0)
2218  (*range_error)++;
2219  *ubp++ = *bp++;
2220  }
2221  break;
2222  case NC_SHORT:
2223  for (bp = (signed char *)src, sp = dest; count < len; count++)
2224  *sp++ = *bp++;
2225  break;
2226  case NC_USHORT:
2227  for (bp = (signed char *)src, usp = dest; count < len; count++)
2228  {
2229  if (*bp < 0)
2230  (*range_error)++;
2231  *usp++ = *bp++;
2232  }
2233  break;
2234  case NC_INT:
2235  for (bp = (signed char *)src, ip = dest; count < len; count++)
2236  *ip++ = *bp++;
2237  break;
2238  case NC_UINT:
2239  for (bp = (signed char *)src, uip = dest; count < len; count++)
2240  {
2241  if (*bp < 0)
2242  (*range_error)++;
2243  *uip++ = *bp++;
2244  }
2245  break;
2246  case NC_INT64:
2247  for (bp = (signed char *)src, lip = dest; count < len; count++)
2248  *lip++ = *bp++;
2249  break;
2250  case NC_UINT64:
2251  for (bp = (signed char *)src, ulip = dest; count < len; count++)
2252  {
2253  if (*bp < 0)
2254  (*range_error)++;
2255  *ulip++ = *bp++;
2256  }
2257  break;
2258  case NC_FLOAT:
2259  for (bp = (signed char *)src, fp = dest; count < len; count++)
2260  *fp++ = *bp++;
2261  break;
2262  case NC_DOUBLE:
2263  for (bp = (signed char *)src, dp = dest; count < len; count++)
2264  *dp++ = *bp++;
2265  break;
2266  default:
2267  LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d",
2268  __func__, src_type, dest_type));
2269  return NC_EBADTYPE;
2270  }
2271  break;
2272 
2273  case NC_UBYTE:
2274  switch (dest_type)
2275  {
2276  case NC_BYTE:
2277  for (ubp = (unsigned char *)src, bp = dest; count < len; count++)
2278  {
2279  if (!strict_nc3 && *ubp > X_SCHAR_MAX)
2280  (*range_error)++;
2281  *bp++ = *ubp++;
2282  }
2283  break;
2284  case NC_SHORT:
2285  for (ubp = (unsigned char *)src, sp = dest; count < len; count++)
2286  *sp++ = *ubp++;
2287  break;
2288  case NC_UBYTE:
2289  for (ubp = (unsigned char *)src, ubp1 = dest; count < len; count++)
2290  *ubp1++ = *ubp++;
2291  break;
2292  case NC_USHORT:
2293  for (ubp = (unsigned char *)src, usp = dest; count < len; count++)
2294  *usp++ = *ubp++;
2295  break;
2296  case NC_INT:
2297  for (ubp = (unsigned char *)src, ip = dest; count < len; count++)
2298  *ip++ = *ubp++;
2299  break;
2300  case NC_UINT:
2301  for (ubp = (unsigned char *)src, uip = dest; count < len; count++)
2302  *uip++ = *ubp++;
2303  break;
2304  case NC_INT64:
2305  for (ubp = (unsigned char *)src, lip = dest; count < len; count++)
2306  *lip++ = *ubp++;
2307  break;
2308  case NC_UINT64:
2309  for (ubp = (unsigned char *)src, ulip = dest; count < len; count++)
2310  *ulip++ = *ubp++;
2311  break;
2312  case NC_FLOAT:
2313  for (ubp = (unsigned char *)src, fp = dest; count < len; count++)
2314  *fp++ = *ubp++;
2315  break;
2316  case NC_DOUBLE:
2317  for (ubp = (unsigned char *)src, dp = dest; count < len; count++)
2318  *dp++ = *ubp++;
2319  break;
2320  default:
2321  LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d",
2322  __func__, src_type, dest_type));
2323  return NC_EBADTYPE;
2324  }
2325  break;
2326 
2327  case NC_SHORT:
2328  switch (dest_type)
2329  {
2330  case NC_UBYTE:
2331  for (sp = (short *)src, ubp = dest; count < len; count++)
2332  {
2333  if (*sp > X_UCHAR_MAX || *sp < 0)
2334  (*range_error)++;
2335  *ubp++ = *sp++;
2336  }
2337  break;
2338  case NC_BYTE:
2339  for (sp = (short *)src, bp = dest; count < len; count++)
2340  {
2341  if (*sp > X_SCHAR_MAX || *sp < X_SCHAR_MIN)
2342  (*range_error)++;
2343  *bp++ = *sp++;
2344  }
2345  break;
2346  case NC_SHORT:
2347  for (sp = (short *)src, sp1 = dest; count < len; count++)
2348  *sp1++ = *sp++;
2349  break;
2350  case NC_USHORT:
2351  for (sp = (short *)src, usp = dest; count < len; count++)
2352  {
2353  if (*sp < 0)
2354  (*range_error)++;
2355  *usp++ = *sp++;
2356  }
2357  break;
2358  case NC_INT:
2359  for (sp = (short *)src, ip = dest; count < len; count++)
2360  *ip++ = *sp++;
2361  break;
2362  case NC_UINT:
2363  for (sp = (short *)src, uip = dest; count < len; count++)
2364  {
2365  if (*sp < 0)
2366  (*range_error)++;
2367  *uip++ = *sp++;
2368  }
2369  break;
2370  case NC_INT64:
2371  for (sp = (short *)src, lip = dest; count < len; count++)
2372  *lip++ = *sp++;
2373  break;
2374  case NC_UINT64:
2375  for (sp = (short *)src, ulip = dest; count < len; count++)
2376  {
2377  if (*sp < 0)
2378  (*range_error)++;
2379  *ulip++ = *sp++;
2380  }
2381  break;
2382  case NC_FLOAT:
2383  for (sp = (short *)src, fp = dest; count < len; count++)
2384  *fp++ = *sp++;
2385  break;
2386  case NC_DOUBLE:
2387  for (sp = (short *)src, dp = dest; count < len; count++)
2388  *dp++ = *sp++;
2389  break;
2390  default:
2391  LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d",
2392  __func__, src_type, dest_type));
2393  return NC_EBADTYPE;
2394  }
2395  break;
2396 
2397  case NC_USHORT:
2398  switch (dest_type)
2399  {
2400  case NC_UBYTE:
2401  for (usp = (unsigned short *)src, ubp = dest; count < len; count++)
2402  {
2403  if (*usp > X_UCHAR_MAX)
2404  (*range_error)++;
2405  *ubp++ = *usp++;
2406  }
2407  break;
2408  case NC_BYTE:
2409  for (usp = (unsigned short *)src, bp = dest; count < len; count++)
2410  {
2411  if (*usp > X_SCHAR_MAX)
2412  (*range_error)++;
2413  *bp++ = *usp++;
2414  }
2415  break;
2416  case NC_SHORT:
2417  for (usp = (unsigned short *)src, sp = dest; count < len; count++)
2418  {
2419  if (*usp > X_SHORT_MAX)
2420  (*range_error)++;
2421  *sp++ = *usp++;
2422  }
2423  break;
2424  case NC_USHORT:
2425  for (usp = (unsigned short *)src, usp1 = dest; count < len; count++)
2426  *usp1++ = *usp++;
2427  break;
2428  case NC_INT:
2429  for (usp = (unsigned short *)src, ip = dest; count < len; count++)
2430  *ip++ = *usp++;
2431  break;
2432  case NC_UINT:
2433  for (usp = (unsigned short *)src, uip = dest; count < len; count++)
2434  *uip++ = *usp++;
2435  break;
2436  case NC_INT64:
2437  for (usp = (unsigned short *)src, lip = dest; count < len; count++)
2438  *lip++ = *usp++;
2439  break;
2440  case NC_UINT64:
2441  for (usp = (unsigned short *)src, ulip = dest; count < len; count++)
2442  *ulip++ = *usp++;
2443  break;
2444  case NC_FLOAT:
2445  for (usp = (unsigned short *)src, fp = dest; count < len; count++)
2446  *fp++ = *usp++;
2447  break;
2448  case NC_DOUBLE:
2449  for (usp = (unsigned short *)src, dp = dest; count < len; count++)
2450  *dp++ = *usp++;
2451  break;
2452  default:
2453  LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d",
2454  __func__, src_type, dest_type));
2455  return NC_EBADTYPE;
2456  }
2457  break;
2458 
2459  case NC_INT:
2460  switch (dest_type)
2461  {
2462  case NC_UBYTE:
2463  for (ip = (int *)src, ubp = dest; count < len; count++)
2464  {
2465  if (*ip > X_UCHAR_MAX || *ip < 0)
2466  (*range_error)++;
2467  *ubp++ = *ip++;
2468  }
2469  break;
2470  case NC_BYTE:
2471  for (ip = (int *)src, bp = dest; count < len; count++)
2472  {
2473  if (*ip > X_SCHAR_MAX || *ip < X_SCHAR_MIN)
2474  (*range_error)++;
2475  *bp++ = *ip++;
2476  }
2477  break;
2478  case NC_SHORT:
2479  for (ip = (int *)src, sp = dest; count < len; count++)
2480  {
2481  if (*ip > X_SHORT_MAX || *ip < X_SHORT_MIN)
2482  (*range_error)++;
2483  *sp++ = *ip++;
2484  }
2485  break;
2486  case NC_USHORT:
2487  for (ip = (int *)src, usp = dest; count < len; count++)
2488  {
2489  if (*ip > X_USHORT_MAX || *ip < 0)
2490  (*range_error)++;
2491  *usp++ = *ip++;
2492  }
2493  break;
2494  case NC_INT: /* src is int */
2495  for (ip = (int *)src, ip1 = dest; count < len; count++)
2496  {
2497  if (*ip > X_INT_MAX || *ip < X_INT_MIN)
2498  (*range_error)++;
2499  *ip1++ = *ip++;
2500  }
2501  break;
2502  case NC_UINT:
2503  for (ip = (int *)src, uip = dest; count < len; count++)
2504  {
2505  if (*ip > X_UINT_MAX || *ip < 0)
2506  (*range_error)++;
2507  *uip++ = *ip++;
2508  }
2509  break;
2510  case NC_INT64:
2511  for (ip = (int *)src, lip = dest; count < len; count++)
2512  *lip++ = *ip++;
2513  break;
2514  case NC_UINT64:
2515  for (ip = (int *)src, ulip = dest; count < len; count++)
2516  {
2517  if (*ip < 0)
2518  (*range_error)++;
2519  *ulip++ = *ip++;
2520  }
2521  break;
2522  case NC_FLOAT:
2523  for (ip = (int *)src, fp = dest; count < len; count++)
2524  *fp++ = *ip++;
2525  break;
2526  case NC_DOUBLE:
2527  for (ip = (int *)src, dp = dest; count < len; count++)
2528  *dp++ = *ip++;
2529  break;
2530  default:
2531  LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d",
2532  __func__, src_type, dest_type));
2533  return NC_EBADTYPE;
2534  }
2535  break;
2536 
2537  case NC_UINT:
2538  switch (dest_type)
2539  {
2540  case NC_UBYTE:
2541  for (uip = (unsigned int *)src, ubp = dest; count < len; count++)
2542  {
2543  if (*uip > X_UCHAR_MAX)
2544  (*range_error)++;
2545  *ubp++ = *uip++;
2546  }
2547  break;
2548  case NC_BYTE:
2549  for (uip = (unsigned int *)src, bp = dest; count < len; count++)
2550  {
2551  if (*uip > X_SCHAR_MAX)
2552  (*range_error)++;
2553  *bp++ = *uip++;
2554  }
2555  break;
2556  case NC_SHORT:
2557  for (uip = (unsigned int *)src, sp = dest; count < len; count++)
2558  {
2559  if (*uip > X_SHORT_MAX)
2560  (*range_error)++;
2561  *sp++ = *uip++;
2562  }
2563  break;
2564  case NC_USHORT:
2565  for (uip = (unsigned int *)src, usp = dest; count < len; count++)
2566  {
2567  if (*uip > X_USHORT_MAX)
2568  (*range_error)++;
2569  *usp++ = *uip++;
2570  }
2571  break;
2572  case NC_INT:
2573  for (uip = (unsigned int *)src, ip = dest; count < len; count++)
2574  {
2575  if (*uip > X_INT_MAX)
2576  (*range_error)++;
2577  *ip++ = *uip++;
2578  }
2579  break;
2580  case NC_UINT:
2581  for (uip = (unsigned int *)src, uip1 = dest; count < len; count++)
2582  {
2583  if (*uip > X_UINT_MAX)
2584  (*range_error)++;
2585  *uip1++ = *uip++;
2586  }
2587  break;
2588  case NC_INT64:
2589  for (uip = (unsigned int *)src, lip = dest; count < len; count++)
2590  *lip++ = *uip++;
2591  break;
2592  case NC_UINT64:
2593  for (uip = (unsigned int *)src, ulip = dest; count < len; count++)
2594  *ulip++ = *uip++;
2595  break;
2596  case NC_FLOAT:
2597  for (uip = (unsigned int *)src, fp = dest; count < len; count++)
2598  *fp++ = *uip++;
2599  break;
2600  case NC_DOUBLE:
2601  for (uip = (unsigned int *)src, dp = dest; count < len; count++)
2602  *dp++ = *uip++;
2603  break;
2604  default:
2605  LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d",
2606  __func__, src_type, dest_type));
2607  return NC_EBADTYPE;
2608  }
2609  break;
2610 
2611  case NC_INT64:
2612  switch (dest_type)
2613  {
2614  case NC_UBYTE:
2615  for (lip = (long long *)src, ubp = dest; count < len; count++)
2616  {
2617  if (*lip > X_UCHAR_MAX || *lip < 0)
2618  (*range_error)++;
2619  *ubp++ = *lip++;
2620  }
2621  break;
2622  case NC_BYTE:
2623  for (lip = (long long *)src, bp = dest; count < len; count++)
2624  {
2625  if (*lip > X_SCHAR_MAX || *lip < X_SCHAR_MIN)
2626  (*range_error)++;
2627  *bp++ = *lip++;
2628  }
2629  break;
2630  case NC_SHORT:
2631  for (lip = (long long *)src, sp = dest; count < len; count++)
2632  {
2633  if (*lip > X_SHORT_MAX || *lip < X_SHORT_MIN)
2634  (*range_error)++;
2635  *sp++ = *lip++;
2636  }
2637  break;
2638  case NC_USHORT:
2639  for (lip = (long long *)src, usp = dest; count < len; count++)
2640  {
2641  if (*lip > X_USHORT_MAX || *lip < 0)
2642  (*range_error)++;
2643  *usp++ = *lip++;
2644  }
2645  break;
2646  case NC_UINT:
2647  for (lip = (long long *)src, uip = dest; count < len; count++)
2648  {
2649  if (*lip > X_UINT_MAX || *lip < 0)
2650  (*range_error)++;
2651  *uip++ = *lip++;
2652  }
2653  break;
2654  case NC_INT:
2655  for (lip = (long long *)src, ip = dest; count < len; count++)
2656  {
2657  if (*lip > X_INT_MAX || *lip < X_INT_MIN)
2658  (*range_error)++;
2659  *ip++ = *lip++;
2660  }
2661  break;
2662  case NC_INT64:
2663  for (lip = (long long *)src, lip1 = dest; count < len; count++)
2664  *lip1++ = *lip++;
2665  break;
2666  case NC_UINT64:
2667  for (lip = (long long *)src, ulip = dest; count < len; count++)
2668  {
2669  if (*lip < 0)
2670  (*range_error)++;
2671  *ulip++ = *lip++;
2672  }
2673  break;
2674  case NC_FLOAT:
2675  for (lip = (long long *)src, fp = dest; count < len; count++)
2676  *fp++ = *lip++;
2677  break;
2678  case NC_DOUBLE:
2679  for (lip = (long long *)src, dp = dest; count < len; count++)
2680  *dp++ = *lip++;
2681  break;
2682  default:
2683  LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d",
2684  __func__, src_type, dest_type));
2685  return NC_EBADTYPE;
2686  }
2687  break;
2688 
2689  case NC_UINT64:
2690  switch (dest_type)
2691  {
2692  case NC_UBYTE:
2693  for (ulip = (unsigned long long *)src, ubp = dest; count < len; count++)
2694  {
2695  if (*ulip > X_UCHAR_MAX)
2696  (*range_error)++;
2697  *ubp++ = *ulip++;
2698  }
2699  break;
2700  case NC_BYTE:
2701  for (ulip = (unsigned long long *)src, bp = dest; count < len; count++)
2702  {
2703  if (*ulip > X_SCHAR_MAX)
2704  (*range_error)++;
2705  *bp++ = *ulip++;
2706  }
2707  break;
2708  case NC_SHORT:
2709  for (ulip = (unsigned long long *)src, sp = dest; count < len; count++)
2710  {
2711  if (*ulip > X_SHORT_MAX)
2712  (*range_error)++;
2713  *sp++ = *ulip++;
2714  }
2715  break;
2716  case NC_USHORT:
2717  for (ulip = (unsigned long long *)src, usp = dest; count < len; count++)
2718  {
2719  if (*ulip > X_USHORT_MAX)
2720  (*range_error)++;
2721  *usp++ = *ulip++;
2722  }
2723  break;
2724  case NC_UINT:
2725  for (ulip = (unsigned long long *)src, uip = dest; count < len; count++)
2726  {
2727  if (*ulip > X_UINT_MAX)
2728  (*range_error)++;
2729  *uip++ = *ulip++;
2730  }
2731  break;
2732  case NC_INT:
2733  for (ulip = (unsigned long long *)src, ip = dest; count < len; count++)
2734  {
2735  if (*ulip > X_INT_MAX)
2736  (*range_error)++;
2737  *ip++ = *ulip++;
2738  }
2739  break;
2740  case NC_INT64:
2741  for (ulip = (unsigned long long *)src, lip = dest; count < len; count++)
2742  {
2743  if (*ulip > X_INT64_MAX)
2744  (*range_error)++;
2745  *lip++ = *ulip++;
2746  }
2747  break;
2748  case NC_UINT64:
2749  for (ulip = (unsigned long long *)src, ulip1 = dest; count < len; count++)
2750  *ulip1++ = *ulip++;
2751  break;
2752  case NC_FLOAT:
2753  for (ulip = (unsigned long long *)src, fp = dest; count < len; count++)
2754  *fp++ = *ulip++;
2755  break;
2756  case NC_DOUBLE:
2757  for (ulip = (unsigned long long *)src, dp = dest; count < len; count++)
2758  *dp++ = *ulip++;
2759  break;
2760  default:
2761  LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d",
2762  __func__, src_type, dest_type));
2763  return NC_EBADTYPE;
2764  }
2765  break;
2766 
2767  case NC_FLOAT:
2768  switch (dest_type)
2769  {
2770  case NC_UBYTE:
2771  for (fp = (float *)src, ubp = dest; count < len; count++)
2772  {
2773  if (*fp > X_UCHAR_MAX || *fp < 0)
2774  (*range_error)++;
2775  *ubp++ = *fp++;
2776  }
2777  break;
2778  case NC_BYTE:
2779  for (fp = (float *)src, bp = dest; count < len; count++)
2780  {
2781  if (*fp > (double)X_SCHAR_MAX || *fp < (double)X_SCHAR_MIN)
2782  (*range_error)++;
2783  *bp++ = *fp++;
2784  }
2785  break;
2786  case NC_SHORT:
2787  for (fp = (float *)src, sp = dest; count < len; count++)
2788  {
2789  if (*fp > (double)X_SHORT_MAX || *fp < (double)X_SHORT_MIN)
2790  (*range_error)++;
2791  *sp++ = *fp++;
2792  }
2793  break;
2794  case NC_USHORT:
2795  for (fp = (float *)src, usp = dest; count < len; count++)
2796  {
2797  if (*fp > X_USHORT_MAX || *fp < 0)
2798  (*range_error)++;
2799  *usp++ = *fp++;
2800  }
2801  break;
2802  case NC_UINT:
2803  for (fp = (float *)src, uip = dest; count < len; count++)
2804  {
2805  if (*fp > X_UINT_MAX || *fp < 0)
2806  (*range_error)++;
2807  *uip++ = *fp++;
2808  }
2809  break;
2810  case NC_INT:
2811  for (fp = (float *)src, ip = dest; count < len; count++)
2812  {
2813  if (*fp > (double)X_INT_MAX || *fp < (double)X_INT_MIN)
2814  (*range_error)++;
2815  *ip++ = *fp++;
2816  }
2817  break;
2818  case NC_INT64:
2819  for (fp = (float *)src, lip = dest; count < len; count++)
2820  {
2821  if (*fp > X_INT64_MAX || *fp <X_INT64_MIN)
2822  (*range_error)++;
2823  *lip++ = *fp++;
2824  }
2825  break;
2826  case NC_UINT64:
2827  for (fp = (float *)src, lip = dest; count < len; count++)
2828  {
2829  if (*fp > X_UINT64_MAX || *fp < 0)
2830  (*range_error)++;
2831  *lip++ = *fp++;
2832  }
2833  break;
2834  case NC_FLOAT:
2835  for (fp = (float *)src, fp1 = dest; count < len; count++)
2836  {
2837  /* if (*fp > X_FLOAT_MAX || *fp < X_FLOAT_MIN)
2838  (*range_error)++;*/
2839  *fp1++ = *fp++;
2840  }
2841  break;
2842  case NC_DOUBLE:
2843  for (fp = (float *)src, dp = dest; count < len; count++)
2844  *dp++ = *fp++;
2845  break;
2846  default:
2847  LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d",
2848  __func__, src_type, dest_type));
2849  return NC_EBADTYPE;
2850  }
2851  break;
2852 
2853  case NC_DOUBLE:
2854  switch (dest_type)
2855  {
2856  case NC_UBYTE:
2857  for (dp = (double *)src, ubp = dest; count < len; count++)
2858  {
2859  if (*dp > X_UCHAR_MAX || *dp < 0)
2860  (*range_error)++;
2861  *ubp++ = *dp++;
2862  }
2863  break;
2864  case NC_BYTE:
2865  for (dp = (double *)src, bp = dest; count < len; count++)
2866  {
2867  if (*dp > X_SCHAR_MAX || *dp < X_SCHAR_MIN)
2868  (*range_error)++;
2869  *bp++ = *dp++;
2870  }
2871  break;
2872  case NC_SHORT:
2873  for (dp = (double *)src, sp = dest; count < len; count++)
2874  {
2875  if (*dp > X_SHORT_MAX || *dp < X_SHORT_MIN)
2876  (*range_error)++;
2877  *sp++ = *dp++;
2878  }
2879  break;
2880  case NC_USHORT:
2881  for (dp = (double *)src, usp = dest; count < len; count++)
2882  {
2883  if (*dp > X_USHORT_MAX || *dp < 0)
2884  (*range_error)++;
2885  *usp++ = *dp++;
2886  }
2887  break;
2888  case NC_UINT:
2889  for (dp = (double *)src, uip = dest; count < len; count++)
2890  {
2891  if (*dp > X_UINT_MAX || *dp < 0)
2892  (*range_error)++;
2893  *uip++ = *dp++;
2894  }
2895  break;
2896  case NC_INT:
2897  for (dp = (double *)src, ip = dest; count < len; count++)
2898  {
2899  if (*dp > X_INT_MAX || *dp < X_INT_MIN)
2900  (*range_error)++;
2901  *ip++ = *dp++;
2902  }
2903  break;
2904  case NC_INT64:
2905  for (dp = (double *)src, lip = dest; count < len; count++)
2906  {
2907  if (*dp > X_INT64_MAX || *dp < X_INT64_MIN)
2908  (*range_error)++;
2909  *lip++ = *dp++;
2910  }
2911  break;
2912  case NC_UINT64:
2913  for (dp = (double *)src, lip = dest; count < len; count++)
2914  {
2915  if (*dp > X_UINT64_MAX || *dp < 0)
2916  (*range_error)++;
2917  *lip++ = *dp++;
2918  }
2919  break;
2920  case NC_FLOAT:
2921  for (dp = (double *)src, fp = dest; count < len; count++)
2922  {
2923  if (*dp > X_FLOAT_MAX || *dp < X_FLOAT_MIN)
2924  (*range_error)++;
2925  *fp++ = *dp++;
2926  }
2927  break;
2928  case NC_DOUBLE:
2929  for (dp = (double *)src, dp1 = dest; count < len; count++)
2930  {
2931  /* if (*dp > X_DOUBLE_MAX || *dp < X_DOUBLE_MIN) */
2932  /* (*range_error)++; */
2933  *dp1++ = *dp++;
2934  }
2935  break;
2936  default:
2937  LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d",
2938  __func__, src_type, dest_type));
2939  return NC_EBADTYPE;
2940  }
2941  break;
2942 
2943  default:
2944  LOG((0, "%s: unexpected src type. src_type %d, dest_type %d",
2945  __func__, src_type, dest_type));
2946  return NC_EBADTYPE;
2947  }
2948  return NC_NOERR;
2949 }
2950 
2964 int
2965 nc4_rec_match_dimscales(NC_GRP_INFO_T *grp)
2966 {
2967  NC_GRP_INFO_T *g;
2968  NC_VAR_INFO_T *var;
2969  NC_DIM_INFO_T *dim;
2970  int retval = NC_NOERR;
2971  int i;
2972 
2973  assert(grp && grp->hdr.name);
2974  LOG((4, "%s: grp->hdr.name %s", __func__, grp->hdr.name));
2975 
2976  /* Perform var dimscale match for child groups. */
2977  for(i=0;i<ncindexsize(grp->children);i++) {
2978  if((g = (NC_GRP_INFO_T*)ncindexith(grp->children,i)) == NULL) continue;
2979  if ((retval = nc4_rec_match_dimscales(g)))
2980  return retval;
2981  }
2982  /* Check all the vars in this group. If they have dimscale info,
2983  * try and find a dimension for them. */
2984  for(i=0;i<ncindexsize(grp->vars);i++)
2985  {
2986  int ndims;
2987  int d;
2988  if((var = (NC_VAR_INFO_T*)ncindexith(grp->vars,i)) == NULL) continue;
2989  /* Check all vars and see if dim[i] != NULL if dimids[i] valid. */
2990  /* This loop is very odd. Under normal circumstances, var->dimid[d] is zero
2991  (from the initial calloc) which is a legitimate dimid. The code does not
2992  distinquish this case from the dimscale case where the id might actually
2993  be defined.
2994  The original nc4_find_dim searched up the group tree looking for the given
2995  dimid in one of the dim lists associated with each ancestor group.
2996  I changed nc4_fnd_dim to use the dimid directly using h5->alldims.
2997  However, here that is incorrect because it will find the dimid 0 always
2998  (if any dimensions were defined). Except that when dimscale dimids have
2999  been defined, one or more of the values in var->dimids will have a
3000  legitimate value.
3001  The solution I choose is to modify nc4_var_list_add to initialize dimids to
3002  illegal values (-1). This is another example of the problems with dimscales.
3003  */
3004  ndims = var->ndims;
3005  for (d = 0; d < ndims; d++)
3006  {
3007  if (var->dim[d] == NULL) {
3008  nc4_find_dim(grp, var->dimids[d], &var->dim[d], NULL);
3009  }
3010  /* assert(var->dim[d] && var->dim[d]->hdr.id == var->dimids[d]); */
3011  }
3012 
3013  /* Skip dimension scale variables */
3014  if (!var->dimscale)
3015  {
3016  int d;
3017  int j;
3018 
3019  /* Are there dimscales for this variable? */
3020  if (var->dimscale_hdf5_objids)
3021  {
3022  for (d = 0; d < var->ndims; d++)
3023  {
3024  nc_bool_t finished = NC_FALSE;
3025  LOG((5, "%s: var %s has dimscale info...", __func__, var->hdr.name));
3026 
3027  /* Check this and parent groups. */
3028  for (g = grp; g && !finished; g = g->parent)
3029  {
3030  /* Check all dims in this group. */
3031  for (j = 0; j < ncindexsize(g->dim); j++)
3032  {
3033  /* Get the HDF5 specific dim info. */
3034  NC_HDF5_DIM_INFO_T *hdf5_dim;
3035  dim = (NC_DIM_INFO_T *)ncindexith(g->dim, j);
3036  assert(dim && dim->format_dim_info);
3037  hdf5_dim = (NC_HDF5_DIM_INFO_T *)dim->format_dim_info;
3038 
3039  /* Check for exact match of fileno/objid arrays
3040  * to find identical objects in HDF5 file. */
3041  if (var->dimscale_hdf5_objids[d].fileno[0] == hdf5_dim->hdf5_objid.fileno[0] &&
3042  var->dimscale_hdf5_objids[d].objno[0] == hdf5_dim->hdf5_objid.objno[0] &&
3043  var->dimscale_hdf5_objids[d].fileno[1] == hdf5_dim->hdf5_objid.fileno[1] &&
3044  var->dimscale_hdf5_objids[d].objno[1] == hdf5_dim->hdf5_objid.objno[1])
3045  {
3046  LOG((4, "%s: for dimension %d, found dim %s", __func__,
3047  d, dim->hdr.name));
3048  var->dimids[d] = dim->hdr.id;
3049  var->dim[d] = dim;
3050  finished = NC_TRUE;
3051  break;
3052  }
3053  } /* next dim */
3054  } /* next grp */
3055  LOG((5, "%s: dimid for this dimscale is %d", __func__,
3056  var->type_info->hdr.id));
3057  } /* next var->dim */
3058  }
3059  /* No dimscales for this var! Invent phony dimensions. */
3060  else
3061  {
3062  hid_t spaceid = 0;
3063  hsize_t *h5dimlen = NULL, *h5dimlenmax = NULL;
3064  int dataset_ndims;
3065 
3066  /* Find the space information for this dimension. */
3067  if ((spaceid = H5Dget_space(var->hdf_datasetid)) < 0)
3068  return NC_EHDFERR;
3069 
3070  /* Get the len of each dim in the space. */
3071  if (var->ndims)
3072  {
3073  if (!(h5dimlen = malloc(var->ndims * sizeof(hsize_t))))
3074  return NC_ENOMEM;
3075  if (!(h5dimlenmax = malloc(var->ndims * sizeof(hsize_t))))
3076  {
3077  free(h5dimlen);
3078  return NC_ENOMEM;
3079  }
3080  if ((dataset_ndims = H5Sget_simple_extent_dims(spaceid, h5dimlen,
3081  h5dimlenmax)) < 0) {
3082  free(h5dimlenmax);
3083  free(h5dimlen);
3084  return NC_EHDFERR;
3085  }
3086  if (dataset_ndims != var->ndims) {
3087  free(h5dimlenmax);
3088  free(h5dimlen);
3089  return NC_EHDFERR;
3090  }
3091  }
3092  else
3093  {
3094  /* Make sure it's scalar. */
3095  if (H5Sget_simple_extent_type(spaceid) != H5S_SCALAR)
3096  return NC_EHDFERR;
3097  }
3098 
3099  /* Release the space object. */
3100  if (H5Sclose(spaceid) < 0) {
3101  free(h5dimlen);
3102  free(h5dimlenmax);
3103  return NC_EHDFERR;
3104  }
3105 
3106  /* Create a phony dimension for each dimension in the
3107  * dataset, unless there already is one the correct
3108  * size. */
3109  for (d = 0; d < var->ndims; d++)
3110  {
3111  int k;
3112  int match;
3113  /* Is there already a phony dimension of the correct size? */
3114  for(match=-1,k=0;k<ncindexsize(grp->dim);k++) {
3115  if((dim = (NC_DIM_INFO_T*)ncindexith(grp->dim,k)) == NULL) continue;
3116  if ((dim->len == h5dimlen[d]) &&
3117  ((h5dimlenmax[d] == H5S_UNLIMITED && dim->unlimited) ||
3118  (h5dimlenmax[d] != H5S_UNLIMITED && !dim->unlimited)))
3119  {match = k; break;}
3120  }
3121 
3122  /* Didn't find a phony dim? Then create one. */
3123  if (match < 0)
3124  {
3125  char phony_dim_name[NC_MAX_NAME + 1];
3126  sprintf(phony_dim_name, "phony_dim_%d", grp->nc4_info->next_dimid);
3127  LOG((3, "%s: creating phony dim for var %s", __func__, var->hdr.name));
3128  if ((retval = nc4_dim_list_add(grp, phony_dim_name, h5dimlen[d], -1, &dim)))
3129  {
3130  free(h5dimlenmax);
3131  free(h5dimlen);
3132  return retval;
3133  }
3134  /* Create struct for HDF5-specific dim info. */
3135  if (!(dim->format_dim_info = calloc(1, sizeof(NC_HDF5_DIM_INFO_T))))
3136  return NC_ENOMEM;
3137  if (h5dimlenmax[d] == H5S_UNLIMITED)
3138  dim->unlimited = NC_TRUE;
3139  }
3140 
3141  /* The variable must remember the dimid. */
3142  var->dimids[d] = dim->hdr.id;
3143  var->dim[d] = dim;
3144  } /* next dim */
3145 
3146  /* Free the memory we malloced. */
3147  free(h5dimlen);
3148  free(h5dimlenmax);
3149  }
3150  }
3151  }
3152 
3153  return retval;
3154 }
3155 
3168 int
3169 nc4_get_typelen_mem(NC_FILE_INFO_T *h5, nc_type xtype, size_t *len)
3170 {
3171  NC_TYPE_INFO_T *type;
3172  int retval;
3173 
3174  LOG((4, "%s xtype: %d", __func__, xtype));
3175  assert(len);
3176 
3177  /* If this is an atomic type, the answer is easy. */
3178  switch (xtype)
3179  {
3180  case NC_BYTE:
3181  case NC_CHAR:
3182  case NC_UBYTE:
3183  *len = sizeof(char);
3184  return NC_NOERR;
3185  case NC_SHORT:
3186  case NC_USHORT:
3187  *len = sizeof(short);
3188  return NC_NOERR;
3189  case NC_INT:
3190  case NC_UINT:
3191  *len = sizeof(int);
3192  return NC_NOERR;
3193  case NC_FLOAT:
3194  *len = sizeof(float);
3195  return NC_NOERR;
3196  case NC_DOUBLE:
3197  *len = sizeof(double);
3198  return NC_NOERR;
3199  case NC_INT64:
3200  case NC_UINT64:
3201  *len = sizeof(long long);
3202  return NC_NOERR;
3203  case NC_STRING:
3204  *len = sizeof(char *);
3205  return NC_NOERR;
3206  }
3207 
3208  /* See if var is compound type. */
3209  if ((retval = nc4_find_type(h5, xtype, &type)))
3210  return retval;
3211 
3212  if (!type)
3213  return NC_EBADTYPE;
3214 
3215  *len = type->size;
3216 
3217  LOG((5, "type->size: %d", type->size));
3218 
3219  return NC_NOERR;
3220 }
3221 
3234 int
3235 nc4_get_typeclass(const NC_FILE_INFO_T *h5, nc_type xtype, int *type_class)
3236 {
3237  int retval = NC_NOERR;
3238 
3239  LOG((4, "%s xtype: %d", __func__, xtype));
3240  assert(type_class);
3241 
3242  /* If this is an atomic type, the answer is easy. */
3243  if (xtype <= NC_STRING)
3244  {
3245  switch (xtype)
3246  {
3247  case NC_BYTE:
3248  case NC_UBYTE:
3249  case NC_SHORT:
3250  case NC_USHORT:
3251  case NC_INT:
3252  case NC_UINT:
3253  case NC_INT64:
3254  case NC_UINT64:
3255  /* NC_INT is class used for all integral types */
3256  *type_class = NC_INT;
3257  break;
3258 
3259  case NC_FLOAT:
3260  case NC_DOUBLE:
3261  /* NC_FLOAT is class used for all floating-point types */
3262  *type_class = NC_FLOAT;
3263  break;
3264 
3265  case NC_CHAR:
3266  *type_class = NC_CHAR;
3267  break;
3268 
3269  case NC_STRING:
3270  *type_class = NC_STRING;
3271  break;
3272 
3273  default:
3274  BAIL(NC_EBADTYPE);
3275  }
3276  }
3277  else
3278  {
3279  NC_TYPE_INFO_T *type;
3280 
3281  /* See if it's a used-defined type */
3282  if ((retval = nc4_find_type(h5, xtype, &type)))
3283  BAIL(retval);
3284  if (!type)
3285  BAIL(NC_EBADTYPE);
3286 
3287  *type_class = type->nc_type_class;
3288  }
3289 
3290 exit:
3291  return retval;
3292 }
3293 
3305 void
3306 reportobject(int uselog, hid_t id, unsigned int type)
3307 {
3308  char name[NC_HDF5_MAX_NAME];
3309  ssize_t len;
3310  const char* typename = NULL;
3311  long long printid = (long long)id;
3312 
3313  len = H5Iget_name(id, name, NC_HDF5_MAX_NAME);
3314  if(len < 0) return;
3315  name[len] = '\0';
3316 
3317  switch (type) {
3318  case H5F_OBJ_FILE: typename = "File"; break;
3319  case H5F_OBJ_DATASET: typename = "Dataset"; break;
3320  case H5F_OBJ_GROUP: typename = "Group"; break;
3321  case H5F_OBJ_DATATYPE: typename = "Datatype"; break;
3322  case H5F_OBJ_ATTR:
3323  typename = "Attribute";
3324  len = H5Aget_name(id, NC_HDF5_MAX_NAME, name);
3325  if(len < 0) len = 0;
3326  name[len] = '\0';
3327  break;
3328  default: typename = "<unknown>"; break;
3329  }
3330 #ifdef LOGGING
3331  if(uselog) {
3332  LOG((0,"Type = %s(%lld) name='%s'",typename,printid,name));
3333  } else
3334 #endif
3335  {
3336  fprintf(stderr,"Type = %s(%lld) name='%s'",typename,printid,name);
3337  }
3338 
3339 }
3340 
3351 static void
3352 reportopenobjectsT(int uselog, hid_t fid, int ntypes, unsigned int* otypes)
3353 {
3354  int t,i;
3355  ssize_t ocount;
3356  size_t maxobjs = -1;
3357  hid_t* idlist = NULL;
3358 
3359  /* Always report somehow */
3360 #ifdef LOGGING
3361  if(uselog)
3362  LOG((0,"\nReport: open objects on %lld",(long long)fid));
3363  else
3364 #endif
3365  fprintf(stdout,"\nReport: open objects on %lld\n",(long long)fid);
3366  maxobjs = H5Fget_obj_count(fid,H5F_OBJ_ALL);
3367  if(idlist != NULL) free(idlist);
3368  idlist = (hid_t*)malloc(sizeof(hid_t)*maxobjs);
3369  for(t=0;t<ntypes;t++) {
3370  unsigned int ot = otypes[t];
3371  ocount = H5Fget_obj_ids(fid,ot,maxobjs,idlist);
3372  for(i=0;i<ocount;i++) {
3373  hid_t o = idlist[i];
3374  reportobject(uselog,o,ot);
3375  }
3376  }
3377  if(idlist != NULL) free(idlist);
3378 }
3379 
3388 void
3389 reportopenobjects(int uselog, hid_t fid)
3390 {
3391  unsigned int OTYPES[5] = {H5F_OBJ_FILE, H5F_OBJ_DATASET, H5F_OBJ_GROUP,
3392  H5F_OBJ_DATATYPE, H5F_OBJ_ATTR};
3393 
3394  reportopenobjectsT(uselog, fid ,5, OTYPES);
3395 }
3396 
3404 void
3405 showopenobjects5(NC_FILE_INFO_T* h5)
3406 {
3407  NC_HDF5_FILE_INFO_T *hdf5_info;
3408 
3409  assert(h5 && h5->format_file_info);
3410  hdf5_info = (NC_HDF5_FILE_INFO_T *)h5->format_file_info;
3411 
3412  fprintf(stderr,"===== begin showopenobjects =====\n");
3413  reportopenobjects(0,hdf5_info->hdfid);
3414  fprintf(stderr,"===== end showopenobjects =====\n");
3415  fflush(stderr);
3416 }
3417 
3426 void
3427 showopenobjects(int ncid)
3428 {
3429  NC_FILE_INFO_T* h5 = NULL;
3430 
3431  /* Find our metadata for this file. */
3432  if (nc4_find_nc_grp_h5(ncid, NULL, NULL, &h5) != NC_NOERR)
3433  fprintf(stderr,"failed\n");
3434  else
3435  showopenobjects5(h5);
3436  fflush(stderr);
3437 }
3438 
3450 int
3451 NC4_hdf5get_libversion(unsigned* major,unsigned* minor,unsigned* release)
3452 {
3453  if(H5get_libversion(major,minor,release) < 0)
3454  return NC_EHDFERR;
3455  return NC_NOERR;
3456 }
3457 
3468 int
3469 NC4_hdf5get_superblock(struct NC_FILE_INFO* h5, int* idp)
3470 {
3471  NC_HDF5_FILE_INFO_T *hdf5_info;
3472  int stat = NC_NOERR;
3473  unsigned super;
3474  hid_t plist = -1;
3475 
3476  assert(h5 && h5->format_file_info);
3477  hdf5_info = (NC_HDF5_FILE_INFO_T *)h5->format_file_info;
3478 
3479  if((plist = H5Fget_create_plist(hdf5_info->hdfid)) < 0)
3480  {stat = NC_EHDFERR; goto done;}
3481  if(H5Pget_version(plist, &super, NULL, NULL, NULL) < 0)
3482  {stat = NC_EHDFERR; goto done;}
3483  if(idp) *idp = (int)super;
3484 done:
3485  if(plist >= 0) H5Pclose(plist);
3486  return stat;
3487 }
3488 
3489 static int NC4_get_strict_att(NC_FILE_INFO_T*);
3490 static int NC4_walk(hid_t, int*);
3491 
3516 int
3517 NC4_isnetcdf4(struct NC_FILE_INFO* h5)
3518 {
3519  int stat;
3520  int isnc4 = 0;
3521  int count;
3522 
3523  /* Look for NC3_STRICT_ATT_NAME */
3524  isnc4 = NC4_get_strict_att(h5);
3525  if(isnc4 > 0)
3526  goto done;
3527  /* attribute did not exist */
3528  /* => last resort: walk the HDF5 file looking for markers */
3529  count = 0;
3530  stat = NC4_walk(((NC_HDF5_GRP_INFO_T *)(h5->root_grp->format_grp_info))->hdf_grpid,
3531  &count);
3532  if(stat != NC_NOERR)
3533  isnc4 = 0;
3534  else /* Threshold is at least two matches */
3535  isnc4 = (count >= 2);
3536 
3537 done:
3538  return isnc4;
3539 }
3540 
3549 static int
3550 NC4_get_strict_att(NC_FILE_INFO_T *h5)
3551 {
3552  hid_t grpid = -1;
3553  hid_t attid = -1;
3554 
3555  /* Get root group ID. */
3556  grpid = ((NC_HDF5_GRP_INFO_T *)(h5->root_grp->format_grp_info))->hdf_grpid;
3557 
3558  /* Try to extract the NC3_STRICT_ATT_NAME attribute */
3559  attid = H5Aopen_name(grpid, NC3_STRICT_ATT_NAME);
3560  H5Aclose(attid);
3561  return attid;
3562 }
3563 
3573 static int
3574 NC4_walk(hid_t gid, int* countp)
3575 {
3576  int ncstat = NC_NOERR;
3577  int i,j,na;
3578  ssize_t len;
3579  hsize_t nobj;
3580  herr_t err;
3581  int otype;
3582  hid_t grpid, dsid;
3583  char name[NC_HDF5_MAX_NAME];
3584 
3585  /* walk group members of interest */
3586  err = H5Gget_num_objs(gid, &nobj);
3587  if(err < 0) return err;
3588 
3589  for(i = 0; i < nobj; i++) {
3590  /* Get name & kind of object in the group */
3591  len = H5Gget_objname_by_idx(gid,(hsize_t)i,name,(size_t)NC_HDF5_MAX_NAME);
3592  if(len < 0) return len;
3593 
3594  otype = H5Gget_objtype_by_idx(gid,(size_t)i);
3595  switch(otype) {
3596  case H5G_GROUP:
3597  grpid = H5Gopen(gid,name);
3598  NC4_walk(grpid,countp);
3599  H5Gclose(grpid);
3600  break;
3601  case H5G_DATASET: /* variables */
3602  /* Check for phony_dim */
3603  if(strcmp(name,"phony_dim")==0)
3604  *countp = *countp + 1;
3605  dsid = H5Dopen(gid,name);
3606  na = H5Aget_num_attrs(dsid);
3607  for(j = 0; j < na; j++) {
3608  hid_t aid = H5Aopen_idx(dsid,(unsigned int) j);
3609  if(aid >= 0) {
3610  const NC_reservedatt* ra;
3611  ssize_t len = H5Aget_name(aid, NC_HDF5_MAX_NAME, name);
3612  if(len < 0) return len;
3613  /* Is this a netcdf-4 marker attribute */
3614  /* Is this a netcdf-4 marker attribute */
3615  ra = NC_findreserved(name);
3616  if(ra != NULL)
3617  *countp = *countp + 1;
3618  }
3619  H5Aclose(aid);
3620  }
3621  H5Dclose(dsid);
3622  break;
3623  default:/* ignore */
3624  break;
3625  }
3626  }
3627  return ncstat;
3628 }
3629 
#define NC_FILL_UBYTE
Default fill value.
Definition: netcdf.h:72
#define NC_ENOMEM
Memory allocation (malloc) failure.
Definition: netcdf.h:402
#define NC_CHAR
ISO/ASCII character.
Definition: netcdf.h:35
#define NC_FILL_CHAR
Default fill value.
Definition: netcdf.h:67
#define NC_UBYTE
unsigned 1 byte int
Definition: netcdf.h:41
#define NC_EDIMSCALE
Problem with HDF5 dimscales.
Definition: netcdf.h:458
#define NC_CLASSIC_MODEL
Enforce classic model on netCDF-4.
Definition: netcdf.h:137
#define NC_MAX_VAR_DIMS
max per variable dimensions
Definition: netcdf.h:273
#define NC_FILL_UINT
Default fill value.
Definition: netcdf.h:74
#define NC_UINT
unsigned 4-byte int
Definition: netcdf.h:43
#define NC_EHDFERR
Error at HDF5 layer.
Definition: netcdf.h:435
#define NC_OPAQUE
opaque types
Definition: netcdf.h:53
#define NC_INT64
signed 8-byte int
Definition: netcdf.h:44
#define NC_STRING
string
Definition: netcdf.h:46
#define NC_DOUBLE
double precision floating point number
Definition: netcdf.h:40
#define NC_FILL_UINT64
Default fill value.
Definition: netcdf.h:76
int nc_type
The nc_type type is just an int.
Definition: netcdf.h:24
#define NC_FILL_STRING
Default fill value.
Definition: netcdf.h:77
#define H5Z_FILTER_SZIP
ID of HDF SZIP filter.
Definition: dvarinq.c:15
#define NC_BYTE
signed 1 byte integer
Definition: netcdf.h:34
#define NC_FILL_INT
Default fill value.
Definition: netcdf.h:69
size_t len
Length of VL data (in base type units)
Definition: netcdf.h:685
#define NC_ENDIAN_LITTLE
In HDF5 files you can set the endianness of variables with nc_def_var_endian().
Definition: netcdf.h:283
#define NC_EATTMETA
Problem with attribute metadata.
Definition: netcdf.h:441
#define NC_VLEN
vlen (variable-length) types
Definition: netcdf.h:52
#define NC_EFILEMETA
Problem with file metadata.
Definition: netcdf.h:439
#define NC_EFILTER
Filter operation failed.
Definition: netcdf.h:467
#define NC_EBADTYPE
Not a netcdf data type.
Definition: netcdf.h:364
#define NC_EDIMMETA
Problem with dimension metadata.
Definition: netcdf.h:440
#define NC_EINVAL
Invalid Argument.
Definition: netcdf.h:332
#define NC_INT
signed 4 byte integer
Definition: netcdf.h:37
#define NC_ENDIAN_BIG
In HDF5 files you can set the endianness of variables with nc_def_var_endian().
Definition: netcdf.h:284
#define NC_MAX_NAME
Maximum for classic library.
Definition: netcdf.h:272
void * p
Pointer to VL data.
Definition: netcdf.h:686
#define NC_NAT
Not A Type.
Definition: netcdf.h:33
EXTERNL int nc_free_vlen(nc_vlen_t *vl)
Free memory in a VLEN object.
Definition: dvlen.c:41
#define NC_USHORT
unsigned 2-byte int
Definition: netcdf.h:42
#define NC_FILL_FLOAT
Default fill value.
Definition: netcdf.h:70
#define NC_EVARMETA
Problem with variable metadata.
Definition: netcdf.h:442
This is the type of arrays of vlens.
Definition: netcdf.h:684
#define NC_SHORT
signed 2 byte integer
Definition: netcdf.h:36
#define NC_ENDIAN_NATIVE
In HDF5 files you can set the endianness of variables with nc_def_var_endian().
Definition: netcdf.h:282
#define NC_ENOTVAR
Variable not found.
Definition: netcdf.h:376
#define NC_EPERM
Write to read only.
Definition: netcdf.h:333
#define NC_NOERR
No Error.
Definition: netcdf.h:322
#define NC_ENUM
enum types
Definition: netcdf.h:54
#define NC_FILL_SHORT
Default fill value.
Definition: netcdf.h:68
#define NC_FILL_DOUBLE
Default fill value.
Definition: netcdf.h:71
#define NC_COMPOUND
compound types
Definition: netcdf.h:55
#define NC_FILL_USHORT
Default fill value.
Definition: netcdf.h:73
#define NC_FILL_BYTE
Default fill value.
Definition: netcdf.h:66
#define NC_GLOBAL
Attribute id to put/get a global attribute.
Definition: netcdf.h:245
#define NC_FLOAT
single precision floating point number
Definition: netcdf.h:39
#define NC_FILL_INT64
Default fill value.
Definition: netcdf.h:75
#define NC_UINT64
unsigned 8-byte int
Definition: netcdf.h:45

Return to the Main Unidata NetCDF page.
Generated on Tue Nov 20 2018 06:04:35 for NetCDF. NetCDF is a Unidata library.