OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
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-2013 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 1901 South First Street,
22 // Suite C-2, Champaign, IL 61820
23 
38 #include "hdf5_handler.h"
39 
40 
43 
44 
60 void depth_first(hid_t pid, const char *gname, DAS & das)
61 {
63  int slinkindex = 0;
64 
65  // Although HDF5 comments are rarely used, we still keep this
66  // function.
67  read_comments(das, gname, pid);
68 
69  H5G_info_t g_info;
70  hsize_t nelems;
71 
72  if (H5Gget_info(pid,&g_info) <0) {
73  string msg =
74  "h5_das handler: unable to obtain the HDF5 group info. for ";
75  msg += gname;
76  throw InternalErr(__FILE__, __LINE__, msg);
77  }
78  nelems = g_info.nlinks;
79 
80  ssize_t oname_size;
81  for (hsize_t i = 0; i < nelems; i++) {
82 
83  // Query the length of object name.
84  oname_size =
85  H5Lget_name_by_idx(pid,".",H5_INDEX_NAME,H5_ITER_NATIVE,i,NULL,
86  (size_t)DODS_NAMELEN, 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],
96  (size_t)(oname_size+1), 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,
121  i, &oinfo, H5P_DEFAULT)<0) {
122  string msg = "Cannot obtain the object info ";
123  msg += gname;
124  throw InternalErr(__FILE__, __LINE__, msg);
125  }
126  H5O_type_t obj_type = oinfo.type;
127 
128  switch (obj_type) {
129 
130  case H5O_TYPE_GROUP: {
131 
132  DBG(cerr << "=depth_first():H5G_GROUP " << &oname[0] << endl);
133 
134  // This function will store the HDF5 group hierarchy into an DAP attribute.
135  add_group_structure_info(das, gname, &oname[0], true);
136 
137  string full_path_name = string(gname) + string(&oname[0]) + "/";
138 
139  hid_t cgroup = H5Gopen(pid, full_path_name.c_str(),H5P_DEFAULT);
140  if (cgroup < 0) {
141  string msg = "opening hdf5 group failed for ";
142  msg += full_path_name;
143  throw InternalErr(__FILE__, __LINE__, msg);
144  }
145 
146  int num_attr;
147 
148  // Get the object info
149  H5O_info_t obj_info;
150  if (H5Oget_info(cgroup, &obj_info) <0) {
151  H5Gclose(cgroup);
152  string msg = "Obtaining the hdf5 group info. failed for ";
153  msg += full_path_name;
154  throw InternalErr(__FILE__, __LINE__, msg);
155  }
156 
157  // Obtain the number of attributes
158  num_attr = obj_info.num_attrs;
159  if (num_attr < 0 ) {
160  H5Gclose(cgroup);
161  string msg = "Fail to get the number of attributes for group ";
162  msg += full_path_name;
163  throw InternalErr(__FILE__, __LINE__,msg);
164  }
165 
166  // Read all attributes in this group and map to DAS.
167  read_objects(das, full_path_name.c_str(), cgroup, num_attr);
168 
169  // Check if this group has been visited by using the hardlink
170  string oid = get_hardlink(cgroup, full_path_name.c_str());
171 
172  // Break the cyclic loop created by hard links.
173  if (oid.empty()) {// The group has never been visited, go to the next level.
174  depth_first(cgroup, full_path_name.c_str(), das);
175  }
176  else {
177 
178  // This group has been visited.
179  // Add the attribute table with the attribute name as HDF5_HARDLINK.
180  // The attribute value is the name of the group when it is first visited.
181  AttrTable *at = das.get_table(full_path_name);
182  if(!at){
183  at = das.add_table(full_path_name, new AttrTable);
184  }
185 
186  // Note that "paths" is a global object to find the visited path.
187  // It is defined at the beginning of this source code file.
188  at->append_attr("HDF5_HARDLINK", STRING, paths.get_name(oid));
189  }
190 
191  if (H5Gclose(cgroup) < 0) {
192  throw InternalErr(__FILE__, __LINE__, "H5Gclose() failed.");
193  }
194  break;
195  } // case H5G_GROUP
196 
197  case H5O_TYPE_DATASET: {
198 
199  DBG(cerr << "=depth_first():H5G_DATASET " << &oname[0] <<
200  endl);
201 
202  // This function will store the HDF5 group hierarchy into an DAP attribute.
203  add_group_structure_info(das, gname, &oname[0], false);
204 
205  string full_path_name = string(gname) + string(&oname[0]);
206  hid_t dset;
207 
208  // Open the dataset
209  if ((dset = H5Dopen(pid, full_path_name.c_str(),H5P_DEFAULT)) < 0) {
210  string msg = "unable to open the hdf5 dataset of the group ";
211  msg += gname;
212  throw InternalErr(__FILE__, __LINE__, msg);
213  }
214 
215  // Get the object info
216  int num_attr;
217  H5O_info_t obj_info;
218  if (H5Oget_info(dset, &obj_info) <0) {
219  H5Dclose(dset);
220  string msg = "Obtaining the info. failed for the dataset ";
221  msg += full_path_name;
222  throw InternalErr(__FILE__, __LINE__, msg);
223  }
224 
225  // Obtain the number of attributes
226  num_attr = obj_info.num_attrs;
227  if (num_attr < 0 ) {
228  H5Dclose(dset);
229  string msg = "Fail to get the number of attributes for dataset ";
230  msg += full_path_name;
231  throw InternalErr(__FILE__, __LINE__,msg);
232  }
233 
234  // Read all attributes in this dataset and map to DAS.
235  read_objects(das, full_path_name, dset, num_attr);
236 
237  string oid = get_hardlink(dset, full_path_name);
238 
239  // Break the cyclic loop created by hard links
240 
241  // If this HDF5 dataset has been visited,
242  // Add the DAS table with the attribute name as HDF5_HARDLINK.
243  // The attribute value is the name of the HDF5 dataset when it is first visited.
244  if (!oid.empty()) {
245  // Add attribute table with HARDLINK
246  AttrTable *at = das.get_table(full_path_name);
247  if(!at) {
248  at = das.add_table(full_path_name, new AttrTable);
249  }
250 
251  // Note that "paths" is a global object to find the visited path.
252  // It is defined at the beginning of this source code file.
253  at->append_attr("HDF5_HARDLINK", STRING, paths.get_name(oid));
254  }
255 
256  if (H5Dclose(dset) < 0) {
257  throw InternalErr(__FILE__, __LINE__, "Could not close the dataset.");
258  }
259  break;
260  } // case H5G_DATASET
261 
262  case H5O_TYPE_NAMED_DATATYPE:
263  // ignore the named datatype
264  break;
265 
266  default:
267  break;
268  }
269  } // for (int i = 0; i < nelems; i++)
270 
271  DBG(cerr << "<depth_first():" << gname << endl);
272 }
273 
288 string print_attr(hid_t type, int loc, void *sm_buf) {
289 //static char *print_attr(hid_t type, int loc, void *sm_buf) {
290  union {
291  char *tcp;
292  short *tsp;
293  unsigned short *tusp;
294  int *tip;
295  long *tlp;
296  float *tfp;
297  double *tdp;
298  } gp;
299 
300  //char *rep = NULL; // This holds the return value
301  vector<char> rep;
302 
303  //try {
304  switch (H5Tget_class(type)) {
305 
306  case H5T_INTEGER: {
307  // change void pointer into the corresponding integer datatype.
308  // 32 should be long enough to hold one integer and one
309  // floating point number.
310  //rep = new char[32];
311  //memset(rep, 0, 32);
312  rep.resize(32);
313 
314  if (H5Tequal(type, H5T_STD_U8BE) || H5Tequal(type, H5T_STD_U8LE)
315  || H5Tequal(type, H5T_NATIVE_UCHAR)) {
316  gp.tcp = (char *) sm_buf;
317  unsigned char tuchar = *(gp.tcp + loc);
318  // represent uchar with numerical form since for NASA aura
319  // files, type of missing value is unsigned char. ky
320  // 2007-5-4
321  snprintf(&rep[0], 32, "%u", tuchar);
322  }
323 
324  else if (H5Tequal(type, H5T_STD_U16BE)
325  || H5Tequal(type, H5T_STD_U16LE)
326  || H5Tequal(type, H5T_NATIVE_USHORT)) {
327  gp.tusp = (unsigned short *) sm_buf;
328  snprintf(&rep[0], 32, "%hu", *(gp.tusp + loc));
329  }
330 
331  else if (H5Tequal(type, H5T_STD_U32BE)
332  || H5Tequal(type, H5T_STD_U32LE)
333  || H5Tequal(type, H5T_NATIVE_UINT)) {
334 
335  gp.tip = (int *) sm_buf;
336  snprintf(&rep[0], 32, "%u", *(gp.tip + loc));
337  }
338 
339  else if (H5Tequal(type, H5T_STD_U64BE)
340  || H5Tequal(type, H5T_STD_U64LE)
341  || H5Tequal(type, H5T_NATIVE_ULONG)
342  || H5Tequal(type, H5T_NATIVE_ULLONG)) {
343 
344  gp.tlp = (long *) sm_buf;
345  snprintf(&rep[0], 32, "%lu", *(gp.tlp + loc));
346  }
347 
348  else if (H5Tequal(type, H5T_STD_I8BE)
349  || H5Tequal(type, H5T_STD_I8LE)
350  || H5Tequal(type, H5T_NATIVE_CHAR)) {
351 
352  gp.tcp = (char *) sm_buf;
353  // Display byte in numerical form. This is for Aura file.
354  //
355  // This generates an attribute like "Byte _FillValue -127".
356  // It can cause IDV to crash since Java OPeNDAP expects
357  // Byte value > 0.
358  //
359  // See ticket: http://scm.opendap.org/trac/ticket/1199
360  snprintf(&rep[0], 32, "%d", *(gp.tcp + loc));
361  }
362 
363  else if (H5Tequal(type, H5T_STD_I16BE)
364  || H5Tequal(type, H5T_STD_I16LE)
365  || H5Tequal(type, H5T_NATIVE_SHORT)) {
366 
367  gp.tsp = (short *) sm_buf;
368  snprintf(&rep[0], 32, "%hd", *(gp.tsp + loc));
369  }
370 
371  else if (H5Tequal(type, H5T_STD_I32BE)
372  || H5Tequal(type, H5T_STD_I32LE)
373  || H5Tequal(type, H5T_NATIVE_INT)) {
374 
375  gp.tip = (int *) sm_buf;
376  snprintf(&rep[0], 32, "%d", *(gp.tip + loc));
377  }
378 
379  else if (H5Tequal(type, H5T_STD_I64BE)
380  || H5Tequal(type, H5T_STD_I64LE)
381  || H5Tequal(type, H5T_NATIVE_LONG)
382  || H5Tequal(type, H5T_NATIVE_LLONG)) {
383 
384  gp.tlp = (long *) sm_buf;
385  snprintf(&rep[0], 32, "%ld", *(gp.tlp + loc));
386  }
387 
388  break;
389  }
390 
391  case H5T_FLOAT: {
392  rep.resize(32);
393  char gps[30];
394 
395  if (H5Tget_size(type) == 4) {
396 
397  // Represent the float number.
398  // Some space may be wasted. But it is okay.
399  gp.tfp = (float *) sm_buf;
400  snprintf(gps, 30, "%.10g", *(gp.tfp + loc));
401  int ll = strlen(gps);
402 
403  // Add the dot to assure this is a floating number
404  if (!strchr(gps, '.') && !strchr(gps, 'e'))
405  gps[ll++] = '.';
406 
407  gps[ll] = '\0';
408  snprintf(&rep[0], 32, "%s", gps);
409  }
410  else if (H5Tget_size(type) == 8) {
411 
412  gp.tdp = (double *) sm_buf;
413  snprintf(gps, 30, "%.17g", *(gp.tdp + loc));
414  int ll = strlen(gps);
415  if (!strchr(gps, '.') && !strchr(gps, 'e'))
416  gps[ll++] = '.';
417  gps[ll] = '\0';
418  snprintf(&rep[0], 32, "%s", gps);
419  }
420  else if (H5Tget_size(type) == 0){
421  throw InternalErr(__FILE__, __LINE__, "H5Tget_size() failed.");
422  }
423  break;
424  }
425 
426  case H5T_STRING: {
427  int str_size = H5Tget_size(type);
428  if(H5Tis_variable_str(type) == true)
429  // cerr <<"variable length string "<<endl;
430  if (str_size == 0){
431  throw InternalErr(__FILE__, __LINE__, "H5Tget_size() failed.");
432  }
433  DBG(cerr << "=print_attr(): H5T_STRING sm_buf=" << (char *) sm_buf
434  << " size=" << str_size << endl);
435  char *buf = NULL;
436  // This try/catch block is here to protect the allocation of buf.
437  try {
438  buf = new char[str_size + 1];
439  strncpy(buf, (char *) sm_buf, str_size);
440  buf[str_size] = '\0';
441  //rep = new char[str_size + 3];
442  rep.resize(str_size+3);
443  snprintf(&rep[0], str_size + 3, "%s", buf);
444  rep[str_size + 2] = '\0';
445  delete[] buf; buf = 0;
446  }
447  catch (...) {
448  if( buf ) delete[] buf;
449  throw;
450  }
451  break;
452  }
453 
454  default:
455  break;
456  } // switch(H5Tget_class(type))
457  //} // try
458  //catch (...) {
459 // if( rep ) delete[] rep;
460 // throw;
461  // }
462 
463  string rep_str(rep.begin(),rep.end());
464  return rep_str;
465 }
466 
467 
469 // \fn read_objects(DAS & das, const string & varname, hid_t oid, int num_attr)
481 void read_objects(DAS & das, const string & varname, hid_t oid, int num_attr)
482 {
483 
484  DBG(cerr << ">read_objects():"
485  << "varname=" << varname << " id=" << oid << endl);
486 
487  // Prepare a variable for full path attribute.
488  string hdf5_path = HDF5_OBJ_FULLPATH;
489 
490  // Obtain the DAS table of which the name is the variable name.
491  // If not finding the table, add a table of which the name is the variable name.
492  AttrTable *attr_table_ptr = das.get_table(varname);
493  if (!attr_table_ptr) {
494  DBG(cerr << "=read_objects(): adding a table with name " << varname
495  << endl);
496  attr_table_ptr = das.add_table(varname, new AttrTable);
497  }
498 
499  // Add a DAP attribute that stores the HDF5 absolute path
500  attr_table_ptr->append_attr(hdf5_path.c_str(), STRING, varname);
501 
502  // Check the number of attributes in this HDF5 object and
503  // put HDF5 attribute information into the DAS table.
504  //char *print_rep = NULL;
505  string print_rep;
506  vector<char>temp_buf;
507 
508  //try {
509  bool ignore_attr = false;
510  hid_t attr_id;
511  for (int j = 0; j < num_attr; j++) {
512 
513  // Obtain attribute information.
514  DSattr_t attr_inst;
515 
516  // Ignore the attributes of which the HDF5 datatype
517  // cannot be mapped to DAP2. The ignored attribute datatypes can be found
518  // at function get_attr_info in h5get.cc.
519  attr_id = get_attr_info(oid, j, &attr_inst, &ignore_attr);
520  if (ignore_attr) continue;
521 
522  // Since HDF5 attribute may be in string datatype, it must be dealt
523  // properly. Get data type.
524  hid_t ty_id = attr_inst.type;
525  string dap_type = get_dap_type(ty_id);
526  string attr_name = attr_inst.name;
527 
528 
529  // We have to handle variable length string differently.
530  if (H5Tis_variable_str(attr_inst.type)) {
531 
532  DBG(cerr <<"attribute name " << attr_name <<endl);
533  DBG(cerr <<"attribute size " <<attr_inst.need <<endl);
534  DBG(cerr <<"attribute type size " <<(int)(H5Tget_size(attr_inst.type))<<endl);
535 
536  hid_t temp_space_id = H5Aget_space(attr_id);
537  DBG(cerr <<"attribute calculated size "<<(int)(H5Tget_size(attr_inst.type)) *(int)(H5Sget_simple_extent_npoints(temp_space_id)) <<endl);
538 
539  // Variable length string attribute values only store pointers of the actual string value.
540  temp_buf.resize((size_t)attr_inst.need);
541 
542  if (H5Aread(attr_id, ty_id, &temp_buf[0]) < 0) {
543  H5Sclose(temp_space_id);
544  H5Aclose(attr_id);
545  throw InternalErr(__FILE__, __LINE__, "unable to read HDF5 attribute data");
546  }
547 
548  char *temp_bp;
549  temp_bp = &temp_buf[0];
550  char* onestring;
551  for (unsigned int temp_i = 0; temp_i <attr_inst.nelmts; temp_i++) {
552 
553  // This line will assure that we get the real variable length string value.
554  onestring =*(char **)temp_bp;
555 
556  // Change the C-style string to C++ STD string just for easy appending the attributes in DAP.
557  if (onestring !=NULL) {
558  string tempstring(onestring);
559  // cerr <<"temp_string attr "<<tempstring <<endl;
560  attr_table_ptr->append_attr(attr_name, dap_type, tempstring);
561  }
562 
563  // going to the next value.
564  temp_bp +=H5Tget_size(attr_inst.type);
565  }
566  if (temp_buf.empty() != true) {
567  // Reclaim any VL memory if necessary.
568  H5Dvlen_reclaim(attr_inst.type,temp_space_id,H5P_DEFAULT,&temp_buf[0]);
569  temp_buf.clear();
570  }
571  H5Sclose(temp_space_id);
572  }
573  else {
574 
575  vector<char> value;
576  value.resize(attr_inst.need + sizeof(char));
577  DBG(cerr << "arttr_inst.need=" << attr_inst.need << endl);
578 
579  // Read HDF5 attribute data.
580  if (H5Aread(attr_id, ty_id, (void *) (&value[0])) < 0) {
581  // value is deleted in the catch block below so
582  // shouldn't be deleted here. pwest Mar 18, 2009
583  throw InternalErr(__FILE__, __LINE__, "unable to read HDF5 attribute data");
584  }
585  DBG(cerr << "H5Aread(" << attr_inst.name << ")=" << value << endl);
586 
587  // For scalar data, just read data once.
588  if (attr_inst.ndims == 0) {
589  for (int loc = 0; loc < (int) attr_inst.nelmts; loc++) {
590  print_rep = print_attr(ty_id, loc, &value[0]);
591  //if (print_rep != NULL) {
592  if (print_rep.c_str() != NULL) {
593  attr_table_ptr->append_attr(attr_name, dap_type, print_rep.c_str());
594  //delete[] print_rep;
595  //print_rep = NULL;
596  }
597  }
598 
599  }
600  else {
601  // If the hdf5 data type is HDF5 string or number of dimension is > 0;
602  // handle this differently.
603  DBG(cerr << "=read_objects(): ndims=" << (int) attr_inst.
604  ndims << endl);
605 
606  // Get the attribute datatype size
607  int elesize = (int) H5Tget_size(attr_inst.type);
608  if (elesize == 0) {
609  DBG(cerr << "=read_objects(): elesize=0" << endl);
610  //delete[] value;
611  if (H5Aclose(attr_id) < 0) {
612  throw InternalErr(__FILE__, __LINE__, "unable to close attibute id");
613  }
614 
615  throw InternalErr(__FILE__, __LINE__, "unable to get attibute size");
616  }
617 
618  // Due to the implementation of print_attr, the attribute value will be
619  // written one by one.
620  char *tempvalue = &value[0];
621  // cerr <<"nelems = "<<(int)attr_inst.nelmts <<endl;
622 
623 // for (int dim = 0; dim < (int) attr_inst.ndims; dim++) {
624 // for (int sizeindex = 0; sizeindex < (int) attr_inst.size[dim]; sizeindex++) {
625 
626  // Write this value. the "loc" can always be set to 0 since
627  // tempvalue will be moved to the next value.
628  for( hsize_t temp_index = 0; temp_index < attr_inst.nelmts; temp_index ++) {
629  print_rep = print_attr(ty_id, 0/*loc*/, tempvalue);
630  //if (print_rep != NULL) {
631  if (print_rep.c_str() != NULL) {
632  attr_table_ptr->append_attr(attr_name, dap_type, print_rep.c_str());
633  tempvalue = tempvalue + elesize;
634 
635  DBG(cerr
636  << "tempvalue=" << tempvalue
637  << "elesize=" << elesize
638  << endl);
639 
640  //delete[] print_rep;
641  //print_rep = NULL;
642  }
643  else {
644  if (H5Aclose(attr_id) < 0) {
645  throw InternalErr(__FILE__, __LINE__, "unable to close HDF5 attibute id");
646  }
647 
648  throw InternalErr(__FILE__, __LINE__, "unable to convert attibute value to DAP");
649  }
650  }
651  // } // for (int sizeindex = 0; ...
652  // } // for (int dim = 0; ...
653  } // if attr_inst.ndims != 0
654  }
655  if (H5Aclose(attr_id) < 0) {
656  throw InternalErr(__FILE__, __LINE__, "unable to close attibute id");
657 
658  }
659  } // for (int j = 0; j < num_attr; j++)
660  //} // try - protects print_rep and value
661 #if 0
662  catch (...) {
663  if (print_rep)
664  delete[] print_rep;
665  throw;
666  }
667 #endif
668 
669  DBG(cerr << "<read_objects()" << endl);
670 }
671 
683 void find_gloattr(hid_t file, DAS & das)
684 {
685  DBG(cerr << ">find_gloattr()" << endl);
686 
687  hid_t root = H5Gopen(file, "/",H5P_DEFAULT);
688  try {
689  if (root < 0)
690  throw InternalErr(__FILE__, __LINE__,
691  "unable to open the HDF5 root group");
692 
693  // In the default option of the HDF5 handler, the
694  // HDF5 file structure(group hierarchy) will be mapped to
695  // a DAP attribute HDF5_ROOT_GROUP. In a sense, this created
696  // attribute can be treated as an HDF5 attribute under the root group,
697  // so to say, a global attribute.
698  das.add_table("HDF5_ROOT_GROUP", new AttrTable);
699 
700  // Since the root group is the first HDF5 object to visit(in HDF5RequestHandler.cc, find_gloattr()
701  // is before the depth_first()), it will always be not visited. However, to find the cyclic groups
702  // to root, we still need to add the object name to the global variable name list "paths" defined at
703  // the beginning of the h5das.cc file.
704  get_hardlink(root, "/");
705 
706  // Obtain the number of "real" attributes of the root group.
707  int num_attrs;
708  H5O_info_t obj_info;
709  if (H5Oget_info(root, &obj_info) <0) {
710  H5Gclose(root);
711  string msg = "Obtaining the info. failed for the root group ";
712  throw InternalErr(__FILE__, __LINE__, msg);
713  }
714 
715  // Obtain the number of attributes
716  num_attrs = obj_info.num_attrs;
717  if (num_attrs < 0) {
718  H5Gclose(root);
719  throw InternalErr(__FILE__, __LINE__,
720  "unable to get the number of attributes for the HDF root group ");
721 
722  }
723  if (num_attrs == 0) {
724  if(H5Gclose(root) < 0){
725  throw InternalErr(__FILE__, __LINE__,
726  "Could not close the group.");
727  }
728  DBG(cerr << "<find_gloattr():no attributes" << endl);
729  return;
730  }
731 
732  // Map the HDF5 root attributes to DAP and save it in a DAS table "H5_GLOBAL".
733  // In theory, we can just "/" as the table name. To help clients better understand,
734  // we use "H5_GLOBAL" which is a more meaningful name.
735  read_objects(das, "H5_GLOBAL", root, num_attrs);
736 
737  DBG(cerr << "=find_gloattr(): H5Gclose()" << endl);
738  if(H5Gclose(root) < 0){
739  throw InternalErr(__FILE__, __LINE__, "Could not close the group.");
740  }
741  DBG(cerr << "<find_gloattr()" << endl);
742  }
743  catch (...) {
744  if(H5Gclose(root) < 0){
745  throw InternalErr(__FILE__, __LINE__, "Could not close the group.");
746  }
747  throw;
748  }
749 }
750 
765 void get_softlink(DAS & das, hid_t pgroup, const char *gname, const string & oname, int index, size_t val_size)
766 {
767  DBG(cerr << ">get_softlink():" << oname << endl);
768 
769  ostringstream oss;
770  oss << string("HDF5_SOFTLINK");
771  oss << "_";
772  oss << index;
773  string temp_varname = oss.str();
774 
775 //cerr <<"temp_varname "<<temp_varname <<endl;
776 
777  DBG(cerr << "=get_softlink():" << temp_varname << endl);
778  AttrTable *attr_table_ptr = das.get_table(gname);
779  if (!attr_table_ptr)
780  attr_table_ptr = das.add_table(gname, new AttrTable);
781 
782  AttrTable *attr_softlink_ptr;
783  attr_softlink_ptr = attr_table_ptr->append_container(temp_varname);
784 
785  string softlink_name = "linkname";
786  attr_softlink_ptr->append_attr(softlink_name,STRING,oname);
787  string softlink_value_name ="LINKTARGET";
788 
789 
790  // Get the link target information. We always return the link value in a string format.
791 
792  char *buf = 0;
793  try {
794  // TODO replace buf with vector<char> buf(val_size + 1);
795  // then access as a char * using &buf[0]
796  buf = new char[(val_size + 1) * sizeof(char)];
797  // get link target name
798  if (H5Lget_val(pgroup, oname.c_str(), (void*) buf,val_size + 1, H5P_DEFAULT)
799  < 0) {
800  throw InternalErr(__FILE__, __LINE__, "unable to get link value");
801  }
802  attr_softlink_ptr->append_attr(softlink_value_name, STRING, buf);
803  delete[]buf;
804  }
805  catch (...) {
806  delete[] buf;
807  throw;
808  }
809 }
810 
824 string get_hardlink(hid_t pgroup, const string & oname) {
825 
826  DBG(cerr << ">get_hardlink():" << oname << endl);
827 
828  // Get the object info
829  H5O_info_t obj_info;
830  if (H5Oget_info(pgroup, &obj_info) <0) {
831  throw InternalErr(__FILE__, __LINE__, "H5Oget_info() failed.");
832  }
833 
834  // If the reference count is greater than 1,that means
835  // hard links are found. return the original object name this
836  // hard link points to.
837 
838  if (obj_info.rc >1) {
839 
840  ostringstream oss;
841  oss << hex << obj_info.addr;
842  string objno = oss.str();
843 
844  DBG(cerr << "=get_hardlink() objno=" << objno << endl);
845 
846  if (!paths.add(objno, oname)) {
847  return objno;
848  }
849  else {
850  return "";
851  }
852  }
853  else {
854  return "";
855  }
856 
857 }
858 
868 void read_comments(DAS & das, const string & varname, hid_t oid)
869 {
870 
871  // Obtain the comment size
872  int comment_size;
873  comment_size=(int)(H5Oget_comment(oid,NULL,0));
874  if (comment_size <0) {
875  throw InternalErr(__FILE__, __LINE__,
876  "Could not retrieve the comment size.");
877  }
878 
879  if (comment_size > 0) {
880  vector<char> comment;
881  comment.resize(comment_size+1);
882  if (H5Oget_comment(oid,&comment[0],comment_size+1)<0) {
883  throw InternalErr(__FILE__, __LINE__,
884  "Could not retrieve the comment.");
885  }
886 
887  // Insert this comment into the das table.
888  AttrTable *at = das.get_table(varname);
889  if (!at)
890  at = das.add_table(varname, new AttrTable);
891  at->append_attr("HDF5_COMMENT", STRING, &comment[0]);
892 
893  //delete[] comment;
894  }
895 }
896 
916 void add_group_structure_info(DAS & das, const char *gname, char *oname,
917  bool is_group)
918 {
919 
920 
921  string h5_spec_char("/");
922  string dap_notion(".");
923  string::size_type pos = 1;
924 
925  if(gname == NULL){
926  throw InternalErr(__FILE__, __LINE__,
927  "The wrong HDF5 group name.");
928  }
929 
930  string full_path = string(gname);
931 
932  // Change the HDF5 special character '/' with DAP notion '.'
933  // to make sure the group structure can be handled by DAP properly.
934  while ((pos = full_path.find(h5_spec_char, pos)) != string::npos) {
935  full_path.replace(pos, h5_spec_char.size(), dap_notion);
936  pos++;
937  }
938 
939  // If the HDF5 file includes only the root group, replacing
940  // the "/" with the string "HDF5_ROOT_GROUP".
941  // Otherwise, replacing the first "/" with the string "HDF5_ROOT_GROUP.",
942  // (note the . after "HDF5_ROOT_GROUP." . Then cutting the last "/".
943 
944  // TODO I don't think sizeof(gname) is right. jhrg 9/26/13
945  if (strncmp(gname, "/", strlen(gname)) == 0) {
946  full_path.replace(0, 1, "HDF5_ROOT_GROUP");
947  }
948  else {
949  full_path.replace(0, 1, "HDF5_ROOT_GROUP.");
950  full_path = full_path.substr(0, full_path.length() - 1);
951  }
952 
953  DBG(cerr << full_path << endl);
954 
955  AttrTable *at = das.get_table(full_path);
956  if(at == NULL){
957  throw InternalErr(__FILE__, __LINE__,
958  "Failed to add group structure information for "
959  + full_path
960  + " attribute table."
961  + "This happens when a group name has . character.");
962  }
963 
964  // group will be mapped to a container
965  if (is_group) {
966  at->append_container(oname);
967  }
968  else {
969  at->append_attr("Dataset", "String", oname);
970  }
971 }
972 
973 
974 
#define comment
Definition: lex.hdfeos.cc:606
void add_group_structure_info(DAS &das, const char *gname, char *oname, bool is_group)
will insert group information in a structure format into DAS table.
Definition: h5das.cc:916
string get_dap_type(hid_t type)
returns the string representation of HDF5 type.
Definition: h5get.cc:237
HDF5PathFinder paths
A variable for remembering visited paths to break cyclic HDF5 groups.
Definition: h5das.cc:42
string get_name(string id)
Get the object name of id object in the map.
bool add(string id, const string name)
Adds name and id object number into an internal map.
#define DODS_NAMELEN
Maximum length of variable or attribute name(default option only).
Definition: hdf5_handler.h:43
int type
Memory type.
Definition: hdf5_handler.h:91
size_t need
Memory space needed to hold nelmts type.
Definition: hdf5_handler.h:99
void read_objects(DAS &das, const string &varname, hid_t oid, int num_attr)
will fill in attributes of a dataset or a group into one DAS table.
Definition: h5das.cc:481
The main header of the HDF5 OPeNDAP handler.
string get_hardlink(hid_t pgroup, const string &oname)
will put hardlink information into a DAS table.
Definition: h5das.cc:824
void find_gloattr(hid_t file, DAS &das)
will fill in attributes of the root group into one DAS table.
Definition: h5das.cc:683
#define NULL
Definition: wcsUtil.h:65
A structure for DAS generation.
Definition: hdf5_handler.h:87
#define HDF5_OBJ_FULLPATH
The special DAS attribute name for HDF5 path information from the top(root) group.
Definition: hdf5_handler.h:45
hid_t get_attr_info(hid_t dset, int index, DSattr_t *attr_inst_ptr, bool *ignore_attr_ptr)
Definition: h5get.cc:56
void read_comments(DAS &das, const string &varname, hid_t oid)
will fill in attributes of a group's comment into DAS table.
Definition: h5das.cc:868
void depth_first(hid_t pid, const char *gname, DAS &das)
depth first traversal of hdf5 file attributes.
Definition: h5das.cc:60
hsize_t nelmts
Number of elements.
Definition: hdf5_handler.h:97
int ndims
Number of dimensions.
Definition: hdf5_handler.h:93
void get_softlink(DAS &das, hid_t pgroup, const char *gname, const string &oname, int index, size_t val_size)
Definition: h5das.cc:765
char name[DODS_NAMELEN]
Name of HDF5 group or dataset.
Definition: hdf5_handler.h:89
string print_attr(hid_t type, int loc, void *sm_buf)
will get the printed representation of an attribute.
Definition: h5das.cc:288