bes  Updated for version 3.20.6
h5get.cc
Go to the documentation of this file.
1 // data server.
2 
3 // Copyright (c) 2007-2016 The HDF Group, Inc. and OPeNDAP, Inc.
4 //
5 // This is free software; you can redistribute it and/or modify it under the
6 // terms of the GNU Lesser General Public License as published by the Free
7 // Software Foundation; either version 2.1 of the License, or (at your
8 // option) any later version.
9 //
10 // This software is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
13 // License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 //
19 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
20 // You can contact The HDF Group, Inc. at 1800 South Oak Street,
21 // Suite 203, Champaign, IL 61820
22 
35 
36 #include "h5get.h"
37 #include "HDF5Int32.h"
38 #include "HDF5UInt32.h"
39 #include "HDF5UInt16.h"
40 #include "HDF5Int16.h"
41 #include "HDF5Byte.h"
42 #include "HDF5Int8.h"
43 #include "HDF5Int64.h"
44 #include "HDF5UInt64.h"
45 #include "HDF5Array.h"
46 #include "HDF5Str.h"
47 #include "HDF5Float32.h"
48 #include "HDF5Float64.h"
49 #include "HDF5Url.h"
50 #include "HDF5Structure.h"
51 
52 #include <BESDebug.h>
53 #include <math.h>
54 #include <sstream>
55 
56 using namespace libdap;
57 
58 // H5Ovisit call back function. When finding the dimension scale attributes, return 1.
59 static int
60 visit_obj_cb(hid_t o_id, const char *name, const H5O_info_t *oinfo,
61  void *_op_data);
62 
63 // H5Aiterate2 call back function, check if having the dimension scale attributes.
64 static herr_t attr_info(hid_t loc_id, const char *name, const H5A_info_t *ainfo, void *opdata);
65 
66 
83 hid_t get_attr_info(hid_t dset, int index, bool is_dap4, DSattr_t * attr_inst_ptr,
84  bool *ignore_attr_ptr)
85 {
86 
87  hid_t attrid = -1;
88 
89  // Always assume that we don't ignore any attributes.
90  *ignore_attr_ptr = false;
91 
92  if ((attrid = H5Aopen_by_idx(dset, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC,(hsize_t)index, H5P_DEFAULT, H5P_DEFAULT)) < 0) {
93  string msg = "unable to open attribute by index ";
94  throw InternalErr(__FILE__, __LINE__, msg);
95  }
96 
97  // Obtain the size of attribute name.
98  ssize_t name_size = H5Aget_name(attrid, 0, NULL);
99  if (name_size < 0) {
100  H5Aclose(attrid);
101  string msg = "unable to obtain the size of the hdf5 attribute name ";
102  throw InternalErr(__FILE__, __LINE__, msg);
103  }
104 
105  vector<char> attr_name;
106  attr_name.resize(name_size+1);
107  // Obtain the attribute name.
108  if ((H5Aget_name(attrid, name_size+1, &attr_name[0])) < 0) {
109  H5Aclose(attrid);
110  string msg = "unable to obtain the hdf5 attribute name ";
111  throw InternalErr(__FILE__, __LINE__, msg);
112  }
113 
114  // Obtain the type of the attribute.
115  hid_t ty_id = -1;
116  if ((ty_id = H5Aget_type(attrid)) < 0) {
117  string msg = "unable to obtain hdf5 datatype for the attribute ";
118  string attrnamestr(attr_name.begin(),attr_name.end());
119  msg += attrnamestr;
120  H5Aclose(attrid);
121  throw InternalErr(__FILE__, __LINE__, msg);
122  }
123 
124  H5T_class_t ty_class = H5Tget_class(ty_id);
125  if (ty_class < 0) {
126  string msg = "cannot get hdf5 attribute datatype class for the attribute ";
127  string attrnamestr(attr_name.begin(),attr_name.end());
128  msg += attrnamestr;
129  H5Aclose(attrid);
130  throw InternalErr(__FILE__, __LINE__, msg);
131  }
132 
133  // The following datatype will not be supported for mapping to DAS for both DAP2 and DAP4.
134  // Note:DAP4 explicitly states that the data should be defined atomic datatype(int, string).
135  // 1-D variable length of string can also be mapped to both DAS and DDS.
136  // The variable length string class is H5T_STRING rather than H5T_VLEN,
137  // So safe here.
138  // We also ignore the mapping of integer 64 bit for DAP2 since DAP2 doesn't
139  // support 64-bit integer. In theory, DAP2 doesn't support long double
140  // (128-bit or 92-bit floating point type), since this rarely happens
141  // in DAP application, we simply don't consider here.
142  // However, DAP4 supports 64-bit integer.
143  if ((ty_class == H5T_TIME) || (ty_class == H5T_BITFIELD)
144  || (ty_class == H5T_OPAQUE) || (ty_class == H5T_ENUM)
145  || (ty_class == H5T_REFERENCE) ||(ty_class == H5T_COMPOUND)
146  || (ty_class == H5T_VLEN) || (ty_class == H5T_ARRAY)){
147 
148  *ignore_attr_ptr = true;
149  H5Tclose(ty_id);
150  return attrid;
151  }
152 
153  // Ignore 64-bit integer for DAP2.
154  // The nested if is better to understand the code. Don't combine
155  if (false == is_dap4) {
156  if((ty_class == H5T_INTEGER) && (H5Tget_size(ty_id)== 8)) {//64-bit int
157  *ignore_attr_ptr = true;
158  H5Tclose(ty_id);
159  return attrid;
160  }
161  }
162 
163  hid_t aspace_id = -1;
164  if ((aspace_id = H5Aget_space(attrid)) < 0) {
165  string msg = "cannot get hdf5 dataspace id for the attribute ";
166  string attrnamestr(attr_name.begin(),attr_name.end());
167  msg += attrnamestr;
168  H5Aclose(attrid);
169  throw InternalErr(__FILE__, __LINE__, msg);
170  }
171 
172  // It is better to use the dynamic allocation of the array.
173  // However, since the DODS_MAX_RANK is not big and it is also
174  // used in other location, we still keep the original code.
175  // KY 2011-11-16
176 
177  int ndims = H5Sget_simple_extent_ndims(aspace_id);
178  if (ndims < 0) {
179  string msg = "cannot get hdf5 dataspace number of dimension for attribute ";
180  string attrnamestr(attr_name.begin(),attr_name.end());
181  msg += attrnamestr;
182  H5Sclose(aspace_id);
183  H5Aclose(attrid);
184  throw InternalErr(__FILE__, __LINE__, msg);
185  }
186 
187  // Check if the dimension size exceeds the maximum number of dimension DAP supports
188  if (ndims > DODS_MAX_RANK) {
189  string msg = "number of dimensions exceeds allowed for attribute ";
190  string attrnamestr(attr_name.begin(),attr_name.end());
191  msg += attrnamestr;
192  H5Sclose(aspace_id);
193  H5Aclose(attrid);
194  throw InternalErr(__FILE__, __LINE__, msg);
195  }
196 
197  hsize_t size[DODS_MAX_RANK];
198  hsize_t maxsize[DODS_MAX_RANK];
199 
200  //The HDF5 attribute should not have unlimited dimension,
201  // maxsize is only a place holder.
202  if (H5Sget_simple_extent_dims(aspace_id, size, maxsize)<0){
203  string msg = "cannot obtain the dim. info for the attribute ";
204  string attrnamestr(attr_name.begin(),attr_name.end());
205  msg += attrnamestr;
206  H5Sclose(aspace_id);
207  H5Aclose(attrid);
208  throw InternalErr(__FILE__, __LINE__, msg);
209  }
210 
211  // Return ndims and size[ndims].
212  hsize_t nelmts = 1;
213  if (ndims) {
214  for (int j = 0; j < ndims; j++)
215  nelmts *= size[j];
216  }
217 
218  size_t ty_size = H5Tget_size(ty_id);
219  if (ty_size == 0) {
220  string msg = "cannot obtain the dtype size for the attribute ";
221  string attrnamestr(attr_name.begin(),attr_name.end());
222  msg += attrnamestr;
223  H5Sclose(aspace_id);
224  H5Aclose(attrid);
225  throw InternalErr(__FILE__, __LINE__, msg);
226  }
227 
228  size_t need = nelmts * H5Tget_size(ty_id);
229 
230  // We want to save memory type in the struct.
231  hid_t memtype = H5Tget_native_type(ty_id, H5T_DIR_ASCEND);
232  if (memtype < 0){
233  string msg = "cannot obtain the memory dtype for the attribute ";
234  string attrnamestr(attr_name.begin(),attr_name.end());
235  msg += attrnamestr;
236  H5Sclose(aspace_id);
237  H5Aclose(attrid);
238  throw InternalErr(__FILE__, __LINE__, msg);
239  }
240 
241  // Save the information to the struct
242  (*attr_inst_ptr).type = memtype;
243  (*attr_inst_ptr).ndims = ndims;
244  (*attr_inst_ptr).nelmts = nelmts;
245  (*attr_inst_ptr).need = need;
246  strncpy((*attr_inst_ptr).name, &attr_name[0], name_size+1);
247 
248  for (int j = 0; j < ndims; j++) {
249  (*attr_inst_ptr).size[j] = size[j];
250  }
251 
252  if(H5Sclose(aspace_id)<0) {
253  H5Aclose(attrid);
254  throw InternalErr(__FILE__,__LINE__,"Cannot close HDF5 dataspace ");
255  }
256 
257  return attrid;
258 }
259 
272 string get_dap_type(hid_t type, bool is_dap4)
273 {
274  size_t size = 0;
275  H5T_sign_t sign;
276  BESDEBUG("h5", ">get_dap_type(): type=" << type << endl);
277  H5T_class_t class_t = H5Tget_class(type);
278  if (H5T_NO_CLASS == class_t)
279  throw InternalErr(__FILE__, __LINE__,
280  "The HDF5 datatype doesn't belong to any Class.");
281  switch (class_t) {
282 
283  case H5T_INTEGER:
284 
285  size = H5Tget_size(type);
286  if (size == 0){
287  throw InternalErr(__FILE__, __LINE__,
288  "size of datatype is invalid");
289  }
290 
291  sign = H5Tget_sign(type);
292  if (sign < 0){
293  throw InternalErr(__FILE__, __LINE__,
294  "sign of datatype is invalid");
295  }
296 
297  BESDEBUG("h5", "=get_dap_type(): H5T_INTEGER" <<
298  " sign = " << sign <<
299  " size = " << size <<
300  endl);
301  if (size == 1){
302  // DAP2 doesn't have signed 8-bit integer, so we need map it to INT16.
303  if(true == is_dap4) {
304  if (sign == H5T_SGN_NONE)
305  return BYTE;
306  else
307  return INT8;
308  }
309  else {
310  if (sign == H5T_SGN_NONE)
311  return BYTE;
312  else
313  return INT16;
314  }
315  }
316 
317  if (size == 2) {
318  if (sign == H5T_SGN_NONE)
319  return UINT16;
320  else
321  return INT16;
322  }
323 
324  if (size == 4) {
325  if (sign == H5T_SGN_NONE)
326  return UINT32;
327  else
328  return INT32;
329  }
330 
331  if(size == 8) {
332  // DAP4 supports 64-bit integer.
333  if (true == is_dap4) {
334  if (sign == H5T_SGN_NONE)
335  return UINT64;
336  else
337  return INT64;
338  }
339  else
340  return INT_ELSE;
341  }
342 
343  return INT_ELSE;
344 
345  case H5T_FLOAT:
346  size = H5Tget_size(type);
347  if (size == 0){
348  throw InternalErr(__FILE__, __LINE__,
349  "size of the datatype is invalid");
350  }
351 
352  BESDEBUG("h5", "=get_dap_type(): FLOAT size = " << size << endl);
353  if (size == 4)
354  return FLOAT32;
355  if (size == 8)
356  return FLOAT64;
357 
358  return FLOAT_ELSE;
359 
360  case H5T_STRING:
361  BESDEBUG("h5", "<get_dap_type(): H5T_STRING" << endl);
362  return STRING;
363 
364  case H5T_REFERENCE:
365  BESDEBUG("h5", "<get_dap_type(): H5T_REFERENCE" << endl);
366  return URL;
367  // Note: Currently DAP2 and DAP4 only support defined atomic types.
368  // So the H5T_COMPOUND and H5_ARRAY cases should never be reached for attribute handling.
369  // However, this function may be used for variable handling.
370  case H5T_COMPOUND:
371  BESDEBUG("h5", "<get_dap_type(): COMPOUND" << endl);
372  return COMPOUND;
373 
374  case H5T_ARRAY:
375  return ARRAY;
376 
377  default:
378  BESDEBUG("h5", "<get_dap_type(): Unmappable Type" << endl);
379  return "Unmappable Type";
380  }
381 }
382 
392 hid_t get_fileid(const char *filename)
393 {
394  hid_t fileid = H5Fopen(filename, H5F_ACC_RDONLY, H5P_DEFAULT);
395  if (fileid < 0){
396  string msg = "cannot open the HDF5 file ";
397  string filenamestr(filename);
398  msg += filenamestr;
399  throw InternalErr(__FILE__, __LINE__, msg);
400  }
401 
402  return fileid;
403 }
404 
414 void close_fileid(hid_t fid)
415 {
416  if (H5Fclose(fid) < 0)
417  throw Error(unknown_error,
418  string("Could not close the HDF5 file."));
419 
420 }
421 
433 void get_dataset(hid_t pid, const string &dname, DS_t * dt_inst_ptr,bool use_dimscale)
434 {
435 
436  BESDEBUG("h5", ">get_dataset()" << endl);
437 
438  // Obtain the dataset ID
439  hid_t dset = -1;
440  if ((dset = H5Dopen(pid, dname.c_str(),H5P_DEFAULT)) < 0) {
441  string msg = "cannot open the HDF5 dataset ";
442  msg += dname;
443  throw InternalErr(__FILE__, __LINE__, msg);
444  }
445 
446  // Obtain the datatype ID
447  hid_t dtype = -1;
448  if ((dtype = H5Dget_type(dset)) < 0) {
449  H5Dclose(dset);
450  string msg = "cannot get the the datatype of HDF5 dataset ";
451  msg += dname;
452  throw InternalErr(__FILE__, __LINE__, msg);
453  }
454 
455  // Obtain the datatype class
456  H5T_class_t ty_class = H5Tget_class(dtype);
457  if (ty_class < 0) {
458  H5Tclose(dtype);
459  H5Dclose(dset);
460  string msg = "cannot get the datatype class of HDF5 dataset ";
461  msg += dname;
462  throw InternalErr(__FILE__, __LINE__, msg);
463  }
464 
465  // These datatype classes are unsupported. Note we do support
466  // variable length string and the variable length string class is
467  // H5T_STRING rather than H5T_VLEN.
468  if ((ty_class == H5T_TIME) || (ty_class == H5T_BITFIELD)
469  || (ty_class == H5T_OPAQUE) || (ty_class == H5T_ENUM) || (ty_class == H5T_VLEN)) {
470  string msg = "unexpected datatype of HDF5 dataset ";
471  msg += dname;
472  throw InternalErr(__FILE__, __LINE__, msg);
473  }
474 
475  hid_t dspace = -1;
476  if ((dspace = H5Dget_space(dset)) < 0) {
477  H5Tclose(dtype);
478  H5Dclose(dset);
479  string msg = "cannot get the the dataspace of HDF5 dataset ";
480  msg += dname;
481  throw InternalErr(__FILE__, __LINE__, msg);
482  }
483 
484  // It is better to use the dynamic allocation of the array.
485  // However, since the DODS_MAX_RANK is not big and it is also
486  // used in other location, we still keep the original code.
487  // KY 2011-11-17
488 
489  int ndims = H5Sget_simple_extent_ndims(dspace);
490  if (ndims < 0) {
491  H5Tclose(dtype);
492  H5Sclose(dspace);
493  H5Dclose(dset);
494  string msg = "cannot get hdf5 dataspace number of dimension for dataset ";
495  msg += dname;
496  throw InternalErr(__FILE__, __LINE__, msg);
497  }
498 
499  // Check if the dimension size exceeds the maximum number of dimension DAP supports
500  if (ndims > DODS_MAX_RANK) {
501  string msg = "number of dimensions exceeds allowed for dataset ";
502  msg += dname;
503  H5Tclose(dtype);
504  H5Sclose(dspace);
505  H5Dclose(dset);
506  throw InternalErr(__FILE__, __LINE__, msg);
507  }
508 
509  hsize_t size[DODS_MAX_RANK];
510  hsize_t maxsize[DODS_MAX_RANK];
511 
512  // Retrieve size. DAP4 doesn't have a convention to support multi-unlimited dimension yet.
513  if (H5Sget_simple_extent_dims(dspace, size, maxsize)<0){
514  string msg = "cannot obtain the dim. info for the dataset ";
515  msg += dname;
516  H5Tclose(dtype);
517  H5Sclose(dspace);
518  H5Dclose(dset);
519  throw InternalErr(__FILE__, __LINE__, msg);
520  }
521 
522  // return ndims and size[ndims].
523  hsize_t nelmts = 1;
524  if (ndims !=0) {
525  for (int j = 0; j < ndims; j++)
526  nelmts *= size[j];
527  }
528 
529  size_t dtype_size = H5Tget_size(dtype);
530  if (dtype_size == 0) {
531  string msg = "cannot obtain the data type size for the dataset ";
532  msg += dname;
533  H5Tclose(dtype);
534  H5Sclose(dspace);
535  H5Dclose(dset);
536  throw InternalErr(__FILE__, __LINE__, msg);
537  }
538 
539  size_t need = nelmts * dtype_size;
540 
541  hid_t memtype = H5Tget_native_type(dtype, H5T_DIR_ASCEND);
542  if (memtype < 0){
543  string msg = "cannot obtain the memory data type for the dataset ";
544  msg += dname;
545  H5Tclose(dtype);
546  H5Sclose(dspace);
547  H5Dclose(dset);
548  throw InternalErr(__FILE__, __LINE__, msg);
549  }
550 
551  (*dt_inst_ptr).type = memtype;
552  (*dt_inst_ptr).ndims = ndims;
553  (*dt_inst_ptr).nelmts = nelmts;
554  (*dt_inst_ptr).need = need;
555  strncpy((*dt_inst_ptr).name, dname.c_str(), dname.length());
556  (*dt_inst_ptr).name[dname.length()] = '\0';
557  for (int j = 0; j < ndims; j++)
558  (*dt_inst_ptr).size[j] = size[j];
559 
560  // For DAP4 when dimension scales are used.
561  if(true == use_dimscale) {
562 
563  // Some HDF5 datasets are dimension scale datasets; some are not. We need to distinguish.
564  bool is_dimscale = false;
565 
566  // Dimension scales must be 1-D.
567  if(1 == ndims) {
568 
569  int count = 0;
570 
571  // This will check if Dimension scale attributes present.
572  herr_t ret = H5Aiterate2(dset, H5_INDEX_NAME, H5_ITER_INC, NULL, attr_info, &count);
573  if(ret < 0) {
574  string msg = "cannot interate the attributes of the dataset ";
575  msg += dname;
576  H5Tclose(dtype);
577  H5Sclose(dspace);
578  H5Dclose(dset);
579  throw InternalErr(__FILE__, __LINE__, msg);
580  }
581 
582  // Find the dimension scale.
583  if (2==count)
584  is_dimscale =true;
585 
586  }
587 
588  if(true == is_dimscale) {
589  // Save the dimension names.We Only need to provide the dimension name(not the full path).
590  (*dt_inst_ptr).dimnames.push_back(dname.substr(dname.find_last_of("/")+1));
591  }
592  else // We need to save all dimension names in this dimension.
593  obtain_dimnames(dset,ndims,dt_inst_ptr);
594  }
595 
596  if(H5Tclose(dtype)<0) {
597  H5Sclose(dspace);
598  H5Dclose(dset);
599  throw InternalErr(__FILE__, __LINE__, "Cannot close the HDF5 datatype.");
600  }
601 
602  if(H5Sclose(dspace)<0) {
603  H5Dclose(dset);
604  throw InternalErr(__FILE__, __LINE__, "Cannot close the HDF5 dataspace.");
605  }
606 
607  if(H5Dclose(dset)<0) {
608  throw InternalErr(__FILE__, __LINE__, "Cannot close the HDF5 dataset.");
609  }
610 
611 }
612 
621 bool check_h5str(hid_t h5type)
622 {
623  if (H5Tget_class(h5type) == H5T_STRING)
624  return true;
625  else
626  return false;
627 }
628 
629 
642 string print_attr(hid_t type, int loc, void *sm_buf) {
643  union {
644  unsigned char* ucp;
645  char *tcp;
646  short *tsp;
647  unsigned short *tusp;
648  int *tip;
649  unsigned int*tuip;
650  long *tlp;
651  unsigned long*tulp;
652  float *tfp;
653  double *tdp;
654  } gp;
655 
656  vector<char> rep;
657 
658  switch (H5Tget_class(type)) {
659 
660  case H5T_INTEGER: {
661 
662  size_t size = H5Tget_size(type);
663  if (size == 0){
664  throw InternalErr(__FILE__, __LINE__,
665  "size of datatype is invalid");
666  }
667 
668  H5T_sign_t sign = H5Tget_sign(type);
669  if (sign < 0){
670  throw InternalErr(__FILE__, __LINE__,
671  "sign of datatype is invalid");
672  }
673 
674  BESDEBUG("h5", "=get_dap_type(): H5T_INTEGER" <<
675  " sign = " << sign <<
676  " size = " << size <<
677  endl);
678 
679  // change void pointer into the corresponding integer datatype.
680  // 32 should be long enough to hold one integer and one
681  // floating point number.
682  rep.resize(32);
683 
684  if (size == 1){
685 
686  if(sign == H5T_SGN_NONE) {
687  gp.ucp = (unsigned char *) sm_buf;
688  unsigned char tuchar = *(gp.ucp + loc);
689  snprintf(&rep[0], 32, "%u", tuchar);
690  }
691 
692  else {
693  gp.tcp = (char *) sm_buf;
694  snprintf(&rep[0], 32, "%d", *(gp.tcp + loc));
695  }
696  }
697 
698  else if (size == 2) {
699 
700  if(sign == H5T_SGN_NONE) {
701  gp.tusp = (unsigned short *) sm_buf;
702  snprintf(&rep[0], 32, "%hu", *(gp.tusp + loc));
703 
704  }
705  else {
706  gp.tsp = (short *) sm_buf;
707  snprintf(&rep[0], 32, "%hd", *(gp.tsp + loc));
708 
709  }
710  }
711 
712  else if (size == 4) {
713 
714  if(sign == H5T_SGN_NONE) {
715  gp.tuip = (unsigned int *) sm_buf;
716  snprintf(&rep[0], 32, "%u", *(gp.tuip + loc));
717 
718  }
719  else {
720  gp.tip = (int *) sm_buf;
721  snprintf(&rep[0], 32, "%d", *(gp.tip + loc));
722  }
723  }
724  else if (size == 8) {
725 
726  if(sign == H5T_SGN_NONE) {
727  gp.tulp = (unsigned long *) sm_buf;
728  snprintf(&rep[0], 32, "%lu", *(gp.tulp + loc));
729  }
730  else {
731  gp.tlp = (long *) sm_buf;
732  snprintf(&rep[0], 32, "%ld", *(gp.tlp + loc));
733  }
734  }
735  else
736  throw InternalErr(__FILE__, __LINE__,"Unsupported integer type, check the size of datatype.");
737 
738  break;
739  }
740 
741  case H5T_FLOAT: {
742  rep.resize(32);
743  char gps[32];
744 
745  if (H5Tget_size(type) == 4) {
746 
747  float attr_val = *(float*)sm_buf;
748  bool is_a_fin = isfinite(attr_val);
749  // Represent the float number.
750  // Some space may be wasted. But it is okay.
751  gp.tfp = (float *) sm_buf;
752  int ll = snprintf(gps, 30, "%.10g", *(gp.tfp + loc));
753  //int ll = strlen(gps);
754 
755  // Add the dot to assure this is a floating number
756  if (!strchr(gps, '.') && !strchr(gps, 'e') && !strchr(gps,'E')
757  && (true == is_a_fin)){
758  gps[ll++] = '.';
759  }
760 
761  gps[ll] = '\0';
762  snprintf(&rep[0], 32, "%s", gps);
763  }
764  else if (H5Tget_size(type) == 8) {
765 
766  double attr_val = *(double*)sm_buf;
767  bool is_a_fin = isfinite(attr_val);
768  gp.tdp = (double *) sm_buf;
769  int ll = snprintf(gps, 30, "%.17g", *(gp.tdp + loc));
770 #if 0
771  //int ll = strlen(gps);
772 #endif
773  if (!strchr(gps, '.') && !strchr(gps, 'e')&& !strchr(gps,'E')
774  && (true == is_a_fin)) {
775  gps[ll++] = '.';
776  }
777  gps[ll] = '\0';
778  snprintf(&rep[0], 32, "%s", gps);
779  }
780  else if (H5Tget_size(type) == 0){
781  throw InternalErr(__FILE__, __LINE__, "H5Tget_size() failed.");
782  }
783  break;
784  }
785 
786  case H5T_STRING: {
787  int str_size = H5Tget_size(type);
788  if(H5Tis_variable_str(type)>0) {
789  throw InternalErr(__FILE__, __LINE__,
790  "print_attr function doesn't handle variable length string, variable length string should be handled separately.");
791  }
792  if (str_size == 0){
793  throw InternalErr(__FILE__, __LINE__, "H5Tget_size() failed.");
794  }
795  BESDEBUG("h5", "=print_attr(): H5T_STRING sm_buf=" << (char *) sm_buf
796  << " size=" << str_size << endl);
797  char *buf = NULL;
798  // This try/catch block is here to protect the allocation of buf.
799  try {
800  buf = new char[str_size + 1];
801  strncpy(buf, (char *) sm_buf, str_size);
802  buf[str_size] = '\0';
803  // Not necessarily allocate 3 more bytes.
804  rep.resize(str_size+3);
805  snprintf(&rep[0], str_size + 3, "%s", buf);
806  rep[str_size + 2] = '\0';
807  delete[] buf; buf = 0;
808  }
809  catch (...) {
810  if( buf ) delete[] buf;
811  throw;
812  }
813  break;
814  }
815 
816  default:
817  break;
818  } // switch(H5Tget_class(type))
819 
820  string rep_str(rep.begin(),rep.end());
821  return rep_str;
822 }
823 
824 D4AttributeType daptype_strrep_to_dap4_attrtype(std::string s){
825 
826  if (s == "Byte")
827  return attr_byte_c;
828  else if (s == "Int8")
829  return attr_int8_c;
830  else if (s == "UInt8") // This may never be used.
831  return attr_uint8_c;
832  else if (s == "Int16")
833  return attr_int16_c;
834  else if (s == "UInt16")
835  return attr_uint16_c;
836  else if (s == "Int32")
837  return attr_int32_c;
838  else if (s == "UInt32")
839  return attr_uint32_c;
840  else if (s == "Int64")
841  return attr_int64_c;
842  else if (s == "UInt64")
843  return attr_uint64_c;
844  else if (s == "Float32")
845  return attr_float32_c;
846  else if (s == "Float64")
847  return attr_float64_c;
848  else if (s == "String")
849  return attr_str_c;
850  else if (s == "Url")
851  return attr_url_c;
852  else
853  return attr_null_c;
854 
855 
856 }
857 
858 
872 //static BaseType *Get_bt(const string &vname,
873 BaseType *Get_bt(const string &vname,
874  const string &vpath,
875  const string &dataset,
876  hid_t datatype, bool is_dap4)
877 {
878  BaseType *btp = NULL;
879 
880  try {
881 
882  BESDEBUG("h5", ">Get_bt varname=" << vname << " datatype=" << datatype
883  << endl);
884 
885  size_t size = 0;
886  H5T_sign_t sign = H5T_SGN_ERROR;
887  switch (H5Tget_class(datatype)) {
888 
889  case H5T_INTEGER:
890  {
891  size = H5Tget_size(datatype);
892  sign = H5Tget_sign(datatype);
893  BESDEBUG("h5", "=Get_bt() H5T_INTEGER size = " << size << " sign = "
894  << sign << endl);
895 
896  if (sign == H5T_SGN_ERROR) {
897  throw InternalErr(__FILE__, __LINE__, "cannot retrieve the sign type of the integer");
898  }
899  if (size == 0) {
900  throw InternalErr(__FILE__, __LINE__, "cannot return the size of the datatype");
901  }
902  else if (size == 1) { // Either signed char or unsigned char
903  // DAP2 doesn't support signed char, it maps to DAP int16.
904  if (sign == H5T_SGN_2) {
905  if (false == is_dap4) // signed char to DAP2 int16
906  btp = new HDF5Int16(vname, vpath, dataset);
907  else
908  btp = new HDF5Int8(vname,vpath,dataset);
909  }
910  else
911  btp = new HDF5Byte(vname, vpath,dataset);
912  }
913  else if (size == 2) {
914  if (sign == H5T_SGN_2)
915  btp = new HDF5Int16(vname, vpath,dataset);
916  else
917  btp = new HDF5UInt16(vname,vpath, dataset);
918  }
919  else if (size == 4) {
920  if (sign == H5T_SGN_2){
921  btp = new HDF5Int32(vname, vpath,dataset);
922  }
923  else
924  btp = new HDF5UInt32(vname,vpath, dataset);
925  }
926  else if (size == 8) {
927  if(true == is_dap4) {
928  if(sign == H5T_SGN_2)
929  btp = new HDF5Int64(vname,vpath, dataset);
930  else
931  btp = new HDF5UInt64(vname,vpath, dataset);
932  }
933  else {
934  throw
935  InternalErr(__FILE__, __LINE__,
936  string("Unsupported HDF5 64-bit Integer type:")
937  + vname);
938  }
939  }
940  }
941  break;
942 
943  case H5T_FLOAT:
944  {
945  size = H5Tget_size(datatype);
946  BESDEBUG("h5", "=Get_bt() H5T_FLOAT size = " << size << endl);
947 
948  if (size == 0) {
949  throw InternalErr(__FILE__, __LINE__, "cannot return the size of the datatype");
950  }
951  else if (size == 4) {
952  btp = new HDF5Float32(vname,vpath, dataset);
953  }
954  else if (size == 8) {
955  btp = new HDF5Float64(vname,vpath, dataset);
956  }
957  }
958  break;
959 
960  case H5T_STRING:
961  btp = new HDF5Str(vname, vpath,dataset);
962  break;
963 
964  // The array datatype is rarely,rarely used. So this
965  // part of code is not reviewed.
966 #if 0
967  case H5T_ARRAY: {
968  BaseType *ar_bt = 0;
969  try {
970  BESDEBUG("h5",
971  "=Get_bt() H5T_ARRAY datatype = " << datatype
972  << endl);
973 
974  // Get the base datatype of the array
975  hid_t dtype_base = H5Tget_super(datatype);
976  ar_bt = Get_bt(vname, dataset, dtype_base);
977  btp = new HDF5Array(vname, dataset, ar_bt);
978  delete ar_bt; ar_bt = 0;
979 
980  // Set the size of the array.
981  int ndim = H5Tget_array_ndims(datatype);
982  size = H5Tget_size(datatype);
983  int nelement = 1;
984 
985  if (dtype_base < 0) {
986  throw InternalErr(__FILE__, __LINE__, "cannot return the base datatype");
987  }
988  if (ndim < 0) {
989  throw InternalErr(__FILE__, __LINE__, "cannot return the rank of the array datatype");
990  }
991  if (size == 0) {
992  throw InternalErr(__FILE__, __LINE__, "cannot return the size of the datatype");
993  }
994  BESDEBUG(cerr
995  << "=Get_bt()" << " Dim = " << ndim
996  << " Size = " << size
997  << endl);
998 
999  hsize_t size2[DODS_MAX_RANK];
1000  if(H5Tget_array_dims(datatype, size2) < 0){
1001  throw
1002  InternalErr(__FILE__, __LINE__,
1003  string("Could not get array dims for: ")
1004  + vname);
1005  }
1006 
1007 
1008  HDF5Array &h5_ar = static_cast < HDF5Array & >(*btp);
1009  for (int dim_index = 0; dim_index < ndim; dim_index++) {
1010  h5_ar.append_dim(size2[dim_index]);
1011  BESDEBUG("h5", "=Get_bt() " << size2[dim_index] << endl);
1012  nelement = nelement * size2[dim_index];
1013  }
1014 
1015  h5_ar.set_did(dt_inst.dset);
1016  // Assign the array datatype id.
1017  h5_ar.set_tid(datatype);
1018  h5_ar.set_memneed(size);
1019  h5_ar.set_numdim(ndim);
1020  h5_ar.set_numelm(nelement);
1021  h5_ar.set_length(nelement);
1022  h5_ar.d_type = H5Tget_class(dtype_base);
1023  if (h5_ar.d_type == H5T_NO_CLASS){
1024  throw InternalErr(__FILE__, __LINE__, "cannot return the datatype class identifier");
1025  }
1026  }
1027  catch (...) {
1028  if( ar_bt ) delete ar_bt;
1029  if( btp ) delete btp;
1030  throw;
1031  }
1032  break;
1033  }
1034 #endif
1035 
1036  // Reference map to DAP URL, check the technical note.
1037  case H5T_REFERENCE:
1038  btp = new HDF5Url(vname, vpath,dataset);
1039  break;
1040 
1041  default:
1042  throw InternalErr(__FILE__, __LINE__,
1043  string("Unsupported HDF5 type: ") + vname);
1044  }
1045  }
1046  catch (...) {
1047  if( btp ) delete btp;
1048  throw;
1049  }
1050 
1051  if (!btp)
1052  throw InternalErr(__FILE__, __LINE__,
1053  string("Could not make a DAP variable for: ")
1054  + vname);
1055 
1056  BESDEBUG("h5", "<Get_bt()" << endl);
1057  return btp;
1058 }
1059 
1060 
1077 //static Structure *Get_structure(const string &varname,
1078 Structure *Get_structure(const string &varname,const string &vpath,
1079  const string &dataset,
1080  hid_t datatype,bool is_dap4)
1081 {
1082  HDF5Structure *structure_ptr = NULL;
1083  char* memb_name = NULL;
1084  hid_t memb_type = -1;
1085 
1086  BESDEBUG("h5", ">Get_structure()" << datatype << endl);
1087 
1088  if (H5Tget_class(datatype) != H5T_COMPOUND)
1089  throw InternalErr(__FILE__, __LINE__,
1090  string("Compound-to-structure mapping error for ")
1091  + varname);
1092 
1093  try {
1094  structure_ptr = new HDF5Structure(varname, vpath, dataset);
1095 
1096  // Retrieve member types
1097  int nmembs = H5Tget_nmembers(datatype);
1098  BESDEBUG("h5", "=Get_structure() has " << nmembs << endl);
1099  if (nmembs < 0){
1100  throw InternalErr(__FILE__, __LINE__, "cannot retrieve the number of elements");
1101  }
1102  for (int i = 0; i < nmembs; i++) {
1103  memb_name = H5Tget_member_name(datatype, i);
1104  H5T_class_t memb_cls = H5Tget_member_class(datatype, i);
1105  memb_type = H5Tget_member_type(datatype, i);
1106  if (memb_name == NULL){
1107  throw InternalErr(__FILE__, __LINE__, "cannot retrieve the name of the member");
1108  }
1109  if ((memb_cls < 0) || (memb_type < 0)) {
1110  throw InternalErr(__FILE__, __LINE__,
1111  string("Type mapping error for ")
1112  + string(memb_name) );
1113  }
1114 
1115  if (memb_cls == H5T_COMPOUND) {
1116  Structure *s = Get_structure(memb_name, memb_name, dataset, memb_type,is_dap4);
1117  structure_ptr->add_var(s);
1118  delete s; s = 0;
1119  }
1120  else if(memb_cls == H5T_ARRAY) {
1121 
1122  BaseType *ar_bt = 0;
1123  BaseType *btp = 0;
1124  Structure *s = 0;
1125  hid_t dtype_base = 0;
1126 
1127  try {
1128 
1129  // Get the base memb_type of the array
1130  dtype_base = H5Tget_super(memb_type);
1131 
1132  // Set the size of the array.
1133  int ndim = H5Tget_array_ndims(memb_type);
1134  size_t size = H5Tget_size(memb_type);
1135  int nelement = 1;
1136 
1137  if (dtype_base < 0) {
1138  throw InternalErr(__FILE__, __LINE__, "cannot return the base memb_type");
1139  }
1140  if (ndim < 0) {
1141  throw InternalErr(__FILE__, __LINE__, "cannot return the rank of the array memb_type");
1142  }
1143  if (size == 0) {
1144  throw InternalErr(__FILE__, __LINE__, "cannot return the size of the memb_type");
1145  }
1146 
1147  hsize_t size2[DODS_MAX_RANK];
1148  if(H5Tget_array_dims(memb_type, size2) < 0){
1149  throw
1150  InternalErr(__FILE__, __LINE__,
1151  string("Could not get array dims for: ")
1152  + string(memb_name));
1153  }
1154 
1155  H5T_class_t array_memb_cls = H5Tget_class(dtype_base);
1156  if(array_memb_cls == H5T_NO_CLASS) {
1157  throw InternalErr(__FILE__, __LINE__,
1158  string("cannot get the correct class for compound type member")
1159  + string(memb_name));
1160  }
1161  if(H5T_COMPOUND == array_memb_cls) {
1162 
1163  s = Get_structure(memb_name, memb_name,dataset, dtype_base,is_dap4);
1164  HDF5Array *h5_ar = new HDF5Array(memb_name, dataset, s);
1165 
1166  for (int dim_index = 0; dim_index < ndim; dim_index++) {
1167  h5_ar->append_dim(size2[dim_index]);
1168  nelement = nelement * size2[dim_index];
1169  }
1170 
1171  h5_ar->set_memneed(size);
1172  h5_ar->set_numdim(ndim);
1173  h5_ar->set_numelm(nelement);
1174  h5_ar->set_length(nelement);
1175 
1176  structure_ptr->add_var(h5_ar);
1177  delete h5_ar;
1178 
1179  }
1180  else if (H5T_INTEGER == array_memb_cls || H5T_FLOAT == array_memb_cls || H5T_STRING == array_memb_cls) {
1181  ar_bt = Get_bt(memb_name, memb_name,dataset, dtype_base,is_dap4);
1182  HDF5Array *h5_ar = new HDF5Array(memb_name,dataset,ar_bt);
1183 
1184  for (int dim_index = 0; dim_index < ndim; dim_index++) {
1185  h5_ar->append_dim(size2[dim_index]);
1186  nelement = nelement * size2[dim_index];
1187  }
1188 
1189  h5_ar->set_memneed(size);
1190  h5_ar->set_numdim(ndim);
1191  h5_ar->set_numelm(nelement);
1192  h5_ar->set_length(nelement);
1193 
1194  structure_ptr->add_var(h5_ar);
1195  delete h5_ar;
1196  }
1197  if( ar_bt ) delete ar_bt;
1198  if( btp ) delete btp;
1199  if(s) delete s;
1200  H5Tclose(dtype_base);
1201 
1202  }
1203  catch (...) {
1204  if( ar_bt ) delete ar_bt;
1205  if( btp ) delete btp;
1206  if(s) delete s;
1207  H5Tclose(dtype_base);
1208  throw;
1209  }
1210 
1211  }
1212  else if (memb_cls == H5T_INTEGER || memb_cls == H5T_FLOAT || memb_cls == H5T_STRING) {
1213  BaseType *bt = Get_bt(memb_name, memb_name,dataset, memb_type,is_dap4);
1214  structure_ptr->add_var(bt);
1215  delete bt; bt = 0;
1216  }
1217  else {
1218  free(memb_name);
1219  memb_name = NULL;
1220  throw InternalErr(__FILE__, __LINE__, "unsupported field datatype inside a compound datatype");
1221  }
1222  // Caller needs to free the memory allocated by the library for memb_name.
1223  if(memb_name != NULL)
1224  free(memb_name);
1225  }
1226  }
1227  catch (...) {
1228  if( structure_ptr )
1229  delete structure_ptr;
1230  if(memb_name!= NULL)
1231  free(memb_name);
1232  if(memb_type != -1)
1233  H5Tclose(memb_type);
1234  throw;
1235  }
1236 
1237  BESDEBUG("h5", "<Get_structure()" << endl);
1238 
1239  return structure_ptr;
1240 }
1241 
1258 
1259 // Function to use H5Ovisit to check if dimension scale attributes exist.
1260 bool check_dimscale(hid_t fileid) {
1261 
1262  bool ret_value = false;
1263  herr_t ret_o= H5Ovisit(fileid, H5_INDEX_NAME, H5_ITER_INC, visit_obj_cb, NULL);
1264  if(ret_o < 0)
1265  throw InternalErr(__FILE__, __LINE__, "H5Ovisit fails");
1266  else
1267  ret_value =(ret_o >0)?true:false;
1268 
1269  return ret_value;
1270 }
1271 
1272 static int
1273 visit_obj_cb(hid_t group_id, const char *name, const H5O_info_t *oinfo,
1274  void *_op_data)
1275 {
1276 
1277  if(oinfo->type == H5O_TYPE_DATASET) {
1278 
1279  hid_t dataset = -1;
1280  dataset = H5Dopen2(group_id,name,H5P_DEFAULT);
1281  if(dataset <0)
1282  throw InternalErr(__FILE__, __LINE__, "H5Dopen2 fails in the H5Ovisit call back function.");
1283 
1284  hid_t dspace = -1;
1285  dspace = H5Dget_space(dataset);
1286  if(dspace <0) {
1287  H5Dclose(dataset);
1288  throw InternalErr(__FILE__, __LINE__, "H5Dget_space fails in the H5Ovisit call back function.");
1289  }
1290 
1291  // We only support netCDF-4 like dimension scales, that is the dimension scale dataset is 1-D dimension.
1292  if(H5Sget_simple_extent_ndims(dspace) == 1) {
1293 
1294  int count = 0;
1295  // Check if having "class = DIMENSION_SCALE" and REFERENCE_LIST attributes.
1296  herr_t ret = H5Aiterate2(dataset, H5_INDEX_NAME, H5_ITER_INC, NULL, attr_info, &count);
1297  if(ret < 0) {
1298  H5Sclose(dspace);
1299  H5Dclose(dataset);
1300  throw InternalErr(__FILE__, __LINE__, "H5Aiterate2 fails in the H5Ovisit call back function.");
1301  }
1302 
1303  // Find it.
1304  if (2==count) {
1305  if(dspace != -1)
1306  H5Sclose(dspace);
1307  if(dataset != -1)
1308  H5Dclose(dataset);
1309  return 1;
1310  }
1311 
1312  }
1313  if(dspace != -1)
1314  H5Sclose(dspace);
1315  if(dataset != -1)
1316  H5Dclose(dataset);
1317  }
1318  return 0;
1319 }
1332 
1333 static herr_t
1334 attr_info(hid_t loc_id, const char *name, const H5A_info_t *ainfo, void *opdata)
1335 {
1336  int *count = (int*)opdata;
1337 
1338  hid_t attr_id = -1;
1339  hid_t atype_id = -1;
1340 
1341  // Open the attribute
1342  attr_id = H5Aopen(loc_id, name, H5P_DEFAULT);
1343  if(attr_id < 0)
1344  throw InternalErr(__FILE__, __LINE__, "H5Aopen fails in the attr_info call back function.");
1345 
1346  // Get attribute datatype and dataspace
1347  atype_id = H5Aget_type(attr_id);
1348  if(atype_id < 0) {
1349  H5Aclose(attr_id);
1350  throw InternalErr(__FILE__, __LINE__, "H5Aget_type fails in the attr_info call back function.");
1351  }
1352 
1353  try {
1354 
1355  // If finding the "REFERENCE_LIST", increases the count.
1356  if ((H5T_COMPOUND == H5Tget_class(atype_id)) && (strcmp(name,"REFERENCE_LIST")==0)) {
1357  (*count)++;
1358  }
1359 
1360  // Check if finding the CLASS attribute.
1361  if ((H5T_STRING == H5Tget_class(atype_id)) && (strcmp(name,"CLASS") == 0)) {
1362 
1363  H5T_str_t str_pad = H5Tget_strpad(atype_id);
1364 
1365  hid_t aspace_id = -1;
1366  aspace_id = H5Aget_space(attr_id);
1367  if(aspace_id < 0)
1368  throw InternalErr(__FILE__, __LINE__, "H5Aget_space fails in the attr_info call back function.");
1369 
1370  // CLASS is a variable-length string
1371  int ndims = H5Sget_simple_extent_ndims(aspace_id);
1372  hsize_t nelmts = 1;
1373 
1374  // if it is a scalar attribute, just define number of elements to be 1.
1375  if (ndims != 0) {
1376 
1377  vector<hsize_t> asize;
1378  vector<hsize_t> maxsize;
1379  asize.resize(ndims);
1380  maxsize.resize(ndims);
1381 
1382  // DAP applications don't care about the unlimited dimensions
1383  // since the applications only care about retrieving the data.
1384  // So we don't check the maxsize to see if it is the unlimited dimension
1385  // attribute.
1386  if (H5Sget_simple_extent_dims(aspace_id, &asize[0], &maxsize[0])<0) {
1387  H5Sclose(aspace_id);
1388  throw InternalErr(__FILE__, __LINE__, "Cannot obtain the dim. info in the H5Aiterate2 call back function.");
1389  }
1390 
1391  // Return ndims and size[ndims].
1392  for (int j = 0; j < ndims; j++)
1393  nelmts *= asize[j];
1394  } // if(ndims != 0)
1395 
1396  size_t ty_size = H5Tget_size(atype_id);
1397  if (0 == ty_size) {
1398  H5Sclose(aspace_id);
1399  throw InternalErr(__FILE__, __LINE__, "Cannot obtain the type size in the H5Aiterate2 call back function.");
1400  }
1401 
1402  size_t total_bytes = nelmts * ty_size;
1403  string total_vstring ="";
1404  if(H5Tis_variable_str(atype_id) > 0) {
1405 
1406  // Variable length string attribute values only store pointers of the actual string value.
1407  vector<char> temp_buf;
1408  temp_buf.resize(total_bytes);
1409 
1410  if (H5Aread(attr_id, atype_id, &temp_buf[0]) < 0){
1411  H5Sclose(aspace_id);
1412  throw InternalErr(__FILE__,__LINE__,"Cannot read the attribute in the H5Aiterate2 call back function");
1413  }
1414 
1415  char *temp_bp = NULL;
1416  temp_bp = &temp_buf[0];
1417  char* onestring = NULL;
1418 
1419  for (unsigned int temp_i = 0; temp_i <nelmts; temp_i++) {
1420 
1421  // This line will assure that we get the real variable length string value.
1422  onestring =*(char **)temp_bp;
1423 
1424  if(onestring!= NULL)
1425  total_vstring +=string(onestring);
1426 
1427  // going to the next value.
1428  temp_bp +=ty_size;
1429  }
1430 
1431  if ((&temp_buf[0]) != NULL) {
1432  // Reclaim any VL memory if necessary.
1433  if (H5Dvlen_reclaim(atype_id,aspace_id,H5P_DEFAULT,&temp_buf[0]) < 0) {
1434  H5Sclose(aspace_id);
1435  throw InternalErr(__FILE__,__LINE__,"Cannot reclaim VL memory in the H5Aiterate2 call back function.");
1436  }
1437  }
1438 
1439  }
1440  else {// Fixed-size string, need to retrieve the string value.
1441 
1442  // string attribute values
1443  vector<char> temp_buf;
1444  temp_buf.resize(total_bytes);
1445  if (H5Aread(attr_id, atype_id, &temp_buf[0]) < 0){
1446  H5Sclose(aspace_id);
1447  throw InternalErr(__FILE__,__LINE__,"Cannot read the attribute in the H5Aiterate2 call back function");
1448  }
1449  string temp_buf_string(temp_buf.begin(),temp_buf.end());
1450  total_vstring = temp_buf_string.substr(0,total_bytes);
1451 
1452  // Note: we need to remove the string pad or term to find DIMENSION_SCALE.
1453  if(str_pad != H5T_STR_ERROR)
1454  total_vstring = total_vstring.substr(0,total_vstring.size()-1);
1455  }
1456 
1457  // Close attribute data space ID.
1458  if(aspace_id != -1)
1459  H5Sclose(aspace_id);
1460  if(total_vstring == "DIMENSION_SCALE"){
1461  (*count)++;
1462  }
1463  }
1464  }
1465  catch(...) {
1466  if(atype_id != -1)
1467  H5Tclose(atype_id);
1468  if(attr_id != -1)
1469  H5Aclose(attr_id);
1470  throw;
1471  }
1472 
1473  // Close IDs.
1474  if(atype_id != -1)
1475  H5Tclose(atype_id);
1476  if(attr_id != -1)
1477  H5Aclose(attr_id);
1478 
1479  //find both class=DIMENSION_SCALE and REFERENCE_LIST, just return 1.
1480  if((*count)==2)
1481  return 1;
1482 
1483  return 0;
1484 }
1485 
1486 
1494 void obtain_dimnames(hid_t dset,int ndims, DS_t *dt_inst_ptr) {
1495 
1496  htri_t has_dimension_list = -1;
1497 
1498  string dimlist_name = "DIMENSION_LIST";
1499  has_dimension_list = H5Aexists(dset,dimlist_name.c_str());
1500 
1501  if(has_dimension_list > 0 && ndims > 0) {
1502 
1503  hobj_ref_t rbuf;
1504  vector<hvl_t> vlbuf;
1505  vlbuf.resize(ndims);
1506 
1507  hid_t attr_id = -1;
1508  hid_t atype_id = -1;
1509  hid_t amemtype_id = -1;
1510  hid_t aspace_id = -1;
1511  hid_t ref_dset = -1;
1512 
1513  try {
1514  attr_id = H5Aopen(dset,dimlist_name.c_str(),H5P_DEFAULT);
1515  if (attr_id <0 ) {
1516  string msg = "Cannot open the attribute " + dimlist_name + " of HDF5 dataset "+ string(dt_inst_ptr->name);
1517  throw InternalErr(__FILE__, __LINE__, msg);
1518  }
1519 
1520  atype_id = H5Aget_type(attr_id);
1521  if (atype_id <0) {
1522  string msg = "Cannot get the datatype of the attribute " + dimlist_name + " of HDF5 dataset "+ string(dt_inst_ptr->name);
1523  throw InternalErr(__FILE__, __LINE__, msg);
1524  }
1525 
1526  amemtype_id = H5Tget_native_type(atype_id, H5T_DIR_ASCEND);
1527  if (amemtype_id < 0) {
1528  string msg = "Cannot get the memory datatype of the attribute " + dimlist_name + " of HDF5 dataset "+ string(dt_inst_ptr->name);
1529  throw InternalErr(__FILE__, __LINE__, msg);
1530 
1531  }
1532 
1533  if (H5Aread(attr_id,amemtype_id,&vlbuf[0]) <0) {
1534  string msg = "Cannot obtain the referenced object for the variable " + string(dt_inst_ptr->name);
1535  throw InternalErr(__FILE__, __LINE__, msg);
1536  }
1537 
1538  vector<char> objname;
1539 
1540  // The dimension names of variables will be the HDF5 dataset names dereferenced from the DIMENSION_LIST attribute.
1541  for (int i = 0; i < ndims; i++) {
1542 
1543  if(vlbuf[i].p == NULL) {
1544  stringstream sindex ;
1545  sindex <<i;
1546  string msg = "For variable " + string(dt_inst_ptr->name) + "; ";
1547  msg = msg + "the dimension of which the index is "+ sindex.str() + " doesn't exist. ";
1548  throw InternalErr(__FILE__, __LINE__, msg);
1549  }
1550 
1551  rbuf =((hobj_ref_t*)vlbuf[i].p)[0];
1552 
1553  // Note: H5Rget_name may be used to replace H5RDEREFERENCE and H5Iget_name in the future. KY 2016-06-28
1554  if ((ref_dset = H5RDEREFERENCE(attr_id, H5R_OBJECT, &rbuf)) < 0) {
1555  string msg = "Cannot dereference from the DIMENSION_LIST attribute for the variable " + string(dt_inst_ptr->name);
1556  throw InternalErr(__FILE__, __LINE__, msg);
1557  }
1558 
1559  ssize_t objnamelen = -1;
1560  if ((objnamelen= H5Iget_name(ref_dset,NULL,0))<=0) {
1561  string msg = "Cannot obtain the dimension name length for the variable " + string(dt_inst_ptr->name);
1562  throw InternalErr(__FILE__,__LINE__,msg);
1563  }
1564 
1565  objname.resize(objnamelen+1);
1566  if ((objnamelen= H5Iget_name(ref_dset,&objname[0],objnamelen+1))<=0) {
1567  H5Dclose(ref_dset);
1568  string msg = "Cannot obtain the dimension name for the variable " + string(dt_inst_ptr->name);
1569  throw InternalErr(__FILE__,__LINE__,msg);
1570  }
1571 
1572  string objname_str = string(objname.begin(),objname.end());
1573 
1574  // Must trim the string delimter.
1575  string trim_objname = objname_str.substr(0,objnamelen);
1576 
1577  // Need to save the dimension names without the path
1578  dt_inst_ptr->dimnames.push_back(trim_objname.substr(trim_objname.find_last_of("/")+1));
1579 
1580  if(H5Dclose(ref_dset)<0) {
1581  throw InternalErr(__FILE__,__LINE__,"Cannot close the HDF5 dataset in the function obtain_dimnames().");
1582  }
1583  objname.clear();
1584  }// for (vector<Dimension *>::iterator ird is var->dims.begin()
1585  if(vlbuf.size()!= 0) {
1586 
1587  if ((aspace_id = H5Aget_space(attr_id)) < 0) {
1588  string msg = "Cannot close the HDF5 attribute space successfully for <DIMENSION_LIST> of the variable "+string(dt_inst_ptr->name);
1589  throw InternalErr(__FILE__,__LINE__,msg);
1590  }
1591 
1592  if (H5Dvlen_reclaim(amemtype_id,aspace_id,H5P_DEFAULT,(void*)&vlbuf[0])<0) {
1593  throw InternalErr(__FILE__,__LINE__,"Cannot reclaim the variable length memory in the function obtain_dimnames()");
1594  }
1595 
1596  H5Sclose(aspace_id);
1597 
1598  }
1599 
1600  H5Tclose(atype_id);
1601  H5Tclose(amemtype_id);
1602  H5Aclose(attr_id);
1603 
1604  }
1605 
1606  catch(...) {
1607 
1608  if(atype_id != -1)
1609  H5Tclose(atype_id);
1610 
1611  if(amemtype_id != -1)
1612  H5Tclose(amemtype_id);
1613 
1614  if(aspace_id != -1)
1615  H5Sclose(aspace_id);
1616 
1617  if(attr_id != -1)
1618  H5Aclose(attr_id);
1619 
1620  throw;
1621  }
1622 
1623  }
1624  return ;
1625 }
1626 
1627 void write_vlen_str_attrs(hid_t attr_id,hid_t ty_id, DSattr_t * attr_inst_ptr,D4Attribute *d4_attr, AttrTable* d2_attr,bool is_dap4){
1628 
1629  BESDEBUG("h5","attribute name " << attr_inst_ptr->name <<endl);
1630  BESDEBUG("h5","attribute size " <<attr_inst_ptr->need <<endl);
1631  BESDEBUG("h5","attribute type size " <<(int)(H5Tget_size(ty_id))<<endl);
1632 
1633  hid_t temp_space_id = H5Aget_space(attr_id);
1634  BESDEBUG("h5","attribute calculated size "<<(int)(H5Tget_size(ty_id)) *(int)(H5Sget_simple_extent_npoints(temp_space_id)) <<endl);
1635  if(temp_space_id <0) {
1636  H5Tclose(ty_id);
1637  H5Aclose(attr_id);
1638  throw InternalErr(__FILE__, __LINE__, "unable to read HDF5 attribute data");
1639  }
1640 
1641  vector<char> temp_buf;
1642  // Variable length string attribute values only store pointers of the actual string value.
1643  temp_buf.resize((size_t)attr_inst_ptr->need);
1644 
1645  if (H5Aread(attr_id, ty_id, &temp_buf[0]) < 0) {
1646  H5Tclose(ty_id);
1647  H5Aclose(attr_id);
1648  H5Sclose(temp_space_id);
1649  throw InternalErr(__FILE__, __LINE__, "unable to read HDF5 attribute data");
1650  }
1651 
1652  char *temp_bp;
1653  temp_bp = &temp_buf[0];
1654  char* onestring;
1655  for (unsigned int temp_i = 0; temp_i <attr_inst_ptr->nelmts; temp_i++) {
1656 
1657  // This line will assure that we get the real variable length string value.
1658  onestring =*(char **)temp_bp;
1659 
1660  // Change the C-style string to C++ STD string just for easy appending the attributes in DAP.
1661  if (onestring !=NULL) {
1662  string tempstring(onestring);
1663  if(true == is_dap4)
1664  d4_attr->add_value(tempstring);
1665  else
1666  d2_attr->append_attr(attr_inst_ptr->name,"String",tempstring);
1667  }
1668 
1669  temp_bp +=H5Tget_size(ty_id);
1670  }
1671  if (temp_buf.empty() != true) {
1672 
1673  // Reclaim any VL memory if necessary.
1674  herr_t ret_vlen_claim;
1675  ret_vlen_claim = H5Dvlen_reclaim(ty_id,temp_space_id,H5P_DEFAULT,&temp_buf[0]);
1676  if(ret_vlen_claim < 0){
1677  H5Tclose(ty_id);
1678  H5Aclose(attr_id);
1679  H5Sclose(temp_space_id);
1680  throw InternalErr(__FILE__, __LINE__, "Cannot reclaim the memory buffer of the HDF5 variable length string.");
1681  }
1682 
1683  temp_buf.clear();
1684  }
1685  H5Sclose(temp_space_id);
1686 }
A class for handling all types of array in HDF5 for the default option.
This class provides a way to map HDF5 byte to DAP Byte for the default option.
A class for mapping HDF5 32-bit float to DAP for the default option.
A class for mapping HDF5 64-bit float to DAP for the default option.
A class for HDF5 signed 16 bit integer type.
This class provides a way to map HDF5 32 bit integer to DAP Int32 for the default option.
This class provides a way to map HDF5 Int64 to DAP Int64 for the default option.
This class provides a way to map HDF5 int8 to DAP Int8 for the default option.
This class that translates HDF5 string into DAP string for the default option.
This class converts HDF5 compound type into DAP structure for the default option.
This class provides a way to map unsigned HDF5 16 bit integer to DAP UInt16 for the default option.
This class provides a way to map unsigned HDF5 32 bit integer to DAP UInt32.
This class provides a way to map HDF5 uint64 to DAP UInt64 for the default option.
This class generates DAP URL type for the default option.
void set_numdim(int ndims)
remembers number of dimensions of this array.
Definition: HDF5Array.cc:1450
void set_numelm(int nelms)
remembers number of elements in this array.
Definition: HDF5Array.cc:1454
void set_memneed(size_t need)
remembers memory size needed.
Definition: HDF5Array.cc:1446
string print_attr(hid_t type, int loc, void *sm_buf)
Definition: h5get.cc:642
bool check_h5str(hid_t h5type)
Definition: h5get.cc:621
hid_t get_fileid(const char *filename)
Definition: h5get.cc:392
string get_dap_type(hid_t type, bool is_dap4)
Definition: h5get.cc:272
void close_fileid(hid_t fid)
Definition: h5get.cc:414
void obtain_dimnames(hid_t dset, int ndims, DS_t *dt_inst_ptr)
Definition: h5get.cc:1494
hid_t get_attr_info(hid_t dset, int index, bool is_dap4, DSattr_t *attr_inst_ptr, bool *ignore_attr_ptr)
Definition: h5get.cc:83
const int DODS_MAX_RANK
Maximum number of dimensions in an array(default option only).
Definition: hdf5_handler.h:62
A structure for DDS generation.
Definition: hdf5_handler.h:70
char name[DODS_NAMELEN]
Name of HDF5 group or dataset.
Definition: hdf5_handler.h:72
A structure for DAS generation.
Definition: hdf5_handler.h:92
char name[DODS_NAMELEN]
Name of HDF5 group or dataset.
Definition: hdf5_handler.h:94
hsize_t nelmts
Number of elements.
Definition: hdf5_handler.h:102
hsize_t need
Memory space needed to hold nelmts type.
Definition: hdf5_handler.h:104