GNU Octave  4.2.1
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-2017 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 #if defined (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 <limits>
39 #include <string>
40 #include <vector>
41 
42 #include "byte-swap.h"
43 #include "data-conv.h"
44 #include "file-ops.h"
45 #include "glob-match.h"
46 #include "lo-mappers.h"
47 #include "mach-info.h"
48 #include "oct-env.h"
49 #include "oct-time.h"
50 #include "quit.h"
51 #include "str-vec.h"
52 #include "oct-locbuf.h"
53 
54 #include "Cell.h"
55 #include "defun.h"
56 #include "error.h"
57 #include "errwarn.h"
58 #include "load-save.h"
59 #include "oct-hdf5.h"
60 #include "ovl.h"
61 #include "oct-map.h"
62 #include "ov-cell.h"
63 #include "pager.h"
64 #include "pt-exp.h"
65 #include "sysdep.h"
66 #include "unwind-prot.h"
67 #include "utils.h"
68 #include "variables.h"
69 #include "version.h"
70 #include "dMatrix.h"
71 #include "ov-lazy-idx.h"
72 
73 #include "ls-utils.h"
74 #include "ls-hdf5.h"
75 
76 #if defined (HAVE_HDF5)
77 
78 static hid_t
79 check_hdf5_id_value (octave_hdf5_id id, const char *who)
80 {
82  error ("%s: internal error: ID too large for hid_t", who);
83 
84  return static_cast<hid_t> (id);
85 }
86 
87 #endif
88 
89 hdf5_fstreambase::hdf5_fstreambase (const char *name, int mode, int /* prot */)
90  : file_id (-1), current_item (-1)
91 {
92 #if defined (HAVE_HDF5)
93 
94  if (mode & std::ios::in)
95  file_id = H5Fopen (name, H5F_ACC_RDONLY, octave_H5P_DEFAULT);
96  else if (mode & std::ios::out)
97  {
98  if (mode & std::ios::app && H5Fis_hdf5 (name) > 0)
99  file_id = H5Fopen (name, H5F_ACC_RDWR, octave_H5P_DEFAULT);
100  else
101  file_id = H5Fcreate (name, H5F_ACC_TRUNC, octave_H5P_DEFAULT,
103  }
104  if (file_id < 0)
105  std::ios::setstate (std::ios::badbit);
106 
107  current_item = 0;
108 
109 #else
110  err_disabled_feature ("hdf5_fstreambase", "HDF5");
111 #endif
112 }
113 
114 void
116 {
117 #if defined (HAVE_HDF5)
118 
119  if (file_id >= 0)
120  {
121  if (H5Fclose (file_id) < 0)
122  std::ios::setstate (std::ios::badbit);
123  file_id = -1;
124  }
125 
126 #else
127  // This shouldn't happen because construction of hdf5_fstreambase
128  // objects is supposed to be impossible if HDF5 is not available.
129 
130  panic_impossible ();
131 #endif
132 }
133 
134 void
135 hdf5_fstreambase::open (const char *name, int mode, int)
136 {
137 #if defined (HAVE_HDF5)
138 
139  clear ();
140 
141  if (mode & std::ios::in)
142  file_id = H5Fopen (name, H5F_ACC_RDONLY, octave_H5P_DEFAULT);
143  else if (mode & std::ios::out)
144  {
145  if (mode & std::ios::app && H5Fis_hdf5 (name) > 0)
146  file_id = H5Fopen (name, H5F_ACC_RDWR, octave_H5P_DEFAULT);
147  else
148  file_id = H5Fcreate (name, H5F_ACC_TRUNC, octave_H5P_DEFAULT,
150  }
151  if (file_id < 0)
152  std::ios::setstate (std::ios::badbit);
153 
154  current_item = 0;
155 
156 #else
157  // This shouldn't happen because construction of hdf5_fstreambase
158  // objects is supposed to be impossible if HDF5 is not available.
159 
160  panic_impossible ();
161 #endif
162 }
163 
164 static std::string
166 {
168 
169  size_t nm_len = nm.length ();
170 
171  if (nm_len > 0)
172  {
173  if (! isalpha (nm[0]))
174  retval += '_';
175 
176  for (size_t i = 0; i < nm_len; i++)
177  {
178  char c = nm[i];
179  retval += (isalnum (c) || c == '_') ? c : '_';
180  }
181  }
182 
183  return retval;
184 }
185 
186 // Given two compound types t1 and t2, determine whether they
187 // are compatible for reading/writing. This function only
188 // works for non-nested types composed of simple elements (ints, floats...),
189 // which is all we need it for
190 
191 bool
193 {
194 #if defined (HAVE_HDF5)
195 
196  int n;
197  if ((n = H5Tget_nmembers (t1)) != H5Tget_nmembers (t2))
198  return false;
199 
200  for (int i = 0; i < n; ++i)
201  {
202  hid_t mt1 = H5Tget_member_type (t1, i);
203  hid_t mt2 = H5Tget_member_type (t2, i);
204 
205  if (H5Tget_class (mt1) != H5Tget_class (mt2))
206  return false;
207 
208  H5Tclose (mt2);
209  H5Tclose (mt1);
210  }
211 
212  return true;
213 
214 #else
215  err_disabled_feature ("hdf5_types_compatible", "HDF5");
216 #endif
217 }
218 
219 // Return true if loc_id has the attribute named attr_name, and false
220 // otherwise.
221 
222 bool
223 hdf5_check_attr (octave_hdf5_id loc_id, const char *attr_name)
224 {
225 #if defined (HAVE_HDF5)
226 
227  bool retval = false;
228 
229  // we have to pull some shenanigans here to make sure
230  // HDF5 doesn't print out all sorts of error messages if we
231  // call H5Aopen for a non-existing attribute
232 
233  H5E_auto_t err_func;
234  void *err_func_data;
235 
236  // turn off error reporting temporarily, but save the error
237  // reporting function:
238 
239 #if defined (HAVE_HDF5_18)
240  H5Eget_auto (octave_H5E_DEFAULT, &err_func, &err_func_data);
241  H5Eset_auto (octave_H5E_DEFAULT, 0, 0);
242 #else
243  H5Eget_auto (&err_func, &err_func_data);
244  H5Eset_auto (0, 0);
245 #endif
246 
247  hid_t attr_id = H5Aopen_name (loc_id, attr_name);
248 
249  if (attr_id >= 0)
250  {
251  // successful
252  retval = true;
253  H5Aclose (attr_id);
254  }
255 
256  // restore error reporting:
257 #if defined (HAVE_HDF5_18)
258  H5Eset_auto (octave_H5E_DEFAULT, err_func, err_func_data);
259 #else
260  H5Eset_auto (err_func, err_func_data);
261 #endif
262  return retval;
263 
264 #else
265  err_disabled_feature ("hdf5_check_attr", "HDF5");
266 #endif
267 }
268 
269 bool
271  const char *attr_name, void *buf)
272 {
273 #if defined (HAVE_HDF5)
274 
275  bool retval = false;
276 
277  // we have to pull some shenanigans here to make sure
278  // HDF5 doesn't print out all sorts of error messages if we
279  // call H5Aopen for a non-existing attribute
280 
281  H5E_auto_t err_func;
282  void *err_func_data;
283 
284  // turn off error reporting temporarily, but save the error
285  // reporting function:
286 
287 #if defined (HAVE_HDF5_18)
288  H5Eget_auto (octave_H5E_DEFAULT, &err_func, &err_func_data);
289  H5Eset_auto (octave_H5E_DEFAULT, 0, 0);
290 #else
291  H5Eget_auto (&err_func, &err_func_data);
292  H5Eset_auto (0, 0);
293 #endif
294 
295  hid_t attr_id = H5Aopen_name (loc_id, attr_name);
296 
297  if (attr_id >= 0)
298  {
299  hid_t space_id = H5Aget_space (attr_id);
300 
301  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
302 
303  if (rank == 0)
304  retval = H5Aread (attr_id, type_id, buf) >= 0;
305  H5Aclose (attr_id);
306  }
307 
308  // restore error reporting:
309 #if defined (HAVE_HDF5_18)
310  H5Eset_auto (octave_H5E_DEFAULT, err_func, err_func_data);
311 #else
312  H5Eset_auto (err_func, err_func_data);
313 #endif
314  return retval;
315 
316 #else
317  err_disabled_feature ("hdf5_get_scalar_attr", "HDF5");
318 #endif
319 }
320 
321 // The following subroutines creates an HDF5 representations of the way
322 // we will store Octave complex types (pairs of floating-point numbers).
323 // NUM_TYPE is the HDF5 numeric type to use for storage (e.g.
324 // H5T_NATIVE_DOUBLE to save as 'double'). Note that any necessary
325 // conversions are handled automatically by HDF5.
326 
329 {
330 #if defined (HAVE_HDF5)
331 
332  hid_t type_id = H5Tcreate (H5T_COMPOUND, sizeof (double) * 2);
333 
334  H5Tinsert (type_id, "real", 0 * sizeof (double), num_type);
335  H5Tinsert (type_id, "imag", 1 * sizeof (double), num_type);
336 
337  return type_id;
338 
339 #else
340  err_disabled_feature ("hdf5_make_complex_type", "HDF5");
341 #endif
342 }
343 
344 #if defined (HAVE_HDF5)
345 
346 // This function is designed to be passed to H5Giterate, which calls it
347 // on each data item in an HDF5 file. For the item whose name is NAME in
348 // the group GROUP_ID, this function sets dv->tc to an Octave representation
349 // of that item. (dv must be a pointer to hdf5_callback_data.) (It also
350 // sets the other fields of dv).
351 //
352 // It returns 1 on success (in which case H5Giterate stops and returns),
353 // -1 on error, and 0 to tell H5Giterate to continue on to the next item
354 // (e.g., if NAME was a data type we don't recognize).
355 
356 static herr_t
357 hdf5_read_next_data_internal (hid_t group_id, const char *name, void *dv)
358 {
359  hdf5_callback_data *d = static_cast<hdf5_callback_data *> (dv);
360  hid_t type_id = -1;
361  hid_t type_class_id = -1;
362  hid_t data_id = -1;
363  hid_t subgroup_id = -1;
364  hid_t space_id = -1;;
365 
366  H5G_stat_t info;
367  herr_t retval = 0;
368  bool ident_valid = valid_identifier (name);
369 
370  std::string vname = name;
371 
372  // Allow identifiers as all digits so we can load lists saved by
373  // earlier versions of Octave.
374 
375  if (! ident_valid)
376  {
377  // fix the identifier, replacing invalid chars with underscores
378  vname = make_valid_identifier (vname);
379 
380  // check again (in case vname was null, empty, or some such thing):
381  ident_valid = valid_identifier (vname);
382  }
383 
384  H5Gget_objinfo (group_id, name, 1, &info);
385 
386  if (info.type == H5G_GROUP && ident_valid)
387  {
388 #if defined (HAVE_HDF5_18)
389  subgroup_id = H5Gopen (group_id, name, octave_H5P_DEFAULT);
390 #else
391  subgroup_id = H5Gopen (group_id, name);
392 #endif
393 
394  if (subgroup_id < 0)
395  {
396  retval = subgroup_id;
397  goto done;
398  }
399 
400  if (hdf5_check_attr (subgroup_id, "OCTAVE_NEW_FORMAT"))
401  {
402 #if defined (HAVE_HDF5_18)
403  data_id = H5Dopen (subgroup_id, "type", octave_H5P_DEFAULT);
404 #else
405  data_id = H5Dopen (subgroup_id, "type");
406 #endif
407 
408  if (data_id < 0)
409  {
410  retval = data_id;
411  goto done;
412  }
413 
414  type_id = H5Dget_type (data_id);
415 
416  type_class_id = H5Tget_class (type_id);
417 
418  if (type_class_id != H5T_STRING)
419  goto done;
420 
421  space_id = H5Dget_space (data_id);
422  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
423 
424  if (rank != 0)
425  goto done;
426 
427  int slen = H5Tget_size (type_id);
428  if (slen < 0)
429  goto done;
430 
431  OCTAVE_LOCAL_BUFFER (char, typ, slen);
432 
433  // create datatype for (null-terminated) string to read into:
434  hid_t st_id = H5Tcopy (H5T_C_S1);
435  H5Tset_size (st_id, slen);
436 
437  if (H5Dread (data_id, st_id, octave_H5S_ALL, octave_H5S_ALL, octave_H5P_DEFAULT,
438  typ) < 0)
439  goto done;
440 
441  H5Tclose (st_id);
442  H5Dclose (data_id);
443 
445 
446  retval = (d->tc.load_hdf5 (subgroup_id, "value") ? 1 : -1);
447 
448  // check for OCTAVE_GLOBAL attribute:
449  d->global = hdf5_check_attr (subgroup_id, "OCTAVE_GLOBAL");
450 
451  H5Gclose (subgroup_id);
452  }
453  else
454  {
455  // an HDF5 group is treated as an octave structure by
456  // default (since that preserves name information), and an
457  // octave list otherwise.
458 
459  if (hdf5_check_attr (subgroup_id, "OCTAVE_LIST"))
461  else
462  d->tc = octave_value_typeinfo::lookup_type ("struct");
463 
464  // check for OCTAVE_GLOBAL attribute:
465  d->global = hdf5_check_attr (subgroup_id, "OCTAVE_GLOBAL");
466 
467  H5Gclose (subgroup_id);
468 
469  retval = (d->tc.load_hdf5 (group_id, name) ? 1 : -1);
470  }
471 
472  }
473  else if (info.type == H5G_DATASET && ident_valid)
474  {
475  // For backwards compatibility.
476 #if defined (HAVE_HDF5_18)
477  data_id = H5Dopen (group_id, name, octave_H5P_DEFAULT);
478 #else
479  data_id = H5Dopen (group_id, name);
480 #endif
481 
482  if (data_id < 0)
483  {
484  retval = data_id;
485  goto done;
486  }
487 
488  type_id = H5Dget_type (data_id);
489 
490  type_class_id = H5Tget_class (type_id);
491 
492  if (type_class_id == H5T_FLOAT)
493  {
494  space_id = H5Dget_space (data_id);
495 
496  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
497 
498  if (rank == 0)
499  d->tc = octave_value_typeinfo::lookup_type ("scalar");
500  else
501  d->tc = octave_value_typeinfo::lookup_type ("matrix");
502 
503  H5Sclose (space_id);
504  }
505  else if (type_class_id == H5T_INTEGER)
506  {
507  // What integer type do we really have..
508  std::string int_typ;
509 #if defined (HAVE_H5T_GET_NATIVE_TYPE)
510  // FIXME: test this code and activated with an autoconf
511  // test!! It is also incorrect for 64-bit indexing!!
512 
513  switch (H5Tget_native_type (type_id, H5T_DIR_ASCEND))
514  {
515  case H5T_NATIVE_CHAR:
516  int_typ = "int8 ";
517  break;
518 
519  case H5T_NATIVE_SHORT:
520  int_typ = "int16 ";
521  break;
522 
523  case H5T_NATIVE_INT:
524  case H5T_NATIVE_LONG:
525  int_typ = "int32 ";
526  break;
527 
528  case H5T_NATIVE_LLONG:
529  int_typ = "int64 ";
530  break;
531 
532  case H5T_NATIVE_UCHAR:
533  int_typ = "uint8 ";
534  break;
535 
536  case H5T_NATIVE_USHORT:
537  int_typ = "uint16 ";
538  break;
539 
540  case H5T_NATIVE_UINT:
541  case H5T_NATIVE_ULONG:
542  int_typ = "uint32 ";
543  break;
544 
545  case H5T_NATIVE_ULLONG:
546  int_typ = "uint64 ";
547  break;
548  }
549 #else
550  hid_t int_sign = H5Tget_sign (type_id);
551 
552  if (int_sign == H5T_SGN_ERROR)
553  warning ("load: can't read '%s' (unknown datatype)", name);
554  else
555  {
556  if (int_sign == H5T_SGN_NONE)
557  int_typ.append ("u");
558  int_typ.append ("int");
559 
560  int slen = H5Tget_size (type_id);
561  if (slen < 0)
562  warning ("load: can't read '%s' (unknown datatype)", name);
563  else
564  {
565  switch (slen)
566  {
567  case 1:
568  int_typ.append ("8 ");
569  break;
570 
571  case 2:
572  int_typ.append ("16 ");
573  break;
574 
575  case 4:
576  int_typ.append ("32 ");
577  break;
578 
579  case 8:
580  int_typ.append ("64 ");
581  break;
582 
583  default:
584  warning ("load: can't read '%s' (unknown datatype)",
585  name);
586  int_typ = "";
587  break;
588  }
589  }
590  }
591 #endif
592  if (int_typ == "")
593  warning ("load: can't read '%s' (unknown datatype)", name);
594  else
595  {
596  // Matrix or scalar?
597  space_id = H5Dget_space (data_id);
598 
599  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
600 
601  if (rank == 0)
602  int_typ.append ("scalar");
603  else
604  int_typ.append ("matrix");
605 
606  d->tc = octave_value_typeinfo::lookup_type (int_typ);
607  H5Sclose (space_id);
608  }
609  }
610  else if (type_class_id == H5T_STRING)
611  d->tc = octave_value_typeinfo::lookup_type ("string");
612  else if (type_class_id == H5T_COMPOUND)
613  {
614  hid_t complex_type = hdf5_make_complex_type (H5T_NATIVE_DOUBLE);
615 
616  if (hdf5_types_compatible (type_id, complex_type))
617  {
618  // read complex matrix or scalar variable
619  space_id = H5Dget_space (data_id);
620  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
621 
622  if (rank == 0)
623  d->tc = octave_value_typeinfo::lookup_type ("complex scalar");
624  else
625  d->tc = octave_value_typeinfo::lookup_type ("complex matrix");
626 
627  H5Sclose (space_id);
628  }
629  else
630  // Assume that if its not complex its a range.
631  // If its not, it'll be rejected later in the range code.
632  d->tc = octave_value_typeinfo::lookup_type ("range");
633 
634  H5Tclose (complex_type);
635  }
636  else
637  {
638  warning ("load: can't read '%s' (unknown datatype)", name);
639  retval = 0; // unknown datatype; skip
640  return retval;
641  }
642 
643  // check for OCTAVE_GLOBAL attribute:
644  d->global = hdf5_check_attr (data_id, "OCTAVE_GLOBAL");
645 
646  H5Tclose (type_id);
647  H5Dclose (data_id);
648 
649  retval = (d->tc.load_hdf5 (group_id, name) ? 1 : -1);
650  }
651 
652  if (! ident_valid)
653  {
654  // should we attempt to handle invalid identifiers by converting
655  // bad characters to '_', say?
656  warning ("load: skipping invalid identifier '%s' in hdf5 file",
657  name);
658  }
659 
660 done:
661  if (retval < 0)
662  error ("load: error while reading hdf5 item %s", name);
663 
664  if (retval > 0)
665  {
666  // get documentation string, if any:
667  int comment_length = H5Gget_comment (group_id, name, 0, 0);
668 
669  if (comment_length > 1)
670  {
671  OCTAVE_LOCAL_BUFFER (char, tdoc, comment_length);
672  H5Gget_comment (group_id, name, comment_length, tdoc);
673  d->doc = tdoc;
674  }
675  else if (vname != name)
676  {
677  // the name was changed; store the original name
678  // as the documentation string:
679  d->doc = name;
680  }
681 
682  // copy name (actually, vname):
683  d->name = vname;
684  }
685 
686  return retval;
687 }
688 
689 #endif
690 
692 hdf5_read_next_data (octave_hdf5_id group_id, const char *name, void *dv)
693 {
694 #if defined (HAVE_HDF5)
695 
696  hid_t new_id = check_hdf5_id_value (group_id, "hdf5_read_next_data");
697 
698  return hdf5_read_next_data_internal (new_id, name, dv);
699 
700 #else
701  err_disabled_feature ("hdf5_read_next_data", "HDF5");
702 #endif
703 }
704 
706 hdf5_h5g_iterate (octave_hdf5_id loc_id, const char* name, int *idx,
707  void *operator_data)
708 {
709 #if defined (HAVE_HDF5)
710 
711  hid_t new_id = check_hdf5_id_value (loc_id, "hdf5_h5g_iterate");
712 
713  return H5Giterate (new_id, name, idx, hdf5_read_next_data_internal,
714  operator_data);
715 
716 #else
717  err_disabled_feature ("hdf5_h5g_iterate", "HDF5");
718 #endif
719 }
720 
721 // Read the next Octave variable from the stream IS, which must really be
722 // an hdf5_ifstream. Return the variable value in tc, its doc string
723 // in doc, and whether it is global in global. The return value is
724 // the name of the variable, or NULL if none were found or there was
725 // and error.
727 read_hdf5_data (std::istream& is, const std::string& /* filename */,
728  bool& global, octave_value& tc, std::string& doc,
729  const string_vector& argv, int argv_idx, int argc)
730 {
731 #if defined (HAVE_HDF5)
732 
733  check_hdf5_types ();
734 
736 
737  doc.resize (0);
738 
739  hdf5_ifstream& hs = dynamic_cast<hdf5_ifstream&> (is);
741 
742  herr_t H5Giterate_retval = -1;
743 
744  hsize_t num_obj = 0;
745 #if defined (HAVE_HDF5_18)
746  hid_t group_id = H5Gopen (hs.file_id, "/", octave_H5P_DEFAULT);
747 #else
748  hid_t group_id = H5Gopen (hs.file_id, "/");
749 #endif
750  H5Gget_num_objs (group_id, &num_obj);
751  H5Gclose (group_id);
752 
753  // For large datasets and out-of-core functionality,
754  // check if only parts of the data is requested
755  bool load_named_vars = argv_idx < argc;
756  while (load_named_vars && hs.current_item < static_cast<int> (num_obj))
757  {
758  std::vector<char> var_name;
759  bool found = false;
760  size_t len = 0;
761 
762  len = H5Gget_objname_by_idx (hs.file_id, hs.current_item, 0, 0);
763  var_name.resize (len+1);
764  H5Gget_objname_by_idx (hs.file_id, hs.current_item, &var_name[0], len+1);
765 
766  for (int i = argv_idx; i < argc; i++)
767  {
768  glob_match pattern (argv[i]);
769  if (pattern.match (std::string (&var_name[0])))
770  {
771  found = true;
772  break;
773  }
774  }
775 
776  if (found)
777  break;
778 
779  hs.current_item++;
780  }
781 
782  if (hs.current_item < static_cast<int> (num_obj))
783  H5Giterate_retval = H5Giterate (hs.file_id, "/", &hs.current_item,
785 
786  if (H5Giterate_retval > 0)
787  {
788  global = d.global;
789  tc = d.tc;
790  doc = d.doc;
791  }
792  else
793  {
794  // an error occurred (H5Giterate_retval < 0) or there are no
795  // more datasets print an error message if retval < 0?
796  // hdf5_read_next_data already printed one, probably.
797  }
798 
799  if (! d.name.empty ())
800  retval = d.name;
801 
802  return retval;
803 
804 #else
805  err_disabled_feature ("read_hdf5_data", "HDF5");
806 #endif
807 }
808 
809 // Add an attribute named attr_name to loc_id (a simple scalar
810 // attribute with value 1). Return value is >= 0 on success.
812 hdf5_add_attr (octave_hdf5_id loc_id, const char *attr_name)
813 {
814 #if defined (HAVE_HDF5)
815 
816  herr_t retval = 0;
817 
818  hid_t as_id = H5Screate (H5S_SCALAR);
819 
820  if (as_id >= 0)
821  {
822 #if defined (HAVE_HDF5_18)
823  hid_t a_id = H5Acreate (loc_id, attr_name, H5T_NATIVE_UCHAR,
825 #else
826  hid_t a_id = H5Acreate (loc_id, attr_name,
827  H5T_NATIVE_UCHAR, as_id, octave_H5P_DEFAULT);
828 #endif
829  if (a_id >= 0)
830  {
831  unsigned char attr_val = 1;
832 
833  retval = H5Awrite (a_id, H5T_NATIVE_UCHAR, &attr_val);
834 
835  H5Aclose (a_id);
836  }
837  else
838  retval = a_id;
839 
840  H5Sclose (as_id);
841  }
842  else
843  retval = as_id;
844 
845  return retval;
846 
847 #else
848  err_disabled_feature ("hdf5_add_attr", "HDF5");
849 #endif
850 }
851 
854  const char *attr_name, void *buf)
855 {
856 #if defined (HAVE_HDF5)
857 
858  herr_t retval = 0;
859 
860  hid_t as_id = H5Screate (H5S_SCALAR);
861 
862  if (as_id >= 0)
863  {
864 #if defined (HAVE_HDF5_18)
865  hid_t a_id = H5Acreate (loc_id, attr_name, type_id,
867 #else
868  hid_t a_id = H5Acreate (loc_id, attr_name,
869  type_id, as_id, octave_H5P_DEFAULT);
870 #endif
871  if (a_id >= 0)
872  {
873  retval = H5Awrite (a_id, type_id, buf);
874 
875  H5Aclose (a_id);
876  }
877  else
878  retval = a_id;
879 
880  H5Sclose (as_id);
881  }
882  else
883  retval = as_id;
884 
885  return retval;
886 
887 #else
888  err_disabled_feature ("hdf5_add_scalar_attr", "HDF5");
889 #endif
890 }
891 
892 // Save an empty matrix, if needed. Returns
893 // > 0 Saved empty matrix
894 // = 0 Not an empty matrix; did nothing
895 // < 0 Error condition
896 int
897 save_hdf5_empty (octave_hdf5_id loc_id, const char *name, const dim_vector d)
898 {
899 #if defined (HAVE_HDF5)
900 
901  hsize_t sz = d.length ();
903  bool empty = false;
904  hid_t space_hid = -1;
905  hid_t data_hid = -1;
906  int retval;
907  for (hsize_t i = 0; i < sz; i++)
908  {
909  dims[i] = d(i);
910  if (dims[i] < 1)
911  empty = true;
912  }
913 
914  if (! empty)
915  return 0;
916 
917  space_hid = H5Screate_simple (1, &sz, 0);
918  if (space_hid < 0) return space_hid;
919 #if defined (HAVE_HDF5_18)
920  data_hid = H5Dcreate (loc_id, name, H5T_NATIVE_IDX, space_hid,
922 #else
923  data_hid = H5Dcreate (loc_id, name, H5T_NATIVE_IDX, space_hid,
925 #endif
926  if (data_hid < 0)
927  {
928  H5Sclose (space_hid);
929  return data_hid;
930  }
931 
932  retval = H5Dwrite (data_hid, H5T_NATIVE_IDX, octave_H5S_ALL, octave_H5S_ALL,
933  octave_H5P_DEFAULT, dims) >= 0;
934 
935  H5Dclose (data_hid);
936  H5Sclose (space_hid);
937 
938  if (retval >= 0)
939  retval = hdf5_add_attr (loc_id, "OCTAVE_EMPTY_MATRIX");
940 
941  return (retval == 0 ? 1 : retval);
942 
943 #else
944  err_disabled_feature ("save_hdf5_empty", "HDF5");
945 #endif
946 }
947 
948 // Load an empty matrix, if needed. Returns
949 // > 0 loaded empty matrix, dimensions returned
950 // = 0 Not an empty matrix; did nothing
951 // < 0 Error condition
952 int
954 {
955 #if defined (HAVE_HDF5)
956 
957  if (! hdf5_check_attr (loc_id, "OCTAVE_EMPTY_MATRIX"))
958  return 0;
959 
960  hsize_t hdims, maxdims;
961 #if defined (HAVE_HDF5_18)
962  hid_t data_hid = H5Dopen (loc_id, name, octave_H5P_DEFAULT);
963 #else
964  hid_t data_hid = H5Dopen (loc_id, name);
965 #endif
966  hid_t space_id = H5Dget_space (data_hid);
967  H5Sget_simple_extent_dims (space_id, &hdims, &maxdims);
968  int retval;
969 
971 
972  retval = H5Dread (data_hid, H5T_NATIVE_IDX, octave_H5S_ALL, octave_H5S_ALL,
974  if (retval >= 0)
975  {
976  d.resize (hdims);
977  for (hsize_t i = 0; i < hdims; i++)
978  d(i) = dims[i];
979  }
980 
981  H5Sclose (space_id);
982  H5Dclose (data_hid);
983 
984  return (retval == 0 ? hdims : retval);
985 
986 #else
987  err_disabled_feature ("load_hdf5_empty", "HDF5");
988 #endif
989 }
990 
991 // save_type_to_hdf5 is not currently used, since hdf5 doesn't yet support
992 // automatic float<->integer conversions:
993 
994 // return the HDF5 type id corresponding to the Octave save_type
995 
998 {
999 #if defined (HAVE_HDF5)
1000 # if defined (HAVE_HDF5_INT2FLOAT_CONVERSIONS)
1001 
1002  switch (st)
1003  {
1004  case LS_U_CHAR:
1005  return H5T_NATIVE_UCHAR;
1006 
1007  case LS_U_SHORT:
1008  return H5T_NATIVE_USHORT;
1009 
1010  case LS_U_INT:
1011  return H5T_NATIVE_UINT;
1012 
1013  case LS_CHAR:
1014  return H5T_NATIVE_CHAR;
1015 
1016  case LS_SHORT:
1017  return H5T_NATIVE_SHORT;
1018 
1019  case LS_INT:
1020  return H5T_NATIVE_INT;
1021 
1022  case LS_FLOAT:
1023  return H5T_NATIVE_FLOAT;
1024 
1025  case LS_DOUBLE:
1026  default:
1027  return H5T_NATIVE_DOUBLE;
1028  }
1029 
1030 # else
1031 
1032  octave_unused_parameter (st);
1033 
1034  return -1;
1035 
1036 # endif
1037 
1038 #else
1039 
1040  octave_unused_parameter (st);
1041 
1042  err_disabled_feature ("save_type_to_hdf5", "HDF5");
1043 
1044 #endif
1045 }
1046 
1047 // Add the data from TC to the HDF5 location loc_id, which could
1048 // be either a file or a group within a file. Return true if
1049 // successful. This function calls itself recursively for lists
1050 // (stored as HDF5 groups).
1051 
1052 bool
1054  const std::string& name, const std::string& doc,
1055  bool mark_as_global, bool save_as_floats)
1056 {
1057 #if defined (HAVE_HDF5)
1058 
1059  hsize_t dims[3];
1060  hid_t type_id, space_id, data_id, data_type_id;
1061  type_id = space_id = data_id = data_type_id = -1;
1062 
1063  bool retval = false;
1064  octave_value val = tc;
1065  // FIXME: diagonal & permutation matrices currently don't know how to save
1066  // themselves, so we convert them first to normal matrices using A = A(:,:).
1067  // This is a temporary hack.
1068  if (val.is_diag_matrix () || val.is_perm_matrix ()
1070  val = val.full_value ();
1071 
1072  std::string t = val.type_name ();
1073 #if defined (HAVE_HDF5_18)
1074  data_id = H5Gcreate (loc_id, name.c_str (), octave_H5P_DEFAULT,
1076 #else
1077  data_id = H5Gcreate (loc_id, name.c_str (), 0);
1078 #endif
1079  if (data_id < 0)
1080  goto error_cleanup;
1081 
1082  // attach the type of the variable
1083  type_id = H5Tcopy (H5T_C_S1); H5Tset_size (type_id, t.length () + 1);
1084  if (type_id < 0)
1085  goto error_cleanup;
1086 
1087  dims[0] = 0;
1088  space_id = H5Screate_simple (0 , dims, 0);
1089  if (space_id < 0)
1090  goto error_cleanup;
1091 #if defined (HAVE_HDF5_18)
1092  data_type_id = H5Dcreate (data_id, "type", type_id, space_id,
1093  octave_H5P_DEFAULT, octave_H5P_DEFAULT,
1094  octave_H5P_DEFAULT);
1095 #else
1096  data_type_id = H5Dcreate (data_id, "type", type_id, space_id,
1097  octave_H5P_DEFAULT);
1098 #endif
1099  if (data_type_id < 0
1100  || H5Dwrite (data_type_id, type_id, octave_H5S_ALL, octave_H5S_ALL,
1101  octave_H5P_DEFAULT, t.c_str ()) < 0)
1102  goto error_cleanup;
1103 
1104  // Now call the real function to save the variable
1105  retval = val.save_hdf5 (data_id, "value", save_as_floats);
1106 
1107  // attach doc string as comment:
1108  if (retval && doc.length () > 0
1109  && H5Gset_comment (loc_id, name.c_str (), doc.c_str ()) < 0)
1110  retval = false;
1111 
1112  // if it's global, add an attribute "OCTAVE_GLOBAL" with value 1
1113  if (retval && mark_as_global)
1114  retval = hdf5_add_attr (data_id, "OCTAVE_GLOBAL") >= 0;
1115 
1116  // We are saving in the new variable format, so mark it
1117  if (retval)
1118  retval = hdf5_add_attr (data_id, "OCTAVE_NEW_FORMAT") >= 0;
1119 
1120 error_cleanup:
1121 
1122  if (data_type_id >= 0)
1123  H5Dclose (data_type_id);
1124 
1125  if (type_id >= 0)
1126  H5Tclose (type_id);
1127 
1128  if (space_id >= 0)
1129  H5Sclose (space_id);
1130 
1131  if (data_id >= 0)
1132  H5Gclose (data_id);
1133 
1134  if (! retval)
1135  error ("save: error while writing '%s' to hdf5 file", name.c_str ());
1136 
1137  return retval;
1138 
1139 #else
1140  err_disabled_feature ("add_hdf5_data", "HDF5");
1141 #endif
1142 }
1143 
1144 // Write data from TC in HDF5 (binary) format to the stream OS,
1145 // which must be an hdf5_ofstream, returning true on success.
1146 
1147 bool
1148 save_hdf5_data (std::ostream& os, const octave_value& tc,
1149  const std::string& name, const std::string& doc,
1150  bool mark_as_global, bool save_as_floats)
1151 {
1152 #if defined (HAVE_HDF5)
1153 
1154  check_hdf5_types ();
1155 
1156  hdf5_ofstream& hs = dynamic_cast<hdf5_ofstream&> (os);
1157 
1158  return add_hdf5_data (hs.file_id, tc, name, doc,
1159  mark_as_global, save_as_floats);
1160 
1161 #else
1162  err_disabled_feature ("save_hdf5_data", "HDF5");
1163 #endif
1164 }
1165 
1166 #endif
save_type
Definition: data-conv.h:85
uint32_t id
Definition: graphics.cc:11587
void close(void)
Definition: ls-hdf5.cc:115
octave_hdf5_err hdf5_add_scalar_attr(octave_hdf5_id loc_id, octave_hdf5_id type_id, const char *attr_name, void *buf)
Definition: ls-hdf5.cc:853
static int static_type_id(void)
Definition: ov-lazy-idx.h:252
octave_value full_value(void) const
Definition: ov.h:386
bool save_hdf5(octave_hdf5_id loc_id, const char *name, bool save_as_floats)
Definition: ov.h:1288
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:727
octave_value tc
Definition: ls-hdf5.h:107
identity matrix If supplied two scalar respectively For allows like xample val
Definition: data.cc:5068
const octave_hdf5_id octave_H5S_ALL
int argc
Definition: load-save.cc:633
int save_hdf5_empty(octave_hdf5_id loc_id, const char *name, const dim_vector d)
Definition: ls-hdf5.cc:897
Return the CPU time used by your Octave session The first output is the total time spent executing your process and is equal to the sum of second and third which are the number of CPU seconds spent executing in user mode and the number of CPU seconds spent executing in system mode
Definition: data.cc:6386
std::string name
Definition: ls-hdf5.h:101
const octave_hdf5_id octave_H5E_DEFAULT
void resize(int n, int fill_value=0)
Definition: dim-vector.h:316
void error(const char *fmt,...)
Definition: error.cc:570
bool is_perm_matrix(void) const
Definition: ov.h:575
int type_id(void) const
Definition: ov.h:1230
octave_value resize(const dim_vector &dv, bool fill=false) const
Definition: ov.h:524
int load_hdf5_empty(octave_hdf5_id loc_id, const char *name, dim_vector &d)
Definition: ls-hdf5.cc:953
OCTAVE_EXPORT octave_value_list return the number of command line arguments passed to Octave If called with the optional argument the function t
Definition: ov-usr-fcn.cc:935
int octave_hdf5_err
F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T F77_REAL F77_REAL &F77_RET_T F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
bool hdf5_get_scalar_attr(octave_hdf5_id loc_id, octave_hdf5_id type_id, const char *attr_name, void *buf)
Definition: ls-hdf5.cc:270
std::string doc
Definition: ls-hdf5.h:110
string_vector argv
Definition: load-save.cc:635
OCTAVE_EXPORT octave_value_list search each directory of the loadpath for element of the cell array and return the first that matches If the second optional argument return a cell array containing the list of all files that have the same name in the path If no files are found
Definition: utils.cc:302
static octave_value lookup_type(const std::string &nm)
Definition: ov-typeinfo.h:104
done
Definition: syscalls.cc:248
create a structure array and initialize its values The dimensions of each cell array of values must match Singleton cells and non cell values are repeated so that they fill the entire array If the cells are empty
Definition: ov-struct.cc:1688
OCTAVE_EXPORT octave_value_list any number nd example oindent prints the prompt xample Pick a any number!nd example oindent and waits for the user to enter a value The string entered by the user is evaluated as an so it may be a literal a variable name
Definition: input.cc:871
OCTAVE_EXPORT octave_value_list isdir nd deftypefn *std::string nm
Definition: utils.cc:941
bool valid_identifier(const char *s)
Definition: utils.cc:74
bool hdf5_types_compatible(octave_hdf5_id t1, octave_hdf5_id t2)
Definition: ls-hdf5.cc:192
bool load_hdf5(octave_hdf5_id loc_id, const char *name)
Definition: ov.h:1292
bool save_as_floats
Definition: load-save.cc:1581
octave_hdf5_id save_type_to_hdf5(save_type st)
Definition: ls-hdf5.cc:997
octave_hdf5_err hdf5_h5g_iterate(octave_hdf5_id loc_id, const char *name, int *idx, void *operator_data)
Definition: ls-hdf5.cc:706
octave_value retval
Definition: data.cc:6294
#define panic_impossible()
Definition: error.h:40
bool hdf5_check_attr(octave_hdf5_id loc_id, const char *attr_name)
Definition: ls-hdf5.cc:223
bool match(const std::string &str) const
Definition: glob-match.cc:32
int64_t octave_hdf5_id
octave_hdf5_err hdf5_read_next_data(octave_hdf5_id group_id, const char *name, void *dv)
Definition: ls-hdf5.cc:692
octave_idx_type length(void) const
Definition: ov.cc:1623
sz
Definition: data.cc:5342
the sparsity preserving column transformation such that that defines the pivoting threshold can be given in which case it defines the c
Definition: lu.cc:138
the exceeded dimensions are set to if fewer subscripts than dimensions are the exceeding dimensions are merged into the final requested dimension For consider the following dims
Definition: sub2ind.cc:255
static hid_t check_hdf5_id_value(octave_hdf5_id id, const char *who)
Definition: ls-hdf5.cc:79
octave_hdf5_err hdf5_add_attr(octave_hdf5_id loc_id, const char *attr_name)
Definition: ls-hdf5.cc:812
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:1148
void warning(const char *fmt,...)
Definition: error.cc:788
std::string type_name(void) const
Definition: ov.h:1232
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:228
static herr_t hdf5_read_next_data_internal(hid_t group_id, const char *name, void *dv)
Definition: ls-hdf5.cc:357
bool check_hdf5_types(bool warn)
=val(i)}if ode{val(i)}occurs in table i
Definition: lookup.cc:239
is longer than or if then or only for unique occurrences of the complete pattern(false).The default is true.If a cell array of strings ar
Definition: strfind.cc:192
octave_hdf5_id file_id
Definition: ls-hdf5.h:41
#define H5T_NATIVE_IDX
Definition: oct-hdf5.h:39
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:200
const octave_hdf5_id octave_H5P_DEFAULT
write the output to stdout if nargout is
Definition: load-save.cc:1576
int current_item
Definition: ls-hdf5.h:44
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:87
octave_hdf5_id hdf5_make_complex_type(octave_hdf5_id num_type)
Definition: ls-hdf5.cc:328
bool add_hdf5_data(octave_hdf5_id 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:1053
void open(const char *name, int mode, int)
Definition: ls-hdf5.cc:135
static std::string make_valid_identifier(const std::string &nm)
Definition: ls-hdf5.cc:165
static void clear(octave::dynamic_library &oct_file)
Definition: dynamic-ld.cc:230
void err_disabled_feature(const std::string &fcn, const std::string &feature, const std::string &pkg)
Definition: errwarn.cc:50
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:854
int length(void) const
Number of dimensions.
Definition: dim-vector.h:310
dim_vector dv
Definition: sub2ind.cc:263
bool is_diag_matrix(void) const
Definition: ov.h:572