bes  Updated for version 3.20.6
h5das.cc
Go to the documentation of this file.
1 // This file is part of hdf5_handler a HDF5 file handler for the OPeNDAP
2 // data server.
3 
4 // Copyright (c) 2007-2016 The HDF Group, Inc. and OPeNDAP, Inc.
5 //
6 // This is free software; you can redistribute it and/or modify it under the
7 // terms of the GNU Lesser General Public License as published by the Free
8 // Software Foundation; either version 2.1 of the License, or (at your
9 // option) any later version.
10 //
11 // This software is distributed in the hope that it will be useful, but
12 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 // License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 //
20 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
21 // You can contact The HDF Group, Inc. at 1800 South Oak Street,
22 // Suite 203, Champaign, IL 61820
23 
38 #include "hdf5_handler.h"
39 #include <BESDebug.h>
40 
41 using namespace std;
42 using namespace libdap;
43 
46 
62 void depth_first(hid_t pid, const char *gname, DAS & das)
63 {
65  int slinkindex = 0;
66 
67  // Although HDF5 comments are rarely used, we still keep this
68  // function.
69  read_comments(das, gname, pid);
70 
71  H5G_info_t g_info;
72  hsize_t nelems;
73 
74  if (H5Gget_info(pid, &g_info) < 0) {
75  string msg = "h5_das handler: unable to obtain the HDF5 group info. for ";
76  msg += gname;
77  throw InternalErr(__FILE__, __LINE__, msg);
78  }
79  nelems = g_info.nlinks;
80 
81  ssize_t oname_size = 0;
82  for (hsize_t i = 0; i < nelems; i++) {
83 
84  // Query the length of object name.
85  oname_size = H5Lget_name_by_idx(pid, ".", H5_INDEX_NAME, H5_ITER_NATIVE, i, NULL, (size_t) DODS_NAMELEN,
86  H5P_DEFAULT);
87 
88  if (oname_size <= 0) {
89  string msg = "hdf5 object name error from: ";
90  msg += gname;
91  throw InternalErr(__FILE__, __LINE__, msg);
92  }
93  // Obtain the name of the object.
94  vector<char> oname(oname_size + 1);
95  if (H5Lget_name_by_idx(pid, ".", H5_INDEX_NAME, H5_ITER_NATIVE, i, &oname[0], (size_t) (oname_size + 1),
96  H5P_DEFAULT) < 0) {
97  string msg = "hdf5 object name error from: ";
98  msg += gname;
99  throw InternalErr(__FILE__, __LINE__, msg);
100  }
101 
102  // Check if it is the hard link or the soft link
103  H5L_info_t linfo;
104  if (H5Lget_info(pid, &oname[0], &linfo, H5P_DEFAULT) < 0) {
105  string msg = "hdf5 link name error from: ";
106  msg += gname;
107  throw InternalErr(__FILE__, __LINE__, msg);
108  }
109 
110  // This is the soft link.
111  if (linfo.type == H5L_TYPE_SOFT) {
112  slinkindex++;
113  size_t val_size = linfo.u.val_size;
114  get_softlink(das, pid, gname, &oname[0], slinkindex, val_size);
115  continue;
116  }
117 
118  // Obtain the object type
119  H5O_info_t oinfo;
120  if (H5Oget_info_by_idx(pid, ".", H5_INDEX_NAME, H5_ITER_NATIVE, i, &oinfo, H5P_DEFAULT) < 0) {
121  string msg = "Cannot obtain the object info ";
122  msg += gname;
123  throw InternalErr(__FILE__, __LINE__, msg);
124  }
125  H5O_type_t obj_type = oinfo.type;
126 
127  switch (obj_type) {
128 
129  case H5O_TYPE_GROUP: {
130 
131  BESDEBUG("h5", "=depth_first():H5G_GROUP " << &oname[0] << endl);
132 
133  // This function will store the HDF5 group hierarchy into an DAP attribute.
134  add_group_structure_info(das, gname, &oname[0], true);
135 
136  string full_path_name = string(gname) + string(&oname[0]) + "/";
137 
138  hid_t cgroup = H5Gopen(pid, full_path_name.c_str(), H5P_DEFAULT);
139  if (cgroup < 0) {
140  string msg = "opening hdf5 group failed for ";
141  msg += full_path_name;
142  throw InternalErr(__FILE__, __LINE__, msg);
143  }
144 
145  // Get the object info
146  H5O_info_t obj_info;
147  if (H5Oget_info(cgroup, &obj_info) < 0) {
148  H5Gclose(cgroup);
149  string msg = "Obtaining the hdf5 group info. failed for ";
150  msg += full_path_name;
151  throw InternalErr(__FILE__, __LINE__, msg);
152  }
153 
154  // Obtain the number of attributes
155  int num_attr = obj_info.num_attrs;
156  if (num_attr < 0) {
157  H5Gclose(cgroup);
158  string msg = "Fail to get the number of attributes for group ";
159  msg += full_path_name;
160  throw InternalErr(__FILE__, __LINE__, msg);
161  }
162 
163  // Read all attributes in this group and map to DAS.
164  try {
165  read_objects(das, full_path_name.c_str(), cgroup, num_attr);
166  }
167  catch (...) {
168  H5Gclose(cgroup);
169  throw;
170  }
171 
172  // Check if this group has been visited by using the hardlink
173  string oid = get_hardlink(cgroup, full_path_name.c_str());
174 
175  // Break the cyclic loop created by hard links.
176  if (oid.empty()) { // The group has never been visited, go to the next level.
177  depth_first(cgroup, full_path_name.c_str(), das);
178  }
179  else {
180 
181  // This group has been visited.
182  // Add the attribute table with the attribute name as HDF5_HARDLINK.
183  // The attribute value is the name of the group when it is first visited.
184  AttrTable *at = das.get_table(full_path_name);
185  if (!at) {
186  at = das.add_table(full_path_name, new AttrTable);
187  }
188 
189  // Note that "paths" is a global object to find the visited path.
190  // It is defined at the beginning of this source code file.
191  at->append_attr("HDF5_HARDLINK", STRING, paths.get_name(oid));
192  }
193 
194  if (H5Gclose(cgroup) < 0) {
195  throw InternalErr(__FILE__, __LINE__, "H5Gclose() failed.");
196  }
197  break;
198  } // case H5G_GROUP
199 
200  case H5O_TYPE_DATASET: {
201 
202  BESDEBUG("h5", "=depth_first():H5G_DATASET " << &oname[0] << endl);
203 
204  // This function will store the HDF5 group hierarchy into an DAP attribute.
205  add_group_structure_info(das, gname, &oname[0], false);
206 
207  string full_path_name = string(gname) + string(&oname[0]);
208  hid_t dset = -1;
209 
210  // Open the dataset
211  if ((dset = H5Dopen(pid, full_path_name.c_str(), H5P_DEFAULT)) < 0) {
212  string msg = "unable to open the hdf5 dataset of the group ";
213  msg += gname;
214  throw InternalErr(__FILE__, __LINE__, msg);
215  }
216 
217  // Get the object info
218  H5O_info_t obj_info;
219  if (H5Oget_info(dset, &obj_info) < 0) {
220  H5Dclose(dset);
221  string msg = "Obtaining the info. failed for the dataset ";
222  msg += full_path_name;
223  throw InternalErr(__FILE__, __LINE__, msg);
224  }
225 
226  // Obtain the number of attributes
227  int num_attr = obj_info.num_attrs;
228  if (num_attr < 0) {
229  H5Dclose(dset);
230  string msg = "Fail to get the number of attributes for dataset ";
231  msg += full_path_name;
232  throw InternalErr(__FILE__, __LINE__, msg);
233  }
234 
235  // Read all attributes in this dataset and map to DAS.
236  try {
237  read_objects(das, full_path_name, dset, num_attr);
238  }
239  catch (...) {
240  H5Dclose(dset);
241  throw;
242  }
243 
244  string oid = get_hardlink(dset, full_path_name);
245 
246  // Break the cyclic loop created by hard links
247 
248  // If this HDF5 dataset has been visited,
249  // Add the DAS table with the attribute name as HDF5_HARDLINK.
250  // The attribute value is the name of the HDF5 dataset when it is first visited.
251  if (!oid.empty()) {
252  // Add attribute table with HARDLINK
253  AttrTable *at = das.get_table(full_path_name);
254  if (!at) {
255  at = das.add_table(full_path_name, new AttrTable);
256  }
257 
258  // Note that "paths" is a global object to find the visited path.
259  // It is defined at the beginning of this source code file.
260  at->append_attr("HDF5_HARDLINK", STRING, paths.get_name(oid));
261  }
262 
263  if (H5Dclose(dset) < 0) {
264  throw InternalErr(__FILE__, __LINE__, "Could not close the dataset.");
265  }
266  break;
267  } // case H5G_DATASET
268 
269  case H5O_TYPE_NAMED_DATATYPE:
270  // ignore the named datatype
271  break;
272 
273  default:
274  break;
275  }
276  } // end for
277 
278  BESDEBUG("h5", "<depth_first():" << gname << endl);
279 }
280 
281 
283 // \fn read_objects(DAS & das, const string & varname, hid_t oid, int num_attr)
295 void read_objects(DAS & das, const string & varname, hid_t oid, int num_attr)
296 {
297 
298  BESDEBUG("h5", ">read_objects():" << "varname=" << varname << " id=" << oid << endl);
299 
300  // Prepare a variable for full path attribute.
301  string hdf5_path = HDF5_OBJ_FULLPATH;
302 
303  // Obtain the DAS table of which the name is the variable name.
304  // If not finding the table, add a table of which the name is the variable name.
305  AttrTable *attr_table_ptr = das.get_table(varname);
306  if (!attr_table_ptr) {
307  BESDEBUG("h5", "=read_objects(): adding a table with name " << varname << endl);
308  attr_table_ptr = das.add_table(varname, new AttrTable);
309  }
310 
311  // Add a DAP attribute that stores the HDF5 absolute path
312  attr_table_ptr->append_attr(hdf5_path.c_str(), STRING, varname);
313 
314  // Check the number of attributes in this HDF5 object and
315  // put HDF5 attribute information into the DAS table.
316  string print_rep;
317  vector<char> temp_buf;
318 
319  bool ignore_attr = false;
320  hid_t attr_id = -1;
321  for (int j = 0; j < num_attr; j++) {
322 
323  // Obtain attribute information.
324  DSattr_t attr_inst;
325 
326  // Ignore the attributes of which the HDF5 datatype
327  // cannot be mapped to DAP2. The ignored attribute datatypes can be found
328  // at function get_attr_info in h5get.cc.
329  attr_id = get_attr_info(oid, j, false, &attr_inst, &ignore_attr);
330  if (true == ignore_attr) {
331  H5Aclose(attr_id);
332  continue;
333  }
334 
335  // Since HDF5 attribute may be in string datatype, it must be dealt
336  // properly. Get data type.
337  hid_t ty_id = H5Aget_type(attr_id);
338  string dap_type = get_dap_type(ty_id, false);
339  string attr_name = attr_inst.name;
340 
341  // We have to handle variable length string differently.
342  if (H5Tis_variable_str(ty_id)) {
343 
344  write_vlen_str_attrs(attr_id,ty_id,&attr_inst,NULL,attr_table_ptr,false);
345 
346 #if 0
347  BESDEBUG("h5", "attribute name " << attr_name <<endl);
348  BESDEBUG("h5", "attribute size " <<attr_inst.need <<endl);
349  BESDEBUG("h5", "attribute type size " <<(int)(H5Tget_size(ty_id))<<endl);
350 
351  hid_t temp_space_id = H5Aget_space(attr_id);
352  BESDEBUG("h5",
353  "attribute calculated size "<<(int)(H5Tget_size(ty_id)) *(int)(H5Sget_simple_extent_npoints(temp_space_id)) <<endl);
354  if (temp_space_id < 0) {
355  H5Tclose(ty_id);
356  H5Aclose(attr_id);
357  throw InternalErr(__FILE__, __LINE__, "unable to read HDF5 attribute data");
358 
359  }
360 
361  // Variable length string attribute values only store pointers of the actual string value.
362  temp_buf.resize((size_t) attr_inst.need);
363 
364  if (H5Aread(attr_id, ty_id, &temp_buf[0]) < 0) {
365  H5Sclose(temp_space_id);
366  H5Tclose(ty_id);
367  H5Aclose(attr_id);
368  throw InternalErr(__FILE__, __LINE__, "unable to read HDF5 attribute data");
369  }
370 
371  char *temp_bp;
372  temp_bp = &temp_buf[0];
373  char* onestring;
374  for (unsigned int temp_i = 0; temp_i < attr_inst.nelmts; temp_i++) {
375 
376  // This line will assure that we get the real variable length string value.
377  onestring = *(char **) temp_bp;
378 
379  // Change the C-style string to C++ STD string just for easy appending the attributes in DAP.
380  if (onestring != NULL) {
381  string tempstring(onestring);
382  attr_table_ptr->append_attr(attr_name, dap_type, tempstring);
383  }
384 
385  // going to the next value.
386  temp_bp += H5Tget_size(ty_id);
387  }
388  if (temp_buf.empty() != true) {
389  // Reclaim any VL memory if necessary.
390  herr_t ret_vlen_claim;
391  ret_vlen_claim = H5Dvlen_reclaim(ty_id, temp_space_id, H5P_DEFAULT, &temp_buf[0]);
392  if(ret_vlen_claim < 0) {
393  H5Sclose(temp_space_id);
394  throw InternalErr(__FILE__, __LINE__, "Cannot reclaim the memory buffer of the HDF5 variable length string.");
395  }
396  temp_buf.clear();
397  }
398  H5Sclose(temp_space_id);
399 #endif
400  }
401  else {
402  vector<char> value;
403  value.resize(attr_inst.need + sizeof(char));
404  BESDEBUG("h5", "arttr_inst.need=" << attr_inst.need << endl);
405 
406  // Read HDF5 attribute data.
407  if (H5Aread(attr_id, ty_id, (void *) (&value[0])) < 0) {
408  // value is deleted in the catch block below so
409  // shouldn't be deleted here. pwest Mar 18, 2009
410  throw InternalErr(__FILE__, __LINE__, "unable to read HDF5 attribute data");
411  }
412 
413  // For scalar data, just read data once.
414  if (attr_inst.ndims == 0) {
415  for (int loc = 0; loc < (int) attr_inst.nelmts; loc++) {
416  print_rep = print_attr(ty_id, loc, &value[0]);
417  if (print_rep.c_str() != NULL) {
418  attr_table_ptr->append_attr(attr_name, dap_type, print_rep.c_str());
419  }
420  }
421 
422  }
423  else {
424  // If the hdf5 data type is HDF5 string or number of dimension is positive;
425  // handle this differently.
426  BESDEBUG("h5", "=read_objects(): ndims=" << (int) attr_inst. ndims << endl);
427 
428  // Get the attribute datatype size
429  int elesize = (int) H5Tget_size(ty_id);
430  if (elesize == 0) {
431  BESDEBUG("h5", "=read_objects(): elesize=0" << endl);
432  H5Tclose(ty_id);
433  H5Aclose(attr_id);
434  throw InternalErr(__FILE__, __LINE__, "unable to get attibute size");
435  }
436 
437  // Due to the implementation of print_attr, the attribute value will be
438  // written one by one.
439  char *tempvalue = &value[0];
440 
441  // Write this value. the "loc" can always be set to 0 since
442  // tempvalue will be moved to the next value.
443  for (hsize_t temp_index = 0; temp_index < attr_inst.nelmts; temp_index++) {
444  print_rep = print_attr(ty_id, 0/*loc*/, tempvalue);
445  if (print_rep.c_str() != NULL) {
446  attr_table_ptr->append_attr(attr_name, dap_type, print_rep.c_str());
447  tempvalue = tempvalue + elesize;
448 
449  BESDEBUG("h5", "tempvalue=" << tempvalue << "elesize=" << elesize << endl);
450 
451  }
452  else {
453  H5Tclose(ty_id);
454  H5Aclose(attr_id);
455  throw InternalErr(__FILE__, __LINE__, "unable to convert attibute value to DAP");
456  }
457  }
458  } // end if
459  }
460  if (H5Tclose(ty_id) < 0) {
461  H5Aclose(attr_id);
462  throw InternalErr(__FILE__, __LINE__, "unable to close HDF5 type id");
463  }
464  if (H5Aclose(attr_id) < 0) {
465  throw InternalErr(__FILE__, __LINE__, "unable to close attibute id");
466  }
467  } // end for
468  BESDEBUG("h5", "<read_objects()" << endl);
469 }
470 
482 void find_gloattr(hid_t file, DAS & das)
483 {
484  BESDEBUG("h5", ">find_gloattr()" << endl);
485 
486  hid_t root = H5Gopen(file, "/", H5P_DEFAULT);
487  try {
488  if (root < 0) throw InternalErr(__FILE__, __LINE__, "unable to open the HDF5 root group");
489 
490  // In the default option of the HDF5 handler, the
491  // HDF5 file structure(group hierarchy) will be mapped to
492  // a DAP attribute HDF5_ROOT_GROUP. In a sense, this created
493  // attribute can be treated as an HDF5 attribute under the root group,
494  // so to say, a global attribute.
495  das.add_table("HDF5_ROOT_GROUP", new AttrTable);
496 
497  // Since the root group is the first HDF5 object to visit(in HDF5RequestHandler.cc, find_gloattr()
498  // is before the depth_first()), it will always be not visited. However, to find the cyclic groups
499  // to root, we still need to add the object name to the global variable name list "paths" defined at
500  // the beginning of the h5das.cc file.
501  get_hardlink(root, "/");
502 
503  // Obtain the number of "real" attributes of the root group.
504  int num_attrs;
505  H5O_info_t obj_info;
506  if (H5Oget_info(root, &obj_info) < 0) {
507  H5Gclose(root);
508  string msg = "Obtaining the info. failed for the root group ";
509  throw InternalErr(__FILE__, __LINE__, msg);
510  }
511 
512  // Obtain the number of attributes
513  num_attrs = obj_info.num_attrs;
514  if (num_attrs < 0) {
515  H5Gclose(root);
516  throw InternalErr(__FILE__, __LINE__, "unable to get the number of attributes for the HDF root group ");
517 
518  }
519  if (num_attrs == 0) {
520  if (H5Gclose(root) < 0) {
521  throw InternalErr(__FILE__, __LINE__, "Could not close the group.");
522  }
523  BESDEBUG("h5", "<find_gloattr():no attributes" << endl);
524  return;
525  }
526 
527  // Map the HDF5 root attributes to DAP and save it in a DAS table "H5_GLOBAL".
528  // In theory, we can just "/" as the table name. To help clients better understand,
529  // we use "H5_GLOBAL" which is a more meaningful name.
530  read_objects(das, "H5_GLOBAL", root, num_attrs);
531 
532  BESDEBUG("h5", "=find_gloattr(): H5Gclose()" << endl);
533  if (H5Gclose(root) < 0) {
534  throw InternalErr(__FILE__, __LINE__, "Could not close the group.");
535  }
536  BESDEBUG("h5", "<find_gloattr()" << endl);
537  }
538  catch (...) {
539  if (H5Gclose(root) < 0) {
540  throw InternalErr(__FILE__, __LINE__, "Could not close the group.");
541  }
542  throw;
543  }
544 }
545 
560 void get_softlink(DAS & das, hid_t pgroup, const char *gname, const string & oname, int index, size_t val_size)
561 {
562  BESDEBUG("h5", ">get_softlink():" << oname << endl);
563 
564  ostringstream oss;
565  oss << string("HDF5_SOFTLINK");
566  oss << "_";
567  oss << index;
568  string temp_varname = oss.str();
569 
570 
571  BESDEBUG("h5", "=get_softlink():" << temp_varname << endl);
572  AttrTable *attr_table_ptr = das.get_table(gname);
573  if (!attr_table_ptr) attr_table_ptr = das.add_table(gname, new AttrTable);
574 
575  AttrTable *attr_softlink_ptr;
576  attr_softlink_ptr = attr_table_ptr->append_container(temp_varname);
577 
578  string softlink_name = "linkname";
579  attr_softlink_ptr->append_attr(softlink_name, STRING, oname);
580  string softlink_value_name = "LINKTARGET";
581 
582  // Get the link target information. We always return the link value in a string format.
583 
584  char *buf = 0;
585  try {
586  buf = new char[(val_size + 1) * sizeof(char)];
587  // get link target name
588  if (H5Lget_val(pgroup, oname.c_str(), (void*) buf, val_size + 1, H5P_DEFAULT) < 0) {
589  delete[] buf;
590  throw InternalErr(__FILE__, __LINE__, "unable to get link value");
591  }
592  attr_softlink_ptr->append_attr(softlink_value_name, STRING, buf);
593  delete[] buf;
594  }
595  catch (...) {
596  delete[] buf;
597  throw;
598  }
599 }
600 
614 string get_hardlink(hid_t pgroup, const string & oname)
615 {
616 
617  BESDEBUG("h5", ">get_hardlink():" << oname << endl);
618 
619  // Get the object info
620  H5O_info_t obj_info;
621  if (H5Oget_info(pgroup, &obj_info) < 0) {
622  throw InternalErr(__FILE__, __LINE__, "H5Oget_info() failed.");
623  }
624 
625  // If the reference count is greater than 1,that means
626  // hard links are found. return the original object name this
627  // hard link points to.
628 
629  if (obj_info.rc > 1) {
630 
631  ostringstream oss;
632  oss << hex << obj_info.addr;
633  string objno = oss.str();
634 
635  BESDEBUG("h5", "=get_hardlink() objno=" << objno << endl);
636 
637  if (!paths.add(objno, oname)) {
638  return objno;
639  }
640  else {
641  return "";
642  }
643  }
644  else {
645  return "";
646  }
647 
648 }
649 
659 void read_comments(DAS & das, const string & varname, hid_t oid)
660 {
661 
662  // Obtain the comment size
663  int comment_size;
664  comment_size = (int) (H5Oget_comment(oid, NULL, 0));
665  if (comment_size < 0) {
666  throw InternalErr(__FILE__, __LINE__, "Could not retrieve the comment size.");
667  }
668 
669  if (comment_size > 0) {
670  vector<char> comment;
671  comment.resize(comment_size + 1);
672  if (H5Oget_comment(oid, &comment[0], comment_size + 1) < 0) {
673  throw InternalErr(__FILE__, __LINE__, "Could not retrieve the comment.");
674  }
675 
676  // Insert this comment into the das table.
677  AttrTable *at = das.get_table(varname);
678  if (!at) at = das.add_table(varname, new AttrTable);
679  at->append_attr("HDF5_COMMENT", STRING, &comment[0]);
680 
681  }
682 }
683 
703 void add_group_structure_info(DAS & das, const char *gname, char *oname, bool is_group)
704 {
705 
706  string h5_spec_char("/");
707  string dap_notion(".");
708  string::size_type pos = 1;
709 
710  if (gname == NULL) {
711  throw InternalErr(__FILE__, __LINE__, "The wrong HDF5 group name.");
712  }
713 
714  string full_path = string(gname);
715 
716  // Change the HDF5 special character '/' with DAP notion '.'
717  // to make sure the group structure can be handled by DAP properly.
718  while ((pos = full_path.find(h5_spec_char, pos)) != string::npos) {
719  full_path.replace(pos, h5_spec_char.size(), dap_notion);
720  pos++;
721  }
722 
723  // If the HDF5 file includes only the root group, replacing
724  // the "/" with the string "HDF5_ROOT_GROUP".
725  // Otherwise, replacing the first "/" with the string "HDF5_ROOT_GROUP.",
726  // (note the . after "HDF5_ROOT_GROUP." . Then cutting the last "/".
727 
728  if (strncmp(gname, "/", strlen(gname)) == 0) {
729  full_path.replace(0, 1, "HDF5_ROOT_GROUP");
730  }
731  else {
732  full_path.replace(0, 1, "HDF5_ROOT_GROUP.");
733  full_path = full_path.substr(0, full_path.length() - 1);
734  }
735 
736  BESDEBUG("h5", full_path << endl);
737  // TODO: Not sure if we need to create a table for each group. KY 2015-07-08
738  AttrTable *at = das.get_table(full_path);
739  if (at == NULL) {
740  throw InternalErr(__FILE__, __LINE__,
741  "Failed to add group structure information for " + full_path + " attribute table."
742  + "This happens when a group name has . character.");
743  }
744 
745  // group will be mapped to a container
746  if (is_group) {
747  at->append_container(oname);
748  }
749  else {
750  at->append_attr("Dataset", "String", oname);
751  }
752 }
753 
DSattr
A structure for DAS generation.
Definition: hdf5_handler.h:92
DODS_NAMELEN
const int DODS_NAMELEN
Maximum length of variable or attribute name(default option only).
Definition: hdf5_handler.h:64
DSattr::ndims
int ndims
Number of dimensions.
Definition: hdf5_handler.h:98
read_comments
void read_comments(DAS &das, const string &varname, hid_t oid)
Definition: h5das.cc:659
add_group_structure_info
void add_group_structure_info(DAS &das, const char *gname, char *oname, bool is_group)
Definition: h5das.cc:703
DSattr::name
char name[DODS_NAMELEN]
Name of HDF5 group or dataset.
Definition: hdf5_handler.h:94
find_gloattr
void find_gloattr(hid_t file, DAS &das)
Definition: h5das.cc:482
HDF5_OBJ_FULLPATH
const std::string HDF5_OBJ_FULLPATH
The special DAS attribute name for HDF5 path information from the top(root) group.
Definition: hdf5_handler.h:66
DSattr::nelmts
hsize_t nelmts
Number of elements.
Definition: hdf5_handler.h:102
read_objects
void read_objects(DAS &das, const string &varname, hid_t oid, int num_attr)
Definition: h5das.cc:295
libdap
Definition: BESDapFunctionResponseCache.h:35
HDF5PathFinder
Definition: HDF5PathFinder.h:42
DSattr::need
hsize_t need
Memory space needed to hold nelmts type.
Definition: hdf5_handler.h:104
paths
HDF5PathFinder paths
A variable for remembering visited paths to break cyclic HDF5 groups.
Definition: h5das.cc:45
get_hardlink
string get_hardlink(hid_t pgroup, const string &oname)
Definition: h5das.cc:614
HDF5PathFinder::add
bool add(std::string id, const std::string name)
Definition: HDF5PathFinder.cc:50
get_dap_type
string get_dap_type(hid_t type, bool is_dap4)
Definition: h5get.cc:272
HDF5PathFinder::get_name
std::string get_name(std::string id)
Definition: HDF5PathFinder.cc:74
depth_first
void depth_first(hid_t pid, const char *gname, DAS &das)
Definition: h5das.cc:62
print_attr
string print_attr(hid_t type, int loc, void *sm_buf)
Definition: h5get.cc:642
hdf5_handler.h
The main header of the HDF5 OPeNDAP handler.
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