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 }
DSattr
A structure for DAS generation.
Definition: hdf5_handler.h:92
HDF5Float32.h
A class for mapping HDF5 32-bit float to DAP for the default option.
HDF5Byte.h
This class provides a way to map HDF5 byte to DAP Byte for the default option.
HDF5Float64
Definition: HDF5Float64.h:49
close_fileid
void close_fileid(hid_t fid)
Definition: h5get.cc:414
DS
A structure for DDS generation.
Definition: hdf5_handler.h:70
DS::name
char name[DODS_NAMELEN]
Name of HDF5 group or dataset.
Definition: hdf5_handler.h:72
HDF5UInt16.h
This class provides a way to map unsigned HDF5 16 bit integer to DAP UInt16 for the default option.
HDF5UInt32
Definition: HDF5UInt32.h:47
HDF5Float64.h
A class for mapping HDF5 64-bit float to DAP for the default option.
HDF5UInt32.h
This class provides a way to map unsigned HDF5 32 bit integer to DAP UInt32.
get_fileid
hid_t get_fileid(const char *filename)
Definition: h5get.cc:392
HDF5Array::set_numdim
void set_numdim(int ndims)
remembers number of dimensions of this array.
Definition: HDF5Array.cc:1450
DSattr::name
char name[DODS_NAMELEN]
Name of HDF5 group or dataset.
Definition: hdf5_handler.h:94
HDF5Array.h
A class for handling all types of array in HDF5 for the default option.
HDF5Int16.h
A class for HDF5 signed 16 bit integer type.
HDF5Int16
Definition: HDF5Int16.h:48
HDF5Str
Definition: HDF5Str.h:62
HDF5Byte
Definition: HDF5Byte.h:47
DSattr::nelmts
hsize_t nelmts
Number of elements.
Definition: hdf5_handler.h:102
libdap
Definition: BESDapFunctionResponseCache.h:35
HDF5Array::set_memneed
void set_memneed(size_t need)
remembers memory size needed.
Definition: HDF5Array.cc:1446
HDF5Int32.h
This class provides a way to map HDF5 32 bit integer to DAP Int32 for the default option.
check_h5str
bool check_h5str(hid_t h5type)
Definition: h5get.cc:621
HDF5UInt16
Definition: HDF5UInt16.h:47
DODS_MAX_RANK
const int DODS_MAX_RANK
Maximum number of dimensions in an array(default option only).
Definition: hdf5_handler.h:62
HDF5Array::set_numelm
void set_numelm(int nelms)
remembers number of elements in this array.
Definition: HDF5Array.cc:1454
DSattr::need
hsize_t need
Memory space needed to hold nelmts type.
Definition: hdf5_handler.h:104
obtain_dimnames
void obtain_dimnames(hid_t dset, int ndims, DS_t *dt_inst_ptr)
Definition: h5get.cc:1494
HDF5Structure
Definition: HDF5Structure.h:43
HDF5Structure.h
This class converts HDF5 compound type into DAP structure for the default option.
HDF5Float32
Definition: HDF5Float32.h:46
HDF5Str.h
This class that translates HDF5 string into DAP string for the default option.
HDF5Int64
Definition: HDF5Int64.h:47
get_dap_type
string get_dap_type(hid_t type, bool is_dap4)
Definition: h5get.cc:272
HDF5Int32
Definition: HDF5Int32.h:48
HDF5UInt64.h
This class provides a way to map HDF5 uint64 to DAP UInt64 for the default option.
h5get.h
Error
HDF5Array
Definition: HDF5Array.h:48
HDF5Url
Definition: HDF5Url.h:48
HDF5Int8.h
This class provides a way to map HDF5 int8 to DAP Int8 for the default option.
print_attr
string print_attr(hid_t type, int loc, void *sm_buf)
Definition: h5get.cc:642
HDF5Int8
Definition: HDF5Int8.h:47
HDF5Url.h
This class generates DAP URL type for the default option.
HDF5Int64.h
This class provides a way to map HDF5 Int64 to DAP Int64 for the default option.
HDF5UInt64
Definition: HDF5UInt64.h:47
get_attr_info
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