GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
ls-hdf5.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2018 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
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License 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 <https://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 <cctype>
32 
33 #include <iomanip>
34 #include <iostream>
35 #include <limits>
36 #include <string>
37 #include <vector>
38 
39 #include "byte-swap.h"
40 #include "data-conv.h"
41 #include "file-ops.h"
42 #include "glob-match.h"
43 #include "lo-mappers.h"
44 #include "mach-info.h"
45 #include "oct-env.h"
46 #include "oct-time.h"
47 #include "quit.h"
48 #include "str-vec.h"
49 #include "oct-locbuf.h"
50 
51 #include "Cell.h"
52 #include "defun.h"
53 #include "error.h"
54 #include "errwarn.h"
55 #include "interpreter-private.h"
56 #include "load-save.h"
57 #include "oct-hdf5.h"
58 #include "ovl.h"
59 #include "oct-map.h"
60 #include "ov-cell.h"
61 #include "pager.h"
62 #include "pt-exp.h"
63 #include "sysdep.h"
64 #include "unwind-prot.h"
65 #include "utils.h"
66 #include "variables.h"
67 #include "version.h"
68 #include "dMatrix.h"
69 #include "ov-lazy-idx.h"
70 
71 #include "ls-utils.h"
72 #include "ls-hdf5.h"
73 
74 #if defined (HAVE_HDF5)
75 
76 static hid_t
77 check_hdf5_id_value (octave_hdf5_id id, const char *who)
78 {
80  error ("%s: internal error: ID too large for hid_t", who);
81 
82  return static_cast<hid_t> (id);
83 }
84 
85 #endif
86 
87 hdf5_fstreambase::hdf5_fstreambase (const char *name, int mode, int /* prot */)
88  : file_id (-1), current_item (-1)
89 {
90 #if defined (HAVE_HDF5)
91 
92  if (mode & std::ios::in)
93  file_id = H5Fopen (name, H5F_ACC_RDONLY, octave_H5P_DEFAULT);
94  else if (mode & std::ios::out)
95  {
96  if (mode & std::ios::app && H5Fis_hdf5 (name) > 0)
97  file_id = H5Fopen (name, H5F_ACC_RDWR, octave_H5P_DEFAULT);
98  else
99  file_id = H5Fcreate (name, H5F_ACC_TRUNC, octave_H5P_DEFAULT,
101  }
102  if (file_id < 0)
103  std::ios::setstate (std::ios::badbit);
104 
105  current_item = 0;
106 
107 #else
108  err_disabled_feature ("hdf5_fstreambase", "HDF5");
109 #endif
110 }
111 
112 void
114 {
115 #if defined (HAVE_HDF5)
116 
117  if (file_id >= 0)
118  {
119  if (H5Fclose (file_id) < 0)
120  std::ios::setstate (std::ios::badbit);
121  file_id = -1;
122  }
123 
124 #else
125  // This shouldn't happen because construction of hdf5_fstreambase
126  // objects is supposed to be impossible if HDF5 is not available.
127 
128  panic_impossible ();
129 #endif
130 }
131 
132 void
133 hdf5_fstreambase::open (const char *name, int mode, int)
134 {
135 #if defined (HAVE_HDF5)
136 
137  clear ();
138 
139  if (mode & std::ios::in)
140  file_id = H5Fopen (name, H5F_ACC_RDONLY, octave_H5P_DEFAULT);
141  else if (mode & std::ios::out)
142  {
143  if (mode & std::ios::app && H5Fis_hdf5 (name) > 0)
144  file_id = H5Fopen (name, H5F_ACC_RDWR, octave_H5P_DEFAULT);
145  else
146  file_id = H5Fcreate (name, H5F_ACC_TRUNC, octave_H5P_DEFAULT,
148  }
149  if (file_id < 0)
150  std::ios::setstate (std::ios::badbit);
151 
152  current_item = 0;
153 
154 #else
155  // This shouldn't happen because construction of hdf5_fstreambase
156  // objects is supposed to be impossible if HDF5 is not available.
157 
158  panic_impossible ();
159 #endif
160 }
161 
162 static std::string
164 {
166 
167  size_t nm_len = nm.length ();
168 
169  if (nm_len > 0)
170  {
171  if (! isalpha (nm[0]))
172  retval += '_';
173 
174  for (size_t i = 0; i < nm_len; i++)
175  {
176  char c = nm[i];
177  retval += (isalnum (c) || c == '_') ? c : '_';
178  }
179  }
180 
181  return retval;
182 }
183 
184 // Given two compound types t1 and t2, determine whether they
185 // are compatible for reading/writing. This function only
186 // works for non-nested types composed of simple elements (ints, floats...),
187 // which is all we need it for
188 
189 bool
191 {
192 #if defined (HAVE_HDF5)
193 
194  int n;
195  if ((n = H5Tget_nmembers (t1)) != H5Tget_nmembers (t2))
196  return false;
197 
198  for (int i = 0; i < n; ++i)
199  {
200  hid_t mt1 = H5Tget_member_type (t1, i);
201  hid_t mt2 = H5Tget_member_type (t2, i);
202 
203  if (H5Tget_class (mt1) != H5Tget_class (mt2))
204  return false;
205 
206  H5Tclose (mt2);
207  H5Tclose (mt1);
208  }
209 
210  return true;
211 
212 #else
213  err_disabled_feature ("hdf5_types_compatible", "HDF5");
214 #endif
215 }
216 
217 // Return true if loc_id has the attribute named attr_name, and false
218 // otherwise.
219 
220 bool
221 hdf5_check_attr (octave_hdf5_id loc_id, const char *attr_name)
222 {
223 #if defined (HAVE_HDF5)
224 
225  bool retval = false;
226 
227  // we have to pull some shenanigans here to make sure
228  // HDF5 doesn't print out all sorts of error messages if we
229  // call H5Aopen for a non-existing attribute
230 
231  H5E_auto_t err_func;
232  void *err_func_data;
233 
234  // turn off error reporting temporarily, but save the error
235  // reporting function:
236 
237 #if defined (HAVE_HDF5_18)
238  H5Eget_auto (octave_H5E_DEFAULT, &err_func, &err_func_data);
239  H5Eset_auto (octave_H5E_DEFAULT, nullptr, nullptr);
240 #else
241  H5Eget_auto (&err_func, &err_func_data);
242  H5Eset_auto (nullptr, nullptr);
243 #endif
244 
245  hid_t attr_id = H5Aopen_name (loc_id, attr_name);
246 
247  if (attr_id >= 0)
248  {
249  // successful
250  retval = true;
251  H5Aclose (attr_id);
252  }
253 
254  // restore error reporting:
255 #if defined (HAVE_HDF5_18)
256  H5Eset_auto (octave_H5E_DEFAULT, err_func, err_func_data);
257 #else
258  H5Eset_auto (err_func, err_func_data);
259 #endif
260  return retval;
261 
262 #else
263  err_disabled_feature ("hdf5_check_attr", "HDF5");
264 #endif
265 }
266 
267 bool
269  const char *attr_name, void *buf)
270 {
271 #if defined (HAVE_HDF5)
272 
273  bool retval = false;
274 
275  // we have to pull some shenanigans here to make sure
276  // HDF5 doesn't print out all sorts of error messages if we
277  // call H5Aopen for a non-existing attribute
278 
279  H5E_auto_t err_func;
280  void *err_func_data;
281 
282  // turn off error reporting temporarily, but save the error
283  // reporting function:
284 
285 #if defined (HAVE_HDF5_18)
286  H5Eget_auto (octave_H5E_DEFAULT, &err_func, &err_func_data);
287  H5Eset_auto (octave_H5E_DEFAULT, nullptr, nullptr);
288 #else
289  H5Eget_auto (&err_func, &err_func_data);
290  H5Eset_auto (nullptr, nullptr);
291 #endif
292 
293  hid_t attr_id = H5Aopen_name (loc_id, attr_name);
294 
295  if (attr_id >= 0)
296  {
297  hid_t space_id = H5Aget_space (attr_id);
298 
299  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
300 
301  if (rank == 0)
302  retval = H5Aread (attr_id, type_id, buf) >= 0;
303  H5Aclose (attr_id);
304  }
305 
306  // restore error reporting:
307 #if defined (HAVE_HDF5_18)
308  H5Eset_auto (octave_H5E_DEFAULT, err_func, err_func_data);
309 #else
310  H5Eset_auto (err_func, err_func_data);
311 #endif
312  return retval;
313 
314 #else
315  err_disabled_feature ("hdf5_get_scalar_attr", "HDF5");
316 #endif
317 }
318 
319 // The following subroutines creates an HDF5 representations of the way
320 // we will store Octave complex types (pairs of floating-point numbers).
321 // NUM_TYPE is the HDF5 numeric type to use for storage (e.g.
322 // H5T_NATIVE_DOUBLE to save as 'double'). Note that any necessary
323 // conversions are handled automatically by HDF5.
324 
327 {
328 #if defined (HAVE_HDF5)
329 
330  hid_t type_id = H5Tcreate (H5T_COMPOUND, sizeof (double) * 2);
331 
332  H5Tinsert (type_id, "real", 0 * sizeof (double), num_type);
333  H5Tinsert (type_id, "imag", 1 * sizeof (double), num_type);
334 
335  return type_id;
336 
337 #else
338  err_disabled_feature ("hdf5_make_complex_type", "HDF5");
339 #endif
340 }
341 
342 #if defined (HAVE_HDF5)
343 
344 // This function is designed to be passed to H5Giterate, which calls it
345 // on each data item in an HDF5 file. For the item whose name is NAME in
346 // the group GROUP_ID, this function sets dv->tc to an Octave representation
347 // of that item. (dv must be a pointer to hdf5_callback_data.) (It also
348 // sets the other fields of dv).
349 //
350 // It returns 1 on success (in which case H5Giterate stops and returns),
351 // -1 on error, and 0 to tell H5Giterate to continue on to the next item
352 // (e.g., if NAME was a data type we don't recognize).
353 
354 static herr_t
355 hdf5_read_next_data_internal (hid_t group_id, const char *name, void *dv)
356 {
357  hdf5_callback_data *d = static_cast<hdf5_callback_data *> (dv);
358  hid_t type_id = -1;
359  hid_t type_class_id = -1;
360  hid_t data_id = -1;
361  hid_t subgroup_id = -1;
362  hid_t space_id = -1;;
363 
364  H5G_stat_t info;
365  herr_t retval = 0;
366  bool ident_valid = valid_identifier (name);
367 
368  std::string vname = name;
369 
370  octave::type_info& type_info
371  = octave::__get_type_info__ ("hdf5_read_next_data_internal");
372 
373  // Allow identifiers as all digits so we can load lists saved by
374  // earlier versions of Octave.
375 
376  if (! ident_valid)
377  {
378  // fix the identifier, replacing invalid chars with underscores
379  vname = make_valid_identifier (vname);
380 
381  // check again (in case vname was null, empty, or some such thing):
382  ident_valid = valid_identifier (vname);
383  }
384 
385  H5Gget_objinfo (group_id, name, 1, &info);
386 
387  if (info.type == H5G_GROUP && ident_valid)
388  {
389 #if defined (HAVE_HDF5_18)
390  subgroup_id = H5Gopen (group_id, name, octave_H5P_DEFAULT);
391 #else
392  subgroup_id = H5Gopen (group_id, name);
393 #endif
394 
395  if (subgroup_id < 0)
396  {
397  retval = subgroup_id;
398  goto done;
399  }
400 
401  if (hdf5_check_attr (subgroup_id, "OCTAVE_NEW_FORMAT"))
402  {
403 #if defined (HAVE_HDF5_18)
404  data_id = H5Dopen (subgroup_id, "type", octave_H5P_DEFAULT);
405 #else
406  data_id = H5Dopen (subgroup_id, "type");
407 #endif
408 
409  if (data_id < 0)
410  {
411  retval = data_id;
412  goto done;
413  }
414 
415  type_id = H5Dget_type (data_id);
416 
417  type_class_id = H5Tget_class (type_id);
418 
419  if (type_class_id != H5T_STRING)
420  goto done;
421 
422  space_id = H5Dget_space (data_id);
423  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
424 
425  if (rank != 0)
426  goto done;
427 
428  int slen = H5Tget_size (type_id);
429  if (slen < 0)
430  goto done;
431 
432  OCTAVE_LOCAL_BUFFER (char, typ, slen);
433 
434  // create datatype for (null-terminated) string to read into:
435  hid_t st_id = H5Tcopy (H5T_C_S1);
436  H5Tset_size (st_id, slen);
437 
438  if (H5Dread (data_id, st_id, octave_H5S_ALL, octave_H5S_ALL, octave_H5P_DEFAULT,
439  typ) < 0)
440  goto done;
441 
442  H5Tclose (st_id);
443  H5Dclose (data_id);
444 
445  d->tc = type_info.lookup_type (typ);
446 
447  retval = (d->tc.load_hdf5 (subgroup_id, "value") ? 1 : -1);
448 
449  // check for OCTAVE_GLOBAL attribute:
450  d->global = hdf5_check_attr (subgroup_id, "OCTAVE_GLOBAL");
451 
452  H5Gclose (subgroup_id);
453  }
454  else
455  {
456  // an HDF5 group is treated as an octave structure by
457  // default (since that preserves name information), and an
458  // octave list otherwise.
459 
460  if (hdf5_check_attr (subgroup_id, "OCTAVE_LIST"))
461  d->tc = type_info.lookup_type ("list");
462  else
463  d->tc = type_info.lookup_type ("struct");
464 
465  // check for OCTAVE_GLOBAL attribute:
466  d->global = hdf5_check_attr (subgroup_id, "OCTAVE_GLOBAL");
467 
468  H5Gclose (subgroup_id);
469 
470  retval = (d->tc.load_hdf5 (group_id, name) ? 1 : -1);
471  }
472 
473  }
474  else if (info.type == H5G_DATASET && ident_valid)
475  {
476  // For backwards compatibility.
477 #if defined (HAVE_HDF5_18)
478  data_id = H5Dopen (group_id, name, octave_H5P_DEFAULT);
479 #else
480  data_id = H5Dopen (group_id, name);
481 #endif
482 
483  if (data_id < 0)
484  {
485  retval = data_id;
486  goto done;
487  }
488 
489  type_id = H5Dget_type (data_id);
490 
491  type_class_id = H5Tget_class (type_id);
492 
493  if (type_class_id == H5T_FLOAT)
494  {
495  space_id = H5Dget_space (data_id);
496 
497  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
498 
499  if (rank == 0)
500  d->tc = type_info.lookup_type ("scalar");
501  else
502  d->tc = type_info.lookup_type ("matrix");
503 
504  H5Sclose (space_id);
505  }
506  else if (type_class_id == H5T_INTEGER)
507  {
508  // What integer type do we really have..
509  std::string int_typ;
510 #if defined (HAVE_H5T_GET_NATIVE_TYPE)
511  // FIXME: test this code and activated with an autoconf
512  // test!! It is also incorrect for 64-bit indexing!!
513 
514  switch (H5Tget_native_type (type_id, H5T_DIR_ASCEND))
515  {
516  case H5T_NATIVE_CHAR:
517  int_typ = "int8 ";
518  break;
519 
520  case H5T_NATIVE_SHORT:
521  int_typ = "int16 ";
522  break;
523 
524  case H5T_NATIVE_INT:
525  case H5T_NATIVE_LONG:
526  int_typ = "int32 ";
527  break;
528 
529  case H5T_NATIVE_LLONG:
530  int_typ = "int64 ";
531  break;
532 
533  case H5T_NATIVE_UCHAR:
534  int_typ = "uint8 ";
535  break;
536 
537  case H5T_NATIVE_USHORT:
538  int_typ = "uint16 ";
539  break;
540 
541  case H5T_NATIVE_UINT:
542  case H5T_NATIVE_ULONG:
543  int_typ = "uint32 ";
544  break;
545 
546  case H5T_NATIVE_ULLONG:
547  int_typ = "uint64 ";
548  break;
549  }
550 #else
551  hid_t int_sign = H5Tget_sign (type_id);
552 
553  if (int_sign == H5T_SGN_ERROR)
554  warning ("load: can't read '%s' (unknown datatype)", name);
555  else
556  {
557  if (int_sign == H5T_SGN_NONE)
558  int_typ.push_back ('u');
559  int_typ.append ("int");
560 
561  int slen = H5Tget_size (type_id);
562  if (slen < 0)
563  warning ("load: can't read '%s' (unknown datatype)", name);
564  else
565  {
566  switch (slen)
567  {
568  case 1:
569  int_typ.append ("8 ");
570  break;
571 
572  case 2:
573  int_typ.append ("16 ");
574  break;
575 
576  case 4:
577  int_typ.append ("32 ");
578  break;
579 
580  case 8:
581  int_typ.append ("64 ");
582  break;
583 
584  default:
585  warning ("load: can't read '%s' (unknown datatype)",
586  name);
587  int_typ = "";
588  break;
589  }
590  }
591  }
592 #endif
593  if (int_typ == "")
594  warning ("load: can't read '%s' (unknown datatype)", name);
595  else
596  {
597  // Matrix or scalar?
598  space_id = H5Dget_space (data_id);
599 
600  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
601 
602  if (rank == 0)
603  int_typ.append ("scalar");
604  else
605  int_typ.append ("matrix");
606 
607  d->tc = type_info.lookup_type (int_typ);
608  H5Sclose (space_id);
609  }
610  }
611  else if (type_class_id == H5T_STRING)
612  d->tc = type_info.lookup_type ("string");
613  else if (type_class_id == H5T_COMPOUND)
614  {
615  hid_t complex_type = hdf5_make_complex_type (H5T_NATIVE_DOUBLE);
616 
617  if (hdf5_types_compatible (type_id, complex_type))
618  {
619  // read complex matrix or scalar variable
620  space_id = H5Dget_space (data_id);
621  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
622 
623  if (rank == 0)
624  d->tc = type_info.lookup_type ("complex scalar");
625  else
626  d->tc = type_info.lookup_type ("complex matrix");
627 
628  H5Sclose (space_id);
629  }
630  else
631  // Assume that if its not complex its a range.
632  // If its not, it'll be rejected later in the range code.
633  d->tc = type_info.lookup_type ("range");
634 
635  H5Tclose (complex_type);
636  }
637  else
638  {
639  warning ("load: can't read '%s' (unknown datatype)", name);
640  retval = 0; // unknown datatype; skip
641  return retval;
642  }
643 
644  // check for OCTAVE_GLOBAL attribute:
645  d->global = hdf5_check_attr (data_id, "OCTAVE_GLOBAL");
646 
647  H5Tclose (type_id);
648  H5Dclose (data_id);
649 
650  retval = (d->tc.load_hdf5 (group_id, name) ? 1 : -1);
651  }
652 
653  if (! ident_valid)
654  {
655  // should we attempt to handle invalid identifiers by converting
656  // bad characters to '_', say?
657  warning ("load: skipping invalid identifier '%s' in hdf5 file",
658  name);
659  }
660 
661 done:
662  if (retval < 0)
663  error ("load: error while reading hdf5 item %s", name);
664 
665  if (retval > 0)
666  {
667  // get documentation string, if any:
668  int comment_length = H5Gget_comment (group_id, name, 0, nullptr);
669 
670  if (comment_length > 1)
671  {
672  OCTAVE_LOCAL_BUFFER (char, tdoc, comment_length);
673  H5Gget_comment (group_id, name, comment_length, tdoc);
674  d->doc = tdoc;
675  }
676  else if (vname != name)
677  {
678  // the name was changed; store the original name
679  // as the documentation string:
680  d->doc = name;
681  }
682 
683  // copy name (actually, vname):
684  d->name = vname;
685  }
686 
687  return retval;
688 }
689 
690 #endif
691 
693 hdf5_read_next_data (octave_hdf5_id group_id, const char *name, void *dv)
694 {
695 #if defined (HAVE_HDF5)
696 
697  hid_t new_id = check_hdf5_id_value (group_id, "hdf5_read_next_data");
698 
699  return hdf5_read_next_data_internal (new_id, name, dv);
700 
701 #else
702  err_disabled_feature ("hdf5_read_next_data", "HDF5");
703 #endif
704 }
705 
707 hdf5_h5g_iterate (octave_hdf5_id loc_id, const char *name, int *idx,
708  void *operator_data)
709 {
710 #if defined (HAVE_HDF5)
711 
712  hid_t new_id = check_hdf5_id_value (loc_id, "hdf5_h5g_iterate");
713 
714  return H5Giterate (new_id, name, idx, hdf5_read_next_data_internal,
715  operator_data);
716 
717 #else
718  err_disabled_feature ("hdf5_h5g_iterate", "HDF5");
719 #endif
720 }
721 
722 // Read the next Octave variable from the stream IS, which must really be an
723 // hdf5_ifstream. Return the variable value in tc, its doc string in doc, and
724 // whether it is global in global. The return value is the name of the
725 // variable, or NULL if none were found or there was an 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.clear ();
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, nullptr, 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  {
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, nullptr);
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_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 ()
1069  || val.type_id () == octave_lazy_index::static_type_id ())
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, nullptr);
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,
1095 #else
1096  data_type_id = H5Dcreate (data_id, "type", type_id, space_id,
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_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_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_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:12193
void close(void)
Definition: ls-hdf5.cc:113
octave_value lookup_type(const std::string &nm)
Definition: ov-typeinfo.cc:476
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
is already an absolute the name is checked against the file system instead of Octave s loadpath In this if otherwise an empty string is returned If the first argument is a cell array of 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:305
static int static_type_id(void)
Definition: ov-lazy-idx.h:265
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
identity matrix If supplied two scalar respectively For allows like xample val
Definition: data.cc:4986
const octave_hdf5_id octave_H5S_ALL
int argc
Definition: load-save.cc:646
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:6348
const octave_hdf5_id octave_H5E_DEFAULT
void error(const char *fmt,...)
Definition: error.cc:578
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:997
int octave_hdf5_err
nd example oindent opens the file binary numeric values will be read assuming they are stored in IEEE format with the least significant bit and then converted to the native representation Opening a file that is already open simply opens it again and returns a separate file id It is not an error to open a file several though writing to the same file through several different file ids may produce unexpected results The possible values of text mode reading and writing automatically converts linefeeds to the appropriate line end character for the you may append a you must also open the file in binary mode The parameter conversions are currently only supported for and permissions will be set to and then everything is written in a single operation This is very efficient and improves performance c
Definition: file-io.cc:587
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 const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &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:268
string_vector argv
Definition: load-save.cc:648
done
Definition: syscalls.cc:251
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:1736
nd deftypefn *std::string name
Definition: sysdep.cc:647
OCTAVE_EXPORT octave_value_list isdir nd deftypefn *std::string nm
Definition: utils.cc:975
type_info & __get_type_info__(const std::string &who)
bool add_hdf5_data(octave_hdf5_id loc_id, const octave_value &tc, const std::string &name, const std::string &doc, bool mark_global, bool save_as_floats)
Definition: ls-hdf5.cc:1053
bool valid_identifier(const char *s)
Definition: utils.cc:74
bool save_hdf5_data(std::ostream &os, const octave_value &tc, const std::string &name, const std::string &doc, bool mark_global, bool save_as_floats)
Definition: ls-hdf5.cc:1148
bool hdf5_types_compatible(octave_hdf5_id t1, octave_hdf5_id t2)
Definition: ls-hdf5.cc:190
bool save_as_floats
Definition: load-save.cc:1617
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:707
octave_value retval
Definition: data.cc:6246
#define panic_impossible()
Definition: error.h:40
bool hdf5_check_attr(octave_hdf5_id loc_id, const char *attr_name)
Definition: ls-hdf5.cc:221
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:693
sz
Definition: data.cc:5264
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:190
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:77
octave_hdf5_err hdf5_add_attr(octave_hdf5_id loc_id, const char *attr_name)
Definition: ls-hdf5.cc:812
void warning(const char *fmt,...)
Definition: error.cc:801
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:227
static herr_t hdf5_read_next_data_internal(hid_t group_id, const char *name, void *dv)
Definition: ls-hdf5.cc:355
int save_hdf5_empty(octave_hdf5_id loc_id, const char *name, const dim_vector &d)
Definition: ls-hdf5.cc:897
bool check_hdf5_types(bool warn)
octave_idx_type length(void) const
Definition: ovl.h:96
octave_hdf5_id file_id
Definition: ls-hdf5.h:44
#define H5T_NATIVE_IDX
Definition: oct-hdf5.h:39
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:41
for i
Definition: data.cc:5264
const octave_hdf5_id octave_H5P_DEFAULT
octave_idx_type length(void) const
write the output to stdout if nargout is
Definition: load-save.cc:1612
int current_item
Definition: ls-hdf5.h:47
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:326
void open(const char *name, int mode, int)
Definition: ls-hdf5.cc:133
static std::string make_valid_identifier(const std::string &nm)
Definition: ls-hdf5.cc:163
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:888
dim_vector dv
Definition: sub2ind.cc:263
octave::stream os
Definition: file-io.cc:627