GNU Octave  4.0.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
ls-hdf5.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2015 John W. Eaton
4 
5 This file is part of Octave.
6 
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 // Author: Steven G. Johnson <stevenj@alum.mit.edu>
24 
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28 
29 #if defined (HAVE_HDF5)
30 
31 #include <cfloat>
32 #include <cstring>
33 #include <cctype>
34 
35 #include <fstream>
36 #include <iomanip>
37 #include <iostream>
38 #include <string>
39 #include <vector>
40 
41 #include "byte-swap.h"
42 #include "data-conv.h"
43 #include "file-ops.h"
44 #include "glob-match.h"
45 #include "lo-mappers.h"
46 #include "mach-info.h"
47 #include "oct-env.h"
48 #include "oct-time.h"
49 #include "quit.h"
50 #include "str-vec.h"
51 #include "oct-locbuf.h"
52 
53 #include "Cell.h"
54 #include "defun.h"
55 #include "error.h"
56 #include "gripes.h"
57 #include "load-save.h"
58 #include "oct-hdf5-id.h"
59 #include "oct-obj.h"
60 #include "oct-map.h"
61 #include "ov-cell.h"
62 #include "pager.h"
63 #include "pt-exp.h"
64 #include "sysdep.h"
65 #include "unwind-prot.h"
66 #include "utils.h"
67 #include "variables.h"
68 #include "version.h"
69 #include "dMatrix.h"
70 #include "ov-lazy-idx.h"
71 
72 #include "ls-utils.h"
73 #include "ls-hdf5.h"
74 
75 static std::string
76 make_valid_identifier (const std::string& nm)
77 {
78  std::string retval;
79 
80  size_t nm_len = nm.length ();
81 
82  if (nm_len > 0)
83  {
84  if (! isalpha (nm[0]))
85  retval += '_';
86 
87  for (size_t i = 0; i < nm_len; i++)
88  {
89  char c = nm[i];
90  retval += (isalnum (c) || c == '_') ? c : '_';
91  }
92  }
93 
94  return retval;
95 }
96 
97 // Define this to 1 if/when HDF5 supports automatic conversion between
98 // integer and floating-point binary data:
99 #define HAVE_HDF5_INT2FLOAT_CONVERSIONS 0
100 
101 // Given two compound types t1 and t2, determine whether they
102 // are compatible for reading/writing. This function only
103 // works for non-nested types composed of simple elements (ints, floats...),
104 // which is all we need it for
105 
106 bool
107 hdf5_types_compatible (hid_t t1, hid_t t2)
108 {
109  int n;
110  if ((n = H5Tget_nmembers (t1)) != H5Tget_nmembers (t2))
111  return false;
112 
113  for (int i = 0; i < n; ++i)
114  {
115  hid_t mt1 = H5Tget_member_type (t1, i);
116  hid_t mt2 = H5Tget_member_type (t2, i);
117 
118  if (H5Tget_class (mt1) != H5Tget_class (mt2))
119  return false;
120 
121  H5Tclose (mt2);
122  H5Tclose (mt1);
123  }
124 
125  return true;
126 }
127 
128 // Return true if loc_id has the attribute named attr_name, and false
129 // otherwise.
130 
131 bool
132 hdf5_check_attr (hid_t loc_id, const char *attr_name)
133 {
134  bool retval = false;
135 
136  // we have to pull some shenanigans here to make sure
137  // HDF5 doesn't print out all sorts of error messages if we
138  // call H5Aopen for a non-existing attribute
139 
140  H5E_auto_t err_func;
141  void *err_func_data;
142 
143  // turn off error reporting temporarily, but save the error
144  // reporting function:
145 
146 #if HAVE_HDF5_18
147  H5Eget_auto (H5E_DEFAULT, &err_func, &err_func_data);
148  H5Eset_auto (H5E_DEFAULT, 0, 0);
149 #else
150  H5Eget_auto (&err_func, &err_func_data);
151  H5Eset_auto (0, 0);
152 #endif
153 
154  hid_t attr_id = H5Aopen_name (loc_id, attr_name);
155 
156  if (attr_id >= 0)
157  {
158  // successful
159  retval = true;
160  H5Aclose (attr_id);
161  }
162 
163  // restore error reporting:
164 #if HAVE_HDF5_18
165  H5Eset_auto (H5E_DEFAULT, err_func, err_func_data);
166 #else
167  H5Eset_auto (err_func, err_func_data);
168 #endif
169  return retval;
170 }
171 
172 bool
173 hdf5_get_scalar_attr (hid_t loc_id, hid_t type_id,
174  const char *attr_name, void *buf)
175 {
176  bool retval = false;
177 
178  // we have to pull some shenanigans here to make sure
179  // HDF5 doesn't print out all sorts of error messages if we
180  // call H5Aopen for a non-existing attribute
181 
182  H5E_auto_t err_func;
183  void *err_func_data;
184 
185  // turn off error reporting temporarily, but save the error
186  // reporting function:
187 
188 #if HAVE_HDF5_18
189  H5Eget_auto (H5E_DEFAULT, &err_func, &err_func_data);
190  H5Eset_auto (H5E_DEFAULT, 0, 0);
191 #else
192  H5Eget_auto (&err_func, &err_func_data);
193  H5Eset_auto (0, 0);
194 #endif
195 
196  hid_t attr_id = H5Aopen_name (loc_id, attr_name);
197 
198  if (attr_id >= 0)
199  {
200  hid_t space_id = H5Aget_space (attr_id);
201 
202  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
203 
204  if (rank == 0)
205  retval = H5Aread (attr_id, type_id, buf) >= 0;
206  H5Aclose (attr_id);
207  }
208 
209  // restore error reporting:
210 #if HAVE_HDF5_18
211  H5Eset_auto (H5E_DEFAULT, err_func, err_func_data);
212 #else
213  H5Eset_auto (err_func, err_func_data);
214 #endif
215  return retval;
216 }
217 
218 
219 
220 
221 // The following subroutines creates an HDF5 representations of the way
222 // we will store Octave complex types (pairs of floating-point numbers).
223 // NUM_TYPE is the HDF5 numeric type to use for storage (e.g.
224 // H5T_NATIVE_DOUBLE to save as 'double'). Note that any necessary
225 // conversions are handled automatically by HDF5.
226 
227 hid_t
228 hdf5_make_complex_type (hid_t num_type)
229 {
230  hid_t type_id = H5Tcreate (H5T_COMPOUND, sizeof (double) * 2);
231 
232  H5Tinsert (type_id, "real", 0 * sizeof (double), num_type);
233  H5Tinsert (type_id, "imag", 1 * sizeof (double), num_type);
234 
235  return type_id;
236 }
237 
238 // This function is designed to be passed to H5Giterate, which calls it
239 // on each data item in an HDF5 file. For the item whose name is NAME in
240 // the group GROUP_ID, this function sets dv->tc to an Octave representation
241 // of that item. (dv must be a pointer to hdf5_callback_data.) (It also
242 // sets the other fields of dv).
243 //
244 // It returns 1 on success (in which case H5Giterate stops and returns),
245 // -1 on error, and 0 to tell H5Giterate to continue on to the next item
246 // (e.g. if NAME was a data type we don't recognize).
247 
248 herr_t
249 hdf5_read_next_data (hid_t group_id, const char *name, void *dv)
250 {
251  hdf5_callback_data *d = static_cast<hdf5_callback_data *> (dv);
252  hid_t type_id = -1;
253  hid_t type_class_id = -1;
254  hid_t data_id = -1;
255  hid_t subgroup_id = -1;
256  hid_t space_id = -1;;
257 
258  H5G_stat_t info;
259  herr_t retval = 0;
260  bool ident_valid = valid_identifier (name);
261 
262  std::string vname = name;
263 
264  // Allow identifiers as all digits so we can load lists saved by
265  // earlier versions of Octave.
266 
267  if (! ident_valid)
268  {
269  // fix the identifier, replacing invalid chars with underscores
270  vname = make_valid_identifier (vname);
271 
272  // check again (in case vname was null, empty, or some such thing):
273  ident_valid = valid_identifier (vname);
274  }
275 
276  H5Gget_objinfo (group_id, name, 1, &info);
277 
278  if (info.type == H5G_GROUP && ident_valid)
279  {
280 #if HAVE_HDF5_18
281  subgroup_id = H5Gopen (group_id, name, H5P_DEFAULT);
282 #else
283  subgroup_id = H5Gopen (group_id, name);
284 #endif
285 
286  if (subgroup_id < 0)
287  {
288  retval = subgroup_id;
289  goto done;
290  }
291 
292  if (hdf5_check_attr (subgroup_id, "OCTAVE_NEW_FORMAT"))
293  {
294 #if HAVE_HDF5_18
295  data_id = H5Dopen (subgroup_id, "type", H5P_DEFAULT);
296 #else
297  data_id = H5Dopen (subgroup_id, "type");
298 #endif
299 
300  if (data_id < 0)
301  {
302  retval = data_id;
303  goto done;
304  }
305 
306  type_id = H5Dget_type (data_id);
307 
308  type_class_id = H5Tget_class (type_id);
309 
310  if (type_class_id != H5T_STRING)
311  goto done;
312 
313  space_id = H5Dget_space (data_id);
314  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
315 
316  if (rank != 0)
317  goto done;
318 
319  int slen = H5Tget_size (type_id);
320  if (slen < 0)
321  goto done;
322 
323  OCTAVE_LOCAL_BUFFER (char, typ, slen);
324 
325  // create datatype for (null-terminated) string to read into:
326  hid_t st_id = H5Tcopy (H5T_C_S1);
327  H5Tset_size (st_id, slen);
328 
329  if (H5Dread (data_id, st_id, H5S_ALL, H5S_ALL, H5P_DEFAULT,
330  typ) < 0)
331  goto done;
332 
333  H5Tclose (st_id);
334  H5Dclose (data_id);
335 
337 
338  retval = (d->tc.load_hdf5 (subgroup_id, "value") ? 1 : -1);
339 
340  // check for OCTAVE_GLOBAL attribute:
341  d->global = hdf5_check_attr (subgroup_id, "OCTAVE_GLOBAL");
342 
343  H5Gclose (subgroup_id);
344  }
345  else
346  {
347  // an HDF5 group is treated as an octave structure by
348  // default (since that preserves name information), and an
349  // octave list otherwise.
350 
351  if (hdf5_check_attr (subgroup_id, "OCTAVE_LIST"))
353  else
354  d->tc = octave_value_typeinfo::lookup_type ("struct");
355 
356  // check for OCTAVE_GLOBAL attribute:
357  d->global = hdf5_check_attr (subgroup_id, "OCTAVE_GLOBAL");
358 
359  H5Gclose (subgroup_id);
360 
361  retval = (d->tc.load_hdf5 (group_id, name) ? 1 : -1);
362  }
363 
364  }
365  else if (info.type == H5G_DATASET && ident_valid)
366  {
367  // For backwards compatiability.
368 #if HAVE_HDF5_18
369  data_id = H5Dopen (group_id, name, H5P_DEFAULT);
370 #else
371  data_id = H5Dopen (group_id, name);
372 #endif
373 
374  if (data_id < 0)
375  {
376  retval = data_id;
377  goto done;
378  }
379 
380  type_id = H5Dget_type (data_id);
381 
382  type_class_id = H5Tget_class (type_id);
383 
384  if (type_class_id == H5T_FLOAT)
385  {
386  space_id = H5Dget_space (data_id);
387 
388  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
389 
390  if (rank == 0)
391  d->tc = octave_value_typeinfo::lookup_type ("scalar");
392  else
393  d->tc = octave_value_typeinfo::lookup_type ("matrix");
394 
395  H5Sclose (space_id);
396  }
397  else if (type_class_id == H5T_INTEGER)
398  {
399  // What integer type do we really have..
400  std::string int_typ;
401 #ifdef HAVE_H5T_GET_NATIVE_TYPE
402  // FIXME: test this code and activated with an autoconf
403  // test!! It is also incorrect for 64-bit indexing!!
404 
405  switch (H5Tget_native_type (type_id, H5T_DIR_ASCEND))
406  {
407  case H5T_NATIVE_CHAR:
408  int_typ = "int8 ";
409  break;
410 
411  case H5T_NATIVE_SHORT:
412  int_typ = "int16 ";
413  break;
414 
415  case H5T_NATIVE_INT:
416  case H5T_NATIVE_LONG:
417  int_typ = "int32 ";
418  break;
419 
420  case H5T_NATIVE_LLONG:
421  int_typ = "int64 ";
422  break;
423 
424  case H5T_NATIVE_UCHAR:
425  int_typ = "uint8 ";
426  break;
427 
428  case H5T_NATIVE_USHORT:
429  int_typ = "uint16 ";
430  break;
431 
432  case H5T_NATIVE_UINT:
433  case H5T_NATIVE_ULONG:
434  int_typ = "uint32 ";
435  break;
436 
437  case H5T_NATIVE_ULLONG:
438  int_typ = "uint64 ";
439  break;
440  }
441 #else
442  hid_t int_sign = H5Tget_sign (type_id);
443 
444  if (int_sign == H5T_SGN_ERROR)
445  warning ("load: can't read '%s' (unknown datatype)", name);
446  else
447  {
448  if (int_sign == H5T_SGN_NONE)
449  int_typ.append ("u");
450  int_typ.append ("int");
451 
452  int slen = H5Tget_size (type_id);
453  if (slen < 0)
454  warning ("load: can't read '%s' (unknown datatype)", name);
455  else
456  {
457  switch (slen)
458  {
459  case 1:
460  int_typ.append ("8 ");
461  break;
462 
463  case 2:
464  int_typ.append ("16 ");
465  break;
466 
467  case 4:
468  int_typ.append ("32 ");
469  break;
470 
471  case 8:
472  int_typ.append ("64 ");
473  break;
474 
475  default:
476  warning ("load: can't read '%s' (unknown datatype)",
477  name);
478  int_typ = "";
479  break;
480  }
481  }
482  }
483 #endif
484  if (int_typ == "")
485  warning ("load: can't read '%s' (unknown datatype)", name);
486  else
487  {
488  // Matrix or scalar?
489  space_id = H5Dget_space (data_id);
490 
491  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
492 
493  if (rank == 0)
494  int_typ.append ("scalar");
495  else
496  int_typ.append ("matrix");
497 
498  d->tc = octave_value_typeinfo::lookup_type (int_typ);
499  H5Sclose (space_id);
500  }
501  }
502  else if (type_class_id == H5T_STRING)
503  d->tc = octave_value_typeinfo::lookup_type ("string");
504  else if (type_class_id == H5T_COMPOUND)
505  {
506  hid_t complex_type = hdf5_make_complex_type (H5T_NATIVE_DOUBLE);
507 
508  if (hdf5_types_compatible (type_id, complex_type))
509  {
510  // read complex matrix or scalar variable
511  space_id = H5Dget_space (data_id);
512  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
513 
514  if (rank == 0)
515  d->tc = octave_value_typeinfo::lookup_type ("complex scalar");
516  else
517  d->tc = octave_value_typeinfo::lookup_type ("complex matrix");
518 
519  H5Sclose (space_id);
520  }
521  else
522  // Assume that if its not complex its a range. If its not
523  // it'll be rejected later in the range code
524  d->tc = octave_value_typeinfo::lookup_type ("range");
525 
526  H5Tclose (complex_type);
527  }
528  else
529  {
530  warning ("load: can't read '%s' (unknown datatype)", name);
531  retval = 0; // unknown datatype; skip
532  return retval;
533  }
534 
535  // check for OCTAVE_GLOBAL attribute:
536  d->global = hdf5_check_attr (data_id, "OCTAVE_GLOBAL");
537 
538  H5Tclose (type_id);
539  H5Dclose (data_id);
540 
541  retval = (d->tc.load_hdf5 (group_id, name) ? 1 : -1);
542  }
543 
544  if (!ident_valid)
545  {
546  // should we attempt to handle invalid identifiers by converting
547  // bad characters to '_', say?
548  warning ("load: skipping invalid identifier '%s' in hdf5 file",
549  name);
550  }
551 
552 done:
553  if (retval < 0)
554  error ("load: error while reading hdf5 item %s", name);
555 
556  if (retval > 0)
557  {
558  // get documentation string, if any:
559  int comment_length = H5Gget_comment (group_id, name, 0, 0);
560 
561  if (comment_length > 1)
562  {
563  OCTAVE_LOCAL_BUFFER (char, tdoc, comment_length);
564  H5Gget_comment (group_id, name, comment_length, tdoc);
565  d->doc = tdoc;
566  }
567  else if (vname != name)
568  {
569  // the name was changed; store the original name
570  // as the documentation string:
571  d->doc = name;
572  }
573 
574  // copy name (actually, vname):
575  d->name = vname;
576  }
577 
578  return retval;
579 }
580 
581 // Read the next Octave variable from the stream IS, which must really be
582 // an hdf5_ifstream. Return the variable value in tc, its doc string
583 // in doc, and whether it is global in global. The return value is
584 // the name of the variable, or NULL if none were found or there was
585 // and error.
586 std::string
587 read_hdf5_data (std::istream& is, const std::string& /* filename */,
588  bool& global, octave_value& tc, std::string& doc,
589  const string_vector& argv, int argv_idx, int argc)
590 {
592 
593  std::string retval;
594 
595  doc.resize (0);
596 
597  hdf5_ifstream& hs = dynamic_cast<hdf5_ifstream&> (is);
599 
600  herr_t H5Giterate_retval = -1;
601 
602  hsize_t num_obj = 0;
603 #if HAVE_HDF5_18
604  hid_t group_id = H5Gopen (hs.file_id, "/", H5P_DEFAULT);
605 #else
606  hid_t group_id = H5Gopen (hs.file_id, "/");
607 #endif
608  H5Gget_num_objs (group_id, &num_obj);
609  H5Gclose (group_id);
610 
611  // For large datasets and out-of-core functionality,
612  // check if only parts of the data is requested
613  bool load_named_vars = argv_idx < argc;
614  while (load_named_vars && hs.current_item < static_cast<int> (num_obj))
615  {
616  std::vector<char> var_name;
617  bool found = false;
618  size_t len = 0;
619 
620  len = H5Gget_objname_by_idx (hs.file_id, hs.current_item, 0, 0);
621  var_name.resize (len+1);
622  H5Gget_objname_by_idx (hs.file_id, hs.current_item, &var_name[0], len+1);
623 
624  for (int i = argv_idx; i < argc; i++)
625  {
626  glob_match pattern (argv[i]);
627  if (pattern.match (std::string (&var_name[0])))
628  {
629  found = true;
630  break;
631  }
632  }
633 
634  if (found)
635  break;
636 
637  hs.current_item++;
638  }
639 
640 
641  if (hs.current_item < static_cast<int> (num_obj))
642  H5Giterate_retval = H5Giterate (hs.file_id, "/", &hs.current_item,
643  hdf5_read_next_data, &d);
644 
645  if (H5Giterate_retval > 0)
646  {
647  global = d.global;
648  tc = d.tc;
649  doc = d.doc;
650  }
651  else
652  {
653  // an error occurred (H5Giterate_retval < 0) or there are no
654  // more datasets print an error message if retval < 0?
655  // hdf5_read_next_data already printed one, probably.
656  }
657 
658  if (! d.name.empty ())
659  retval = d.name;
660 
661  return retval;
662 }
663 
664 // Add an attribute named attr_name to loc_id (a simple scalar
665 // attribute with value 1). Return value is >= 0 on success.
666 herr_t
667 hdf5_add_attr (hid_t loc_id, const char *attr_name)
668 {
669  herr_t retval = 0;
670 
671  hid_t as_id = H5Screate (H5S_SCALAR);
672 
673  if (as_id >= 0)
674  {
675 #if HAVE_HDF5_18
676  hid_t a_id = H5Acreate (loc_id, attr_name, H5T_NATIVE_UCHAR,
677  as_id, H5P_DEFAULT, H5P_DEFAULT);
678 #else
679  hid_t a_id = H5Acreate (loc_id, attr_name,
680  H5T_NATIVE_UCHAR, as_id, H5P_DEFAULT);
681 #endif
682  if (a_id >= 0)
683  {
684  unsigned char attr_val = 1;
685 
686  retval = H5Awrite (a_id, H5T_NATIVE_UCHAR, &attr_val);
687 
688  H5Aclose (a_id);
689  }
690  else
691  retval = a_id;
692 
693  H5Sclose (as_id);
694  }
695  else
696  retval = as_id;
697 
698  return retval;
699 }
700 
701 herr_t
702 hdf5_add_scalar_attr (hid_t loc_id, hid_t type_id,
703  const char *attr_name, void *buf)
704 {
705  herr_t retval = 0;
706 
707  hid_t as_id = H5Screate (H5S_SCALAR);
708 
709  if (as_id >= 0)
710  {
711 #if HAVE_HDF5_18
712  hid_t a_id = H5Acreate (loc_id, attr_name, type_id,
713  as_id, H5P_DEFAULT, H5P_DEFAULT);
714 #else
715  hid_t a_id = H5Acreate (loc_id, attr_name,
716  type_id, as_id, H5P_DEFAULT);
717 #endif
718  if (a_id >= 0)
719  {
720  retval = H5Awrite (a_id, type_id, buf);
721 
722  H5Aclose (a_id);
723  }
724  else
725  retval = a_id;
726 
727  H5Sclose (as_id);
728  }
729  else
730  retval = as_id;
731 
732  return retval;
733 }
734 
735 // Save an empty matrix, if needed. Returns
736 // > 0 Saved empty matrix
737 // = 0 Not an empty matrix; did nothing
738 // < 0 Error condition
739 int
740 save_hdf5_empty (hid_t loc_id, const char *name, const dim_vector d)
741 {
742  hsize_t sz = d.length ();
744  bool empty = false;
745  hid_t space_hid = -1;
746  hid_t data_hid = -1;
747  int retval;
748  for (hsize_t i = 0; i < sz; i++)
749  {
750  dims[i] = d(i);
751  if (dims[i] < 1)
752  empty = true;
753  }
754 
755  if (!empty)
756  return 0;
757 
758  space_hid = H5Screate_simple (1, &sz, 0);
759  if (space_hid < 0) return space_hid;
760 #if HAVE_HDF5_18
761  data_hid = H5Dcreate (loc_id, name, H5T_NATIVE_IDX, space_hid,
762  H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
763 #else
764  data_hid = H5Dcreate (loc_id, name, H5T_NATIVE_IDX, space_hid,
765  H5P_DEFAULT);
766 #endif
767  if (data_hid < 0)
768  {
769  H5Sclose (space_hid);
770  return data_hid;
771  }
772 
773  retval = H5Dwrite (data_hid, H5T_NATIVE_IDX, H5S_ALL, H5S_ALL,
774  H5P_DEFAULT, dims) >= 0;
775 
776  H5Dclose (data_hid);
777  H5Sclose (space_hid);
778 
779  if (retval >= 0)
780  retval = hdf5_add_attr (loc_id, "OCTAVE_EMPTY_MATRIX");
781 
782  return (retval == 0 ? 1 : retval);
783 }
784 
785 // Load an empty matrix, if needed. Returns
786 // > 0 loaded empty matrix, dimensions returned
787 // = 0 Not an empty matrix; did nothing
788 // < 0 Error condition
789 int
790 load_hdf5_empty (hid_t loc_id, const char *name, dim_vector &d)
791 {
792  if (! hdf5_check_attr (loc_id, "OCTAVE_EMPTY_MATRIX"))
793  return 0;
794 
795  hsize_t hdims, maxdims;
796 #if HAVE_HDF5_18
797  hid_t data_hid = H5Dopen (loc_id, name, H5P_DEFAULT);
798 #else
799  hid_t data_hid = H5Dopen (loc_id, name);
800 #endif
801  hid_t space_id = H5Dget_space (data_hid);
802  H5Sget_simple_extent_dims (space_id, &hdims, &maxdims);
803  int retval;
804 
805  OCTAVE_LOCAL_BUFFER (octave_idx_type, dims, hdims);
806 
807  retval = H5Dread (data_hid, H5T_NATIVE_IDX, H5S_ALL, H5S_ALL,
808  H5P_DEFAULT, dims);
809  if (retval >= 0)
810  {
811  d.resize (hdims);
812  for (hsize_t i = 0; i < hdims; i++)
813  d(i) = dims[i];
814  }
815 
816  H5Sclose (space_id);
817  H5Dclose (data_hid);
818 
819  return (retval == 0 ? hdims : retval);
820 }
821 
822 // save_type_to_hdf5 is not currently used, since hdf5 doesn't yet support
823 // automatic float<->integer conversions:
824 
825 #if HAVE_HDF5_INT2FLOAT_CONVERSIONS
826 
827 // return the HDF5 type id corresponding to the Octave save_type
828 
829 hid_t
830 save_type_to_hdf5 (save_type st)
831 {
832  switch (st)
833  {
834  case LS_U_CHAR:
835  return H5T_NATIVE_UCHAR;
836 
837  case LS_U_SHORT:
838  return H5T_NATIVE_USHORT;
839 
840  case LS_U_INT:
841  return H5T_NATIVE_UINT;
842 
843  case LS_CHAR:
844  return H5T_NATIVE_CHAR;
845 
846  case LS_SHORT:
847  return H5T_NATIVE_SHORT;
848 
849  case LS_INT:
850  return H5T_NATIVE_INT;
851 
852  case LS_FLOAT:
853  return H5T_NATIVE_FLOAT;
854 
855  case LS_DOUBLE:
856  default:
857  return H5T_NATIVE_DOUBLE;
858  }
859 }
860 #endif /* HAVE_HDF5_INT2FLOAT_CONVERSIONS */
861 
862 // Add the data from TC to the HDF5 location loc_id, which could
863 // be either a file or a group within a file. Return true if
864 // successful. This function calls itself recursively for lists
865 // (stored as HDF5 groups).
866 
867 bool
868 add_hdf5_data (hid_t loc_id, const octave_value& tc,
869  const std::string& name, const std::string& doc,
870  bool mark_as_global, bool save_as_floats)
871 {
872  hsize_t dims[3];
873  hid_t type_id, space_id, data_id, data_type_id;
874  type_id = space_id = data_id = data_type_id = -1;
875 
876  bool retval = false;
877  octave_value val = tc;
878  // FIXME: diagonal & permutation matrices currently don't know how to save
879  // themselves, so we convert them first to normal matrices using A = A(:,:).
880  // This is a temporary hack.
881  if (val.is_diag_matrix () || val.is_perm_matrix ()
883  val = val.full_value ();
884 
885  std::string t = val.type_name ();
886 #if HAVE_HDF5_18
887  data_id = H5Gcreate (loc_id, name.c_str (), H5P_DEFAULT, H5P_DEFAULT,
888  H5P_DEFAULT);
889 #else
890  data_id = H5Gcreate (loc_id, name.c_str (), 0);
891 #endif
892  if (data_id < 0)
893  goto error_cleanup;
894 
895  // attach the type of the variable
896  type_id = H5Tcopy (H5T_C_S1); H5Tset_size (type_id, t.length () + 1);
897  if (type_id < 0)
898  goto error_cleanup;
899 
900  dims[0] = 0;
901  space_id = H5Screate_simple (0 , dims, 0);
902  if (space_id < 0)
903  goto error_cleanup;
904 #if HAVE_HDF5_18
905  data_type_id = H5Dcreate (data_id, "type", type_id, space_id,
906  H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
907 #else
908  data_type_id = H5Dcreate (data_id, "type", type_id, space_id, H5P_DEFAULT);
909 #endif
910  if (data_type_id < 0 || H5Dwrite (data_type_id, type_id, H5S_ALL, H5S_ALL,
911  H5P_DEFAULT, t.c_str ()) < 0)
912  goto error_cleanup;
913 
914  // Now call the real function to save the variable
915  retval = val.save_hdf5 (data_id, "value", save_as_floats);
916 
917  // attach doc string as comment:
918  if (retval && doc.length () > 0
919  && H5Gset_comment (loc_id, name.c_str (), doc.c_str ()) < 0)
920  retval = false;
921 
922  // if it's global, add an attribute "OCTAVE_GLOBAL" with value 1
923  if (retval && mark_as_global)
924  retval = hdf5_add_attr (data_id, "OCTAVE_GLOBAL") >= 0;
925 
926  // We are saving in the new variable format, so mark it
927  if (retval)
928  retval = hdf5_add_attr (data_id, "OCTAVE_NEW_FORMAT") >= 0;
929 
930 error_cleanup:
931 
932  if (data_type_id >= 0)
933  H5Dclose (data_type_id);
934 
935  if (type_id >= 0)
936  H5Tclose (type_id);
937 
938  if (space_id >= 0)
939  H5Sclose (space_id);
940 
941  if (data_id >= 0)
942  H5Gclose (data_id);
943 
944  if (! retval)
945  error ("save: error while writing '%s' to hdf5 file", name.c_str ());
946 
947  return retval;
948 }
949 
950 // Write data from TC in HDF5 (binary) format to the stream OS,
951 // which must be an hdf5_ofstream, returning true on success.
952 
953 bool
954 save_hdf5_data (std::ostream& os, const octave_value& tc,
955  const std::string& name, const std::string& doc,
956  bool mark_as_global, bool save_as_floats)
957 {
959 
960  hdf5_ofstream& hs = dynamic_cast<hdf5_ofstream&> (os);
961 
962  return add_hdf5_data (hs.file_id, tc, name, doc,
963  mark_as_global, save_as_floats);
964 }
965 
966 #endif
save_type
Definition: data-conv.h:83
bool hdf5_types_compatible(hid_t t1, hid_t t2)
Definition: ls-hdf5.cc:107
static int static_type_id(void)
Definition: ov-lazy-idx.h:248
octave_value full_value(void) const
Definition: ov.h:385
bool save_hdf5(octave_hdf5_id loc_id, const char *name, bool save_as_floats)
Definition: ov.h:1103
std::string read_hdf5_data(std::istream &is, const std::string &, bool &global, octave_value &tc, std::string &doc, const string_vector &argv, int argv_idx, int argc)
Definition: ls-hdf5.cc:587
octave_value tc
Definition: ls-hdf5.h:150
std::string name
Definition: ls-hdf5.h:144
void resize(int n, int fill_value=0)
Definition: dim-vector.h:287
bool hdf5_check_attr(hid_t loc_id, const char *attr_name)
Definition: ls-hdf5.cc:132
void error(const char *fmt,...)
Definition: error.cc:476
bool is_perm_matrix(void) const
Definition: ov.h:559
int type_id(void) const
Definition: ov.h:1045
herr_t hdf5_read_next_data(hid_t group_id, const char *name, void *dv)
Definition: ls-hdf5.cc:249
herr_t hdf5_add_scalar_attr(hid_t loc_id, hid_t type_id, const char *attr_name, void *buf)
Definition: ls-hdf5.cc:702
hid_t file_id
Definition: ls-hdf5.h:41
F77_RET_T const double const double double * d
int load_hdf5_empty(hid_t loc_id, const char *name, dim_vector &d)
Definition: ls-hdf5.cc:790
std::string doc
Definition: ls-hdf5.h:153
hid_t hdf5_make_complex_type(hid_t num_type)
Definition: ls-hdf5.cc:228
static octave_value lookup_type(const std::string &nm)
Definition: ov-typeinfo.h:104
bool valid_identifier(const char *s)
Definition: utils.cc:77
bool load_hdf5(octave_hdf5_id loc_id, const char *name)
Definition: ov.h:1107
bool add_hdf5_data(hid_t loc_id, const octave_value &tc, const std::string &name, const std::string &doc, bool mark_as_global, bool save_as_floats)
Definition: ls-hdf5.cc:868
herr_t hdf5_add_attr(hid_t loc_id, const char *attr_name)
Definition: ls-hdf5.cc:667
bool hdf5_get_scalar_attr(hid_t loc_id, hid_t type_id, const char *attr_name, void *buf)
Definition: ls-hdf5.cc:173
bool match(const std::string &str) const
Definition: glob-match.cc:33
bool save_hdf5_data(std::ostream &os, const octave_value &tc, const std::string &name, const std::string &doc, bool mark_as_global, bool save_as_floats)
Definition: ls-hdf5.cc:954
void warning(const char *fmt,...)
Definition: error.cc:681
std::string type_name(void) const
Definition: ov.h:1047
#define H5T_NATIVE_IDX
Definition: ls-hdf5.h:209
int save_hdf5_empty(hid_t loc_id, const char *name, const dim_vector d)
Definition: ls-hdf5.cc:740
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:197
bool check_hdf5_id_type(bool warn)
Definition: oct-hdf5-id.cc:32
int current_item
Definition: ls-hdf5.h:44
static std::string make_valid_identifier(const std::string &nm)
Definition: ls-hdf5.cc:76
int length(void) const
Definition: dim-vector.h:281
bool is_diag_matrix(void) const
Definition: ov.h:556