bes Updated for version 3.20.13
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
41using namespace std;
42using namespace libdap;
43
46
62void 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, nullptr, (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.data(), (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.data(), &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.data(), 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.data() << endl);
132
133 // This function will store the HDF5 group hierarchy into an DAP attribute.
134 add_group_structure_info(das, gname, oname.data(), true);
135
136 string full_path_name = string(gname) + string(oname.data()) + "/";
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 auto num_attr = (int)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.data() << endl);
203
204 // This function will store the HDF5 group hierarchy into an DAP attribute.
205 add_group_structure_info(das, gname, oname.data(), false);
206
207 string full_path_name = string(gname) + string(oname.data());
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 auto num_attr = (int)(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)
295void 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,nullptr,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.data()) < 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.data();
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 != nullptr) {
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.data());
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);
404 BESDEBUG("h5", "arttr_inst.need=" << attr_inst.need << endl);
405
406 hid_t memtype = H5Tget_native_type(ty_id, H5T_DIR_ASCEND);
407 // Read HDF5 attribute data.
408 if (H5Aread(attr_id, memtype, (void *) (value.data())) < 0)
409 throw InternalErr(__FILE__, __LINE__, "unable to read HDF5 attribute data");
410
411 H5Aclose(memtype);
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.data());
417 if (print_rep.c_str() != nullptr) {
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 auto 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.data();
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() != nullptr) {
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
482void 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
560void 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 vector<char>buf((val_size + 1) * sizeof(char));
584
585 // get link target name
586 if (H5Lget_val(pgroup, oname.c_str(), (void*) buf.data(), val_size + 1, H5P_DEFAULT) < 0)
587 throw InternalErr(__FILE__, __LINE__, "unable to get link value");
588 attr_softlink_ptr->append_attr(softlink_value_name, STRING, buf.data());
589}
590
604string get_hardlink(hid_t pgroup, const string & oname)
605{
606
607 BESDEBUG("h5", ">get_hardlink():" << oname << endl);
608
609 // Get the object info
610 H5O_info_t obj_info;
611 if (H5OGET_INFO(pgroup, &obj_info) < 0) {
612 throw InternalErr(__FILE__, __LINE__, "H5OGET_INFO() failed.");
613 }
614
615 // If the reference count is greater than 1,that means
616 // hard links are found. return the original object name this
617 // hard link points to.
618
619 if (obj_info.rc > 1) {
620 string objno;
621
622#if (H5_VERS_MAJOR == 1 && ((H5_VERS_MINOR == 12) || (H5_VERS_MINOR == 13)))
623 char *obj_tok_str = nullptr;
624 if(H5Otoken_to_str(pgroup, &(obj_info.token), &obj_tok_str) <0) {
625 throw InternalErr(__FILE__, __LINE__, "H5Otoken_to_str failed.");
626 }
627 objno.assign(obj_tok_str,obj_tok_str+strlen(obj_tok_str));
628 H5free_memory(obj_tok_str);
629#else
630 ostringstream oss;
631 oss << hex << obj_info.addr;
632 objno = oss.str();
633#endif
634
635
636 BESDEBUG("h5", "=get_hardlink() objno=" << objno << endl);
637
638 if (!paths.add(objno, oname)) {
639 return objno;
640 }
641 else {
642 return "";
643 }
644 }
645 else {
646 return "";
647 }
648
649}
650
660void read_comments(DAS & das, const string & varname, hid_t oid)
661{
662
663 // Obtain the comment size
664 int comment_size;
665 comment_size = (int) (H5Oget_comment(oid, nullptr, 0));
666 if (comment_size < 0) {
667 throw InternalErr(__FILE__, __LINE__, "Could not retrieve the comment size.");
668 }
669
670 if (comment_size > 0) {
671 vector<char> comment;
672 comment.resize(comment_size + 1);
673 if (H5Oget_comment(oid, comment.data(), comment_size + 1) < 0) {
674 throw InternalErr(__FILE__, __LINE__, "Could not retrieve the comment.");
675 }
676
677 // Insert this comment into the das table.
678 AttrTable *at = das.get_table(varname);
679 if (!at) at = das.add_table(varname, new AttrTable);
680 at->append_attr("HDF5_COMMENT", STRING, comment.data());
681
682 }
683}
684
704void add_group_structure_info(DAS & das, const char *gname, const char *oname, bool is_group)
705{
706
707 string h5_spec_char("/");
708 string dap_notion(".");
709 string::size_type pos = 1;
710
711 if (gname == nullptr) {
712 throw InternalErr(__FILE__, __LINE__, "The wrong HDF5 group name.");
713 }
714
715 auto full_path = string(gname);
716
717 // Change the HDF5 special character '/' with DAP notion '.'
718 // to make sure the group structure can be handled by DAP properly.
719 while ((pos = full_path.find(h5_spec_char, pos)) != string::npos) {
720 full_path.replace(pos, h5_spec_char.size(), dap_notion);
721 pos++;
722 }
723
724 // If the HDF5 file includes only the root group, replacing
725 // the "/" with the string "HDF5_ROOT_GROUP".
726 // Otherwise, replacing the first "/" with the string "HDF5_ROOT_GROUP.",
727 // (note the . after "HDF5_ROOT_GROUP." . Then cutting the last "/".
728
729 if (strncmp(gname, "/", strlen(gname)) == 0) {
730 full_path.replace(0, 1, "HDF5_ROOT_GROUP");
731 }
732 else {
733 full_path.replace(0, 1, "HDF5_ROOT_GROUP.");
734 full_path = full_path.substr(0, full_path.length() - 1);
735 }
736
737 BESDEBUG("h5", full_path << endl);
738 // TODO: Not sure if we need to create a table for each group. KY 2015-07-08
739 AttrTable *at = das.get_table(full_path);
740 if (at == nullptr) {
741 throw InternalErr(__FILE__, __LINE__,
742 "Failed to add group structure information for " + full_path + " attribute table."
743 + "This happens when a group name has . character.");
744 }
745
746 // group will be mapped to a container
747 if (is_group) {
748 at->append_container(oname);
749 }
750 else {
751 at->append_attr("Dataset", "String", oname);
752 }
753}
754
bool add(const std::string &id, const std::string &name)
std::string get_name(const std::string &id)
string get_hardlink(hid_t pgroup, const string &oname)
Definition: h5das.cc:604
void depth_first(hid_t pid, const char *gname, DAS &das)
Definition: h5das.cc:62
HDF5PathFinder paths
A variable for remembering visited paths to break cyclic HDF5 groups.
Definition: h5das.cc:45
void find_gloattr(hid_t file, DAS &das)
Definition: h5das.cc:482
void read_objects(DAS &das, const string &varname, hid_t oid, int num_attr)
Definition: h5das.cc:295
void read_comments(DAS &das, const string &varname, hid_t oid)
Definition: h5das.cc:660
string print_attr(hid_t type, int loc, void *sm_buf)
Definition: h5get.cc:868
string get_dap_type(hid_t type, bool is_dap4)
Definition: h5get.cc:292
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:90
The main header of the HDF5 OPeNDAP handler.
const int DODS_NAMELEN
Maximum length of variable or attribute name(default option only).
Definition: hdf5_handler.h:65
const std::string HDF5_OBJ_FULLPATH
The special DAS attribute name for HDF5 path information from the top(root) group.
Definition: hdf5_handler.h:67
A structure for DAS generation.
Definition: hdf5_handler.h:96
char name[DODS_NAMELEN]
Name of HDF5 group or dataset.
Definition: hdf5_handler.h:98
int ndims
Number of dimensions.
Definition: hdf5_handler.h:102
hsize_t nelmts
Number of elements.
Definition: hdf5_handler.h:106
hsize_t need
Memory space needed to hold nelmts type.
Definition: hdf5_handler.h:108