Bug Summary

File:libinterp/corefcn/ls-hdf5.cc
Location:line 530, column 11
Description:Value stored to 'retval' is never read

Annotated Source Code

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