Mercurial > hg > octave-lyh
annotate src/ls-hdf5.cc @ 8914:354179c24c79
fix hdf5 saving of diag & perm matrices
author | Jaroslav Hajek <highegg@gmail.com> |
---|---|
date | Thu, 05 Mar 2009 21:50:59 +0100 |
parents | 22462fd58e66 |
children | eb63fbe60fab |
rev | line source |
---|---|
4634 | 1 /* |
2 | |
7017 | 3 Copyright (C) 1996, 1997, 2003, 2004, 2005, 2006, 2007 John W. Eaton |
4634 | 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 | |
7016 | 9 Free Software Foundation; either version 3 of the License, or (at your |
10 option) any later version. | |
4634 | 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 | |
7016 | 18 along with Octave; see the file COPYING. If not, see |
19 <http://www.gnu.org/licenses/>. | |
4634 | 20 |
21 */ | |
22 | |
23 // Author: Steven G. Johnson <stevenj@alum.mit.edu> | |
24 | |
25 #ifdef HAVE_CONFIG_H | |
26 #include <config.h> | |
27 #endif | |
28 | |
29 #if defined (HAVE_HDF5) | |
30 | |
31 #include <cfloat> | |
32 #include <cstring> | |
33 #include <cctype> | |
34 | |
35 #include <fstream> | |
36 #include <iomanip> | |
37 #include <iostream> | |
38 #include <string> | |
4726 | 39 #include <vector> |
4634 | 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" | |
8377
25bc2d31e1bf
improve OCTAVE_LOCAL_BUFFER
Jaroslav Hajek <highegg@gmail.com>
parents:
7336
diff
changeset
|
51 #include "oct-locbuf.h" |
4634 | 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 | |
70 #include "ls-utils.h" | |
71 #include "ls-hdf5.h" | |
72 | |
73 static std::string | |
74 make_valid_identifier (const std::string& nm) | |
75 { | |
76 std::string retval; | |
77 | |
78 size_t nm_len = nm.length (); | |
79 | |
80 if (nm_len > 0) | |
81 { | |
82 if (! isalpha (nm[0])) | |
83 retval += '_'; | |
84 | |
85 for (size_t i = 0; i < nm_len; i++) | |
86 { | |
87 char c = nm[i]; | |
88 retval += (isalnum (c) || c == '_') ? c : '_'; | |
89 } | |
90 } | |
91 | |
92 return retval; | |
93 } | |
94 | |
95 // Define this to 1 if/when HDF5 supports automatic conversion between | |
96 // integer and floating-point binary data: | |
97 #define HAVE_HDF5_INT2FLOAT_CONVERSIONS 0 | |
98 | |
99 // Given two compound types t1 and t2, determine whether they | |
100 // are compatible for reading/writing. This function only | |
101 // works for non-nested types composed of simple elements (ints, floats...), | |
102 // which is all we need it for | |
103 | |
104 bool | |
105 hdf5_types_compatible (hid_t t1, hid_t t2) | |
106 { | |
107 int n; | |
108 if ((n = H5Tget_nmembers (t1)) != H5Tget_nmembers (t2)) | |
109 return false; | |
110 | |
111 for (int i = 0; i < n; ++i) | |
112 { | |
113 hid_t mt1 = H5Tget_member_type (t1, i); | |
114 hid_t mt2 = H5Tget_member_type (t2, i); | |
115 | |
116 if (H5Tget_class (mt1) != H5Tget_class (mt2)) | |
117 return false; | |
118 | |
119 H5Tclose (mt2); | |
120 H5Tclose (mt1); | |
121 } | |
122 | |
123 return true; | |
124 } | |
125 | |
126 // Return true if loc_id has the attribute named attr_name, and false | |
127 // otherwise. | |
128 | |
129 bool | |
130 hdf5_check_attr (hid_t loc_id, const char *attr_name) | |
131 { | |
132 bool retval = false; | |
133 | |
134 // we have to pull some shenanigans here to make sure | |
135 // HDF5 doesn't print out all sorts of error messages if we | |
136 // call H5Aopen for a non-existing attribute | |
137 | |
138 H5E_auto_t err_func; | |
139 void *err_func_data; | |
140 | |
141 // turn off error reporting temporarily, but save the error | |
142 // reporting function: | |
143 | |
144 H5Eget_auto (&err_func, &err_func_data); | |
145 H5Eset_auto (0, 0); | |
146 | |
147 hid_t attr_id = H5Aopen_name (loc_id, attr_name); | |
148 | |
149 if (attr_id >= 0) | |
150 { | |
151 // successful | |
152 retval = 1; | |
153 H5Aclose (attr_id); | |
154 } | |
155 | |
156 // restore error reporting: | |
157 H5Eset_auto (err_func, err_func_data); | |
158 | |
159 return retval; | |
160 } | |
161 | |
4687 | 162 // The following subroutines creates an HDF5 representations of the way |
163 // we will store Octave complex types (pairs of floating-point numbers). | |
164 // NUM_TYPE is the HDF5 numeric type to use for storage (e.g. | |
165 // H5T_NATIVE_DOUBLE to save as 'double'). Note that any necessary | |
166 // conversions are handled automatically by HDF5. | |
4634 | 167 |
4687 | 168 hid_t |
4634 | 169 hdf5_make_complex_type (hid_t num_type) |
170 { | |
171 hid_t type_id = H5Tcreate (H5T_COMPOUND, sizeof (double) * 2); | |
172 | |
173 H5Tinsert (type_id, "real", 0 * sizeof (double), num_type); | |
174 H5Tinsert (type_id, "imag", 1 * sizeof (double), num_type); | |
175 | |
176 return type_id; | |
177 } | |
178 | |
179 // This variable, set in read_hdf5_data(), tells whether we are using | |
180 // a version of HDF5 with a buggy H5Giterate (i.e. which neglects to | |
181 // increment the index parameter to the next unread item). | |
182 static bool have_h5giterate_bug = false; | |
183 | |
184 // This function is designed to be passed to H5Giterate, which calls it | |
185 // on each data item in an HDF5 file. For the item whose name is NAME in | |
186 // the group GROUP_ID, this function sets dv->tc to an Octave representation | |
187 // of that item. (dv must be a pointer to hdf5_callback_data.) (It also | |
188 // sets the other fields of dv). | |
189 // | |
190 // It returns 1 on success (in which case H5Giterate stops and returns), | |
191 // -1 on error, and 0 to tell H5Giterate to continue on to the next item | |
192 // (e.g. if NAME was a data type we don't recognize). | |
193 | |
4687 | 194 herr_t |
4634 | 195 hdf5_read_next_data (hid_t group_id, const char *name, void *dv) |
196 { | |
197 hdf5_callback_data *d = static_cast <hdf5_callback_data *> (dv); | |
4687 | 198 hid_t type_id = -1, type_class_id = -1, data_id = -1, subgroup_id = -1, |
199 space_id = -1; | |
4634 | 200 |
201 H5G_stat_t info; | |
202 herr_t retval = 0; | |
203 bool ident_valid = valid_identifier (name); | |
204 | |
205 std::string vname = name; | |
206 | |
207 // Allow identifiers as all digits so we can load lists saved by | |
208 // earlier versions of Octave. | |
209 | |
4687 | 210 if (! ident_valid ) |
4634 | 211 { |
212 // fix the identifier, replacing invalid chars with underscores | |
213 vname = make_valid_identifier (vname); | |
214 | |
215 // check again (in case vname was null, empty, or some such thing): | |
216 ident_valid = valid_identifier (vname); | |
217 } | |
218 | |
219 H5Gget_objinfo (group_id, name, 1, &info); | |
220 | |
4687 | 221 if (info.type == H5G_GROUP && ident_valid) |
4634 | 222 { |
4687 | 223 subgroup_id = H5Gopen (group_id, name); |
4634 | 224 |
225 if (subgroup_id < 0) | |
226 { | |
227 retval = subgroup_id; | |
228 goto done; | |
229 } | |
230 | |
4687 | 231 if (hdf5_check_attr (subgroup_id, "OCTAVE_NEW_FORMAT")) |
232 { | |
233 data_id = H5Dopen (subgroup_id, "type"); | |
4634 | 234 |
4687 | 235 if (data_id < 0) |
4634 | 236 { |
4687 | 237 retval = data_id; |
238 goto done; | |
4634 | 239 } |
240 | |
4687 | 241 type_id = H5Dget_type (data_id); |
242 | |
243 type_class_id = H5Tget_class (type_id); | |
244 | |
245 if (type_class_id != H5T_STRING) | |
246 goto done; | |
247 | |
248 space_id = H5Dget_space (data_id); | |
249 hsize_t rank = H5Sget_simple_extent_ndims (space_id); | |
250 | |
251 if (rank != 0) | |
252 goto done; | |
253 | |
254 int slen = H5Tget_size (type_id); | |
255 if (slen < 0) | |
256 goto done; | |
257 | |
258 OCTAVE_LOCAL_BUFFER (char, typ, slen); | |
259 | |
260 // create datatype for (null-terminated) string to read into: | |
261 hid_t st_id = H5Tcopy (H5T_C_S1); | |
262 H5Tset_size (st_id, slen); | |
263 | |
264 if (H5Dread (data_id, st_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, | |
5760 | 265 typ) < 0) |
4687 | 266 goto done; |
267 | |
268 H5Tclose (st_id); | |
269 H5Dclose (data_id); | |
270 | |
271 d->tc = octave_value_typeinfo::lookup_type (typ); | |
272 | |
273 retval = (d->tc.load_hdf5 (subgroup_id, "value", | |
274 have_h5giterate_bug) ? 1 : -1); | |
275 | |
276 // check for OCTAVE_GLOBAL attribute: | |
277 d->global = hdf5_check_attr (subgroup_id, "OCTAVE_GLOBAL"); | |
278 | |
279 H5Gclose (subgroup_id); | |
4634 | 280 } |
281 else | |
282 { | |
4687 | 283 // an HDF5 group is treated as an octave structure by |
284 // default (since that preserves name information), and an | |
285 // octave list otherwise. | |
286 | |
287 if (hdf5_check_attr (subgroup_id, "OCTAVE_LIST")) | |
288 d->tc = octave_value_typeinfo::lookup_type ("list"); | |
289 else | |
4948 | 290 d->tc = octave_value_typeinfo::lookup_type ("struct"); |
4687 | 291 |
292 // check for OCTAVE_GLOBAL attribute: | |
293 d->global = hdf5_check_attr (subgroup_id, "OCTAVE_GLOBAL"); | |
294 | |
295 H5Gclose (subgroup_id); | |
4634 | 296 |
4687 | 297 retval = (d->tc.load_hdf5 (group_id, name, have_h5giterate_bug) |
298 ? 1 : -1); | |
299 } | |
300 | |
301 } | |
302 else if (info.type == H5G_DATASET && ident_valid) | |
303 { | |
304 // For backwards compatiability. | |
305 data_id = H5Dopen (group_id, name); | |
306 | |
307 if (data_id < 0) | |
308 { | |
309 retval = data_id; | |
310 goto done; | |
4634 | 311 } |
312 | |
4687 | 313 type_id = H5Dget_type (data_id); |
314 | |
315 type_class_id = H5Tget_class (type_id); | |
316 | |
317 if (type_class_id == H5T_FLOAT) | |
318 { | |
319 space_id = H5Dget_space (data_id); | |
320 | |
321 hsize_t rank = H5Sget_simple_extent_ndims (space_id); | |
322 | |
323 if (rank == 0) | |
324 d->tc = octave_value_typeinfo::lookup_type ("scalar"); | |
325 else | |
326 d->tc = octave_value_typeinfo::lookup_type ("matrix"); | |
327 | |
328 H5Sclose (space_id); | |
329 } | |
4948 | 330 else if (type_class_id == H5T_INTEGER) |
331 { | |
332 // What integer type do we really have.. | |
333 std::string int_typ; | |
334 #ifdef HAVE_H5T_GET_NATIVE_TYPE | |
5775 | 335 // FIXME test this code and activated with an autoconf |
5351 | 336 // test!! It is also incorrect for 64-bit indexing!! |
337 | |
4948 | 338 switch (H5Tget_native_type (type_id, H5T_DIR_ASCEND)) |
339 { | |
340 case H5T_NATIVE_CHAR: | |
341 int_typ = "int8 "; | |
342 break; | |
343 | |
344 case H5T_NATIVE_SHORT: | |
345 int_typ = "int16 "; | |
346 break; | |
347 | |
348 case H5T_NATIVE_INT: | |
349 case H5T_NATIVE_LONG: | |
350 int_typ = "int32 "; | |
351 break; | |
352 | |
353 case H5T_NATIVE_LLONG: | |
354 int_typ = "int64 "; | |
355 break; | |
356 | |
357 case H5T_NATIVE_UCHAR: | |
358 int_typ = "uint8 "; | |
359 break; | |
360 | |
361 case H5T_NATIVE_USHORT: | |
362 int_typ = "uint16 "; | |
363 break; | |
364 | |
365 case H5T_NATIVE_UINT: | |
366 case H5T_NATIVE_ULONG: | |
367 int_typ = "uint32 "; | |
368 break; | |
369 | |
370 case H5T_NATIVE_ULLONG: | |
371 int_typ = "uint64 "; | |
372 break; | |
373 } | |
374 #else | |
375 hid_t int_sign = H5Tget_sign (type_id); | |
376 | |
377 if (int_sign == H5T_SGN_ERROR) | |
378 warning ("load: can't read `%s' (unknown datatype)", name); | |
379 else | |
380 { | |
381 if (int_sign == H5T_SGN_NONE) | |
382 int_typ.append ("u"); | |
383 int_typ.append ("int"); | |
384 | |
385 int slen = H5Tget_size (type_id); | |
386 if (slen < 0) | |
387 warning ("load: can't read `%s' (unknown datatype)", name); | |
388 else | |
389 { | |
390 switch (slen) | |
391 { | |
392 case 1: | |
393 int_typ.append ("8 "); | |
394 break; | |
395 | |
396 case 2: | |
397 int_typ.append ("16 "); | |
398 break; | |
399 | |
400 case 4: | |
401 int_typ.append ("32 "); | |
402 break; | |
403 | |
404 case 8: | |
405 int_typ.append ("64 "); | |
406 break; | |
407 | |
408 default: | |
409 warning ("load: can't read `%s' (unknown datatype)", | |
410 name); | |
411 int_typ = ""; | |
412 break; | |
413 } | |
414 } | |
415 } | |
416 #endif | |
417 if (int_typ == "") | |
418 warning ("load: can't read `%s' (unknown datatype)", name); | |
419 else | |
420 { | |
421 // Matrix or scalar? | |
422 space_id = H5Dget_space (data_id); | |
423 | |
424 hsize_t rank = H5Sget_simple_extent_ndims (space_id); | |
425 | |
426 if (rank == 0) | |
427 int_typ.append ("scalar"); | |
428 else | |
429 int_typ.append ("matrix"); | |
430 | |
431 d->tc = octave_value_typeinfo::lookup_type (int_typ); | |
432 H5Sclose (space_id); | |
433 } | |
434 } | |
4687 | 435 else if (type_class_id == H5T_STRING) |
436 d->tc = octave_value_typeinfo::lookup_type ("string"); | |
437 else if (type_class_id == H5T_COMPOUND) | |
438 { | |
439 hid_t complex_type = hdf5_make_complex_type (H5T_NATIVE_DOUBLE); | |
440 | |
441 if (hdf5_types_compatible (type_id, complex_type)) | |
442 { | |
443 // read complex matrix or scalar variable | |
444 space_id = H5Dget_space (data_id); | |
445 hsize_t rank = H5Sget_simple_extent_ndims (space_id); | |
446 | |
447 if (rank == 0) | |
448 d->tc = octave_value_typeinfo::lookup_type ("complex scalar"); | |
449 else | |
450 d->tc = octave_value_typeinfo::lookup_type ("complex matrix"); | |
451 | |
452 H5Sclose (space_id); | |
453 } | |
454 else | |
455 // Assume that if its not complex its a range. If its not | |
456 // it'll be rejected later in the range code | |
457 d->tc = octave_value_typeinfo::lookup_type ("range"); | |
458 | |
459 H5Tclose (complex_type); | |
460 } | |
461 else | |
462 { | |
463 warning ("load: can't read `%s' (unknown datatype)", name); | |
464 retval = 0; // unknown datatype; skip | |
465 } | |
466 | |
467 // check for OCTAVE_GLOBAL attribute: | |
468 d->global = hdf5_check_attr (data_id, "OCTAVE_GLOBAL"); | |
469 | |
470 H5Tclose (type_id); | |
471 H5Dclose (data_id); | |
472 | |
473 retval = (d->tc.load_hdf5 (group_id, name, have_h5giterate_bug) | |
474 ? 1 : -1); | |
4634 | 475 } |
4687 | 476 |
477 if (!ident_valid) | |
4634 | 478 { |
479 // should we attempt to handle invalid identifiers by converting | |
480 // bad characters to '_', say? | |
481 warning ("load: skipping invalid identifier `%s' in hdf5 file", | |
482 name); | |
483 } | |
484 | |
485 done: | |
486 if (retval < 0) | |
487 error ("load: error while reading hdf5 item %s", name); | |
4687 | 488 |
4634 | 489 if (retval > 0) |
490 { | |
491 // get documentation string, if any: | |
492 int comment_length = H5Gget_comment (group_id, name, 0, 0); | |
493 | |
494 if (comment_length > 1) | |
495 { | |
496 OCTAVE_LOCAL_BUFFER (char, tdoc, comment_length); | |
497 H5Gget_comment (group_id, name, comment_length, tdoc); | |
498 d->doc = tdoc; | |
499 } | |
500 else if (vname != name) | |
501 { | |
4687 | 502 // the name was changed; store the original name |
4634 | 503 // as the documentation string: |
504 d->doc = name; | |
505 } | |
506 | |
507 // copy name (actually, vname): | |
508 d->name = vname; | |
509 } | |
510 | |
511 return retval; | |
512 } | |
513 | |
514 // Read the next Octave variable from the stream IS, which must really be | |
515 // an hdf5_ifstream. Return the variable value in tc, its doc string | |
516 // in doc, and whether it is global in global. The return value is | |
517 // the name of the variable, or NULL if none were found or there was | |
4687 | 518 // and error. |
4634 | 519 std::string |
4687 | 520 read_hdf5_data (std::istream& is, const std::string& /* filename */, |
521 bool& global, octave_value& tc, std::string& doc) | |
4634 | 522 { |
523 std::string retval; | |
524 | |
525 doc.resize (0); | |
526 | |
5760 | 527 hdf5_ifstream& hs = dynamic_cast<hdf5_ifstream&> (is); |
4634 | 528 hdf5_callback_data d; |
529 | |
530 // Versions of HDF5 prior to 1.2.2 had a bug in H5Giterate where it | |
531 // would return the index of the last item processed instead of the | |
532 // next item to be processed, forcing us to increment the index manually. | |
533 | |
534 unsigned int vers_major, vers_minor, vers_release; | |
535 | |
536 H5get_libversion (&vers_major, &vers_minor, &vers_release); | |
537 | |
5775 | 538 // FIXME -- this test looks wrong. |
4634 | 539 have_h5giterate_bug |
540 = (vers_major < 1 | |
541 || (vers_major == 1 && (vers_minor < 2 | |
542 || (vers_minor == 2 && vers_release < 2)))); | |
543 | |
4696 | 544 herr_t H5Giterate_retval = -1; |
545 | |
546 #ifdef HAVE_H5GGET_NUM_OBJS | |
547 hsize_t num_obj = 0; | |
5060 | 548 hid_t group_id = H5Gopen (hs.file_id, "/"); |
549 H5Gget_num_objs (group_id, &num_obj); | |
550 H5Gclose (group_id); | |
4696 | 551 if (hs.current_item < static_cast<int> (num_obj)) |
552 #endif | |
553 H5Giterate_retval = H5Giterate (hs.file_id, "/", &hs.current_item, | |
554 hdf5_read_next_data, &d); | |
4634 | 555 |
556 if (have_h5giterate_bug) | |
557 { | |
558 // H5Giterate sets current_item to the last item processed; we want | |
559 // the index of the next item (for the next call to read_hdf5_data) | |
560 | |
561 hs.current_item++; | |
562 } | |
563 | |
564 if (H5Giterate_retval > 0) | |
565 { | |
566 global = d.global; | |
567 tc = d.tc; | |
568 doc = d.doc; | |
569 } | |
570 else | |
571 { | |
572 // an error occurred (H5Giterate_retval < 0) or there are no | |
573 // more datasets print an error message if retval < 0? | |
574 // hdf5_read_next_data already printed one, probably. | |
575 } | |
576 | |
577 if (! d.name.empty ()) | |
578 retval = d.name; | |
579 | |
580 return retval; | |
581 } | |
582 | |
583 // Add an attribute named attr_name to loc_id (a simple scalar | |
584 // attribute with value 1). Return value is >= 0 on success. | |
585 static herr_t | |
586 hdf5_add_attr (hid_t loc_id, const char *attr_name) | |
587 { | |
588 herr_t retval = 0; | |
589 | |
590 hid_t as_id = H5Screate (H5S_SCALAR); | |
591 | |
592 if (as_id >= 0) | |
593 { | |
594 hid_t a_id = H5Acreate (loc_id, attr_name, | |
595 H5T_NATIVE_UCHAR, as_id, H5P_DEFAULT); | |
596 | |
597 if (a_id >= 0) | |
598 { | |
599 unsigned char attr_val = 1; | |
600 | |
5760 | 601 retval = H5Awrite (a_id, H5T_NATIVE_UCHAR, &attr_val); |
4634 | 602 |
603 H5Aclose (a_id); | |
604 } | |
605 else | |
606 retval = a_id; | |
607 | |
608 H5Sclose (as_id); | |
609 } | |
610 else | |
611 retval = as_id; | |
612 | |
613 return retval; | |
614 } | |
615 | |
4805 | 616 // Save an empty matrix, if needed. Returns |
617 // > 0 Saved empty matrix | |
618 // = 0 Not an empty matrix; did nothing | |
619 // < 0 Error condition | |
620 int | |
621 save_hdf5_empty (hid_t loc_id, const char *name, const dim_vector d) | |
622 { | |
623 hsize_t sz = d.length (); | |
6276 | 624 OCTAVE_LOCAL_BUFFER (octave_idx_type, dims, sz); |
4805 | 625 bool empty = false; |
626 hid_t space_hid = -1, data_hid = -1; | |
627 int retval; | |
628 for (hsize_t i = 0; i < sz; i++) | |
629 { | |
630 dims[i] = d(i); | |
631 if (dims[i] < 1) | |
632 empty = true; | |
633 } | |
634 | |
635 if (!empty) | |
636 return 0; | |
637 | |
5760 | 638 space_hid = H5Screate_simple (1, &sz, 0); |
4805 | 639 if (space_hid < 0) return space_hid; |
640 | |
5351 | 641 data_hid = H5Dcreate (loc_id, name, H5T_NATIVE_IDX, space_hid, |
4805 | 642 H5P_DEFAULT); |
643 if (data_hid < 0) | |
644 { | |
645 H5Sclose (space_hid); | |
646 return data_hid; | |
647 } | |
648 | |
5351 | 649 retval = H5Dwrite (data_hid, H5T_NATIVE_IDX, H5S_ALL, H5S_ALL, |
5760 | 650 H5P_DEFAULT, dims) >= 0; |
4805 | 651 |
652 H5Dclose (data_hid); | |
653 H5Sclose (space_hid); | |
654 | |
655 if (retval >= 0) | |
656 retval = hdf5_add_attr (loc_id, "OCTAVE_EMPTY_MATRIX"); | |
657 | |
658 return (retval == 0 ? 1 : retval); | |
659 } | |
660 | |
661 // Load an empty matrix, if needed. Returns | |
662 // > 0 loaded empty matrix, dimensions returned | |
663 // = 0 Not an empty matrix; did nothing | |
664 // < 0 Error condition | |
665 int | |
666 load_hdf5_empty (hid_t loc_id, const char *name, dim_vector &d) | |
667 { | |
668 if (!hdf5_check_attr(loc_id, "OCTAVE_EMPTY_MATRIX")) | |
669 return 0; | |
670 | |
671 hsize_t hdims, maxdims; | |
672 hid_t data_hid = H5Dopen (loc_id, name); | |
673 hid_t space_id = H5Dget_space (data_hid); | |
674 H5Sget_simple_extent_dims (space_id, &hdims, &maxdims); | |
675 int retval; | |
676 | |
5351 | 677 OCTAVE_LOCAL_BUFFER (octave_idx_type, dims, hdims); |
678 | |
679 retval = H5Dread (data_hid, H5T_NATIVE_IDX, H5S_ALL, H5S_ALL, | |
5760 | 680 H5P_DEFAULT, dims); |
4805 | 681 if (retval >= 0) |
682 { | |
683 d.resize (hdims); | |
684 for (hsize_t i = 0; i < hdims; i++) | |
685 d(i) = dims[i]; | |
686 } | |
687 | |
688 H5Sclose (space_id); | |
689 H5Dclose (data_hid); | |
690 | |
691 return (retval == 0 ? hdims : retval); | |
692 } | |
693 | |
4634 | 694 // save_type_to_hdf5 is not currently used, since hdf5 doesn't yet support |
695 // automatic float<->integer conversions: | |
696 | |
697 #if HAVE_HDF5_INT2FLOAT_CONVERSIONS | |
698 | |
699 // return the HDF5 type id corresponding to the Octave save_type | |
700 | |
4687 | 701 hid_t |
4634 | 702 save_type_to_hdf5 (save_type st) |
703 { | |
704 switch (st) | |
705 { | |
706 case LS_U_CHAR: | |
707 return H5T_NATIVE_UCHAR; | |
708 | |
709 case LS_U_SHORT: | |
710 return H5T_NATIVE_USHORT; | |
711 | |
712 case LS_U_INT: | |
713 return H5T_NATIVE_UINT; | |
714 | |
715 case LS_CHAR: | |
716 return H5T_NATIVE_CHAR; | |
717 | |
718 case LS_SHORT: | |
719 return H5T_NATIVE_SHORT; | |
720 | |
721 case LS_INT: | |
722 return H5T_NATIVE_INT; | |
723 | |
724 case LS_FLOAT: | |
725 return H5T_NATIVE_FLOAT; | |
726 | |
727 case LS_DOUBLE: | |
728 default: | |
729 return H5T_NATIVE_DOUBLE; | |
730 } | |
731 } | |
732 #endif /* HAVE_HDF5_INT2FLOAT_CONVERSIONS */ | |
733 | |
734 // Add the data from TC to the HDF5 location loc_id, which could | |
735 // be either a file or a group within a file. Return true if | |
736 // successful. This function calls itself recursively for lists | |
737 // (stored as HDF5 groups). | |
738 | |
4687 | 739 bool |
4634 | 740 add_hdf5_data (hid_t loc_id, const octave_value& tc, |
741 const std::string& name, const std::string& doc, | |
742 bool mark_as_global, bool save_as_floats) | |
743 { | |
744 hsize_t dims[3]; | |
4687 | 745 hid_t type_id = -1, space_id = -1, data_id = -1, data_type_id = -1; |
746 bool retval = false; | |
747 octave_value val = tc; | |
8401
712cfdc2e417
allow saving diagonal & permutation matrices to hdf5 as full
Jaroslav Hajek <highegg@gmail.com>
parents:
8377
diff
changeset
|
748 // FIXME: diagonal & permutation matrices currently don't know how to save |
712cfdc2e417
allow saving diagonal & permutation matrices to hdf5 as full
Jaroslav Hajek <highegg@gmail.com>
parents:
8377
diff
changeset
|
749 // themselves, so we convert them first to normal matrices using A = A(:,:). |
712cfdc2e417
allow saving diagonal & permutation matrices to hdf5 as full
Jaroslav Hajek <highegg@gmail.com>
parents:
8377
diff
changeset
|
750 // This is a temporary hack. |
712cfdc2e417
allow saving diagonal & permutation matrices to hdf5 as full
Jaroslav Hajek <highegg@gmail.com>
parents:
8377
diff
changeset
|
751 if (val.is_diag_matrix () || val.is_perm_matrix ()) |
8914
354179c24c79
fix hdf5 saving of diag & perm matrices
Jaroslav Hajek <highegg@gmail.com>
parents:
8676
diff
changeset
|
752 val = val.full_value (); |
8401
712cfdc2e417
allow saving diagonal & permutation matrices to hdf5 as full
Jaroslav Hajek <highegg@gmail.com>
parents:
8377
diff
changeset
|
753 |
712cfdc2e417
allow saving diagonal & permutation matrices to hdf5 as full
Jaroslav Hajek <highegg@gmail.com>
parents:
8377
diff
changeset
|
754 std::string t = val.type_name(); |
4634 | 755 |
4687 | 756 data_id = H5Gcreate (loc_id, name.c_str (), 0); |
757 if (data_id < 0) | |
758 goto error_cleanup; | |
4634 | 759 |
4687 | 760 // attach the type of the variable |
761 type_id = H5Tcopy (H5T_C_S1); H5Tset_size (type_id, t.length () + 1); | |
762 if (type_id < 0) | |
763 goto error_cleanup; | |
4634 | 764 |
4687 | 765 dims[0] = 0; |
5760 | 766 space_id = H5Screate_simple (0 , dims, 0); |
4687 | 767 if (space_id < 0) |
768 goto error_cleanup; | |
4634 | 769 |
4687 | 770 data_type_id = H5Dcreate (data_id, "type", type_id, space_id, H5P_DEFAULT); |
771 if (data_type_id < 0 || H5Dwrite (data_type_id, type_id, H5S_ALL, H5S_ALL, | |
5760 | 772 H5P_DEFAULT, t.c_str ()) < 0) |
4687 | 773 goto error_cleanup; |
4634 | 774 |
4687 | 775 // Now call the real function to save the variable |
776 retval = val.save_hdf5 (data_id, "value", save_as_floats); | |
4634 | 777 |
778 // attach doc string as comment: | |
4687 | 779 if (retval && doc.length () > 0 |
4634 | 780 && H5Gset_comment (loc_id, name.c_str (), doc.c_str ()) < 0) |
4687 | 781 retval = false; |
4634 | 782 |
783 // if it's global, add an attribute "OCTAVE_GLOBAL" with value 1 | |
4687 | 784 if (retval && mark_as_global) |
4634 | 785 retval = hdf5_add_attr (data_id, "OCTAVE_GLOBAL") >= 0; |
786 | |
4687 | 787 // We are saving in the new variable format, so mark it |
788 if (retval) | |
789 retval = hdf5_add_attr (data_id, "OCTAVE_NEW_FORMAT") >= 0; | |
790 | |
4634 | 791 error_cleanup: |
792 | |
4687 | 793 if (data_type_id >= 0) |
794 H5Dclose (data_type_id); | |
4634 | 795 |
4687 | 796 if (type_id >= 0) |
797 H5Tclose (type_id); | |
4634 | 798 |
799 if (space_id >= 0) | |
800 H5Sclose (space_id); | |
801 | |
4687 | 802 if (data_id >= 0) |
803 H5Gclose (data_id); | |
804 | |
805 if (! retval) | |
806 error ("save: error while writing `%s' to hdf5 file", name.c_str ()); | |
4634 | 807 |
808 return retval; | |
809 } | |
810 | |
811 // Write data from TC in HDF5 (binary) format to the stream OS, | |
812 // which must be an hdf5_ofstream, returning true on success. | |
813 | |
814 bool | |
815 save_hdf5_data (std::ostream& os, const octave_value& tc, | |
816 const std::string& name, const std::string& doc, | |
817 bool mark_as_global, bool save_as_floats) | |
818 { | |
5760 | 819 hdf5_ofstream& hs = dynamic_cast<hdf5_ofstream&> (os); |
4634 | 820 |
821 return add_hdf5_data (hs.file_id, tc, name, doc, | |
822 mark_as_global, save_as_floats); | |
823 } | |
824 | |
825 #endif | |
826 | |
827 /* | |
828 ;;; Local Variables: *** | |
829 ;;; mode: C++ *** | |
830 ;;; End: *** | |
831 */ |