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