ls-hdf5.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 1996-2012 John W. Eaton
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
00020 
00021 */
00022 
00023 // Author: Steven G. Johnson <stevenj@alum.mit.edu>
00024 
00025 #ifdef HAVE_CONFIG_H
00026 #include <config.h>
00027 #endif
00028 
00029 #if defined (HAVE_HDF5)
00030 
00031 #include <cfloat>
00032 #include <cstring>
00033 #include <cctype>
00034 
00035 #include <fstream>
00036 #include <iomanip>
00037 #include <iostream>
00038 #include <string>
00039 #include <vector>
00040 
00041 #include "byte-swap.h"
00042 #include "data-conv.h"
00043 #include "file-ops.h"
00044 #include "glob-match.h"
00045 #include "lo-mappers.h"
00046 #include "mach-info.h"
00047 #include "oct-env.h"
00048 #include "oct-time.h"
00049 #include "quit.h"
00050 #include "str-vec.h"
00051 #include "oct-locbuf.h"
00052 
00053 #include "Cell.h"
00054 #include "defun.h"
00055 #include "error.h"
00056 #include "gripes.h"
00057 #include "load-save.h"
00058 #include "oct-obj.h"
00059 #include "oct-map.h"
00060 #include "ov-cell.h"
00061 #include "pager.h"
00062 #include "pt-exp.h"
00063 #include "sysdep.h"
00064 #include "unwind-prot.h"
00065 #include "utils.h"
00066 #include "variables.h"
00067 #include "version.h"
00068 #include "dMatrix.h"
00069 #include "ov-lazy-idx.h"
00070 
00071 #include "ls-utils.h"
00072 #include "ls-hdf5.h"
00073 
00074 static std::string
00075 make_valid_identifier (const std::string& nm)
00076 {
00077   std::string retval;
00078 
00079   size_t nm_len = nm.length ();
00080 
00081   if (nm_len > 0)
00082     {
00083       if (! isalpha (nm[0]))
00084         retval += '_';
00085 
00086       for (size_t i = 0; i < nm_len; i++)
00087         {
00088           char c = nm[i];
00089           retval += (isalnum (c) || c == '_') ? c : '_';
00090         }
00091     }
00092 
00093   return retval;
00094 }
00095 
00096 // Define this to 1 if/when HDF5 supports automatic conversion between
00097 // integer and floating-point binary data:
00098 #define HAVE_HDF5_INT2FLOAT_CONVERSIONS 0
00099 
00100 // Given two compound types t1 and t2, determine whether they
00101 // are compatible for reading/writing.  This function only
00102 // works for non-nested types composed of simple elements (ints, floats...),
00103 // which is all we need it for
00104 
00105 bool
00106 hdf5_types_compatible (hid_t t1, hid_t t2)
00107 {
00108   int n;
00109   if ((n = H5Tget_nmembers (t1)) != H5Tget_nmembers (t2))
00110     return false;
00111 
00112   for (int i = 0; i < n; ++i)
00113     {
00114       hid_t mt1 = H5Tget_member_type (t1, i);
00115       hid_t mt2 = H5Tget_member_type (t2, i);
00116 
00117       if (H5Tget_class (mt1) != H5Tget_class (mt2))
00118         return false;
00119 
00120       H5Tclose (mt2);
00121       H5Tclose (mt1);
00122     }
00123 
00124   return true;
00125 }
00126 
00127 // Return true if loc_id has the attribute named attr_name, and false
00128 // otherwise.
00129 
00130 bool
00131 hdf5_check_attr (hid_t loc_id, const char *attr_name)
00132 {
00133   bool retval = false;
00134 
00135   // we have to pull some shenanigans here to make sure
00136   // HDF5 doesn't print out all sorts of error messages if we
00137   // call H5Aopen for a non-existing attribute
00138 
00139   H5E_auto_t err_func;
00140   void *err_func_data;
00141 
00142   // turn off error reporting temporarily, but save the error
00143   // reporting function:
00144 
00145 #if HAVE_HDF5_18
00146   H5Eget_auto (H5E_DEFAULT, &err_func, &err_func_data);
00147   H5Eset_auto (H5E_DEFAULT, 0, 0);
00148 #else
00149   H5Eget_auto (&err_func, &err_func_data);
00150   H5Eset_auto (0, 0);
00151 #endif
00152 
00153   hid_t attr_id = H5Aopen_name (loc_id, attr_name);
00154 
00155   if (attr_id >= 0)
00156     {
00157       // successful
00158       retval = true;
00159       H5Aclose (attr_id);
00160     }
00161 
00162   // restore error reporting:
00163 #if HAVE_HDF5_18
00164   H5Eset_auto (H5E_DEFAULT, err_func, err_func_data);
00165 #else
00166   H5Eset_auto (err_func, err_func_data);
00167 #endif
00168   return retval;
00169 }
00170 
00171 bool
00172 hdf5_get_scalar_attr (hid_t loc_id, hid_t type_id,
00173                       const char *attr_name, void *buf)
00174 {
00175   bool retval = false;
00176 
00177   // we have to pull some shenanigans here to make sure
00178   // HDF5 doesn't print out all sorts of error messages if we
00179   // call H5Aopen for a non-existing attribute
00180 
00181   H5E_auto_t err_func;
00182   void *err_func_data;
00183 
00184   // turn off error reporting temporarily, but save the error
00185   // reporting function:
00186 
00187 #if HAVE_HDF5_18
00188   H5Eget_auto (H5E_DEFAULT, &err_func, &err_func_data);
00189   H5Eset_auto (H5E_DEFAULT, 0, 0);
00190 #else
00191   H5Eget_auto (&err_func, &err_func_data);
00192   H5Eset_auto (0, 0);
00193 #endif
00194 
00195   hid_t attr_id = H5Aopen_name (loc_id, attr_name);
00196 
00197   if (attr_id >= 0)
00198     {
00199       hid_t space_id = H5Aget_space (attr_id);
00200 
00201       hsize_t rank = H5Sget_simple_extent_ndims (space_id);
00202 
00203       if (rank == 0)
00204         retval = H5Aread (attr_id, type_id, buf) >= 0;
00205       H5Aclose (attr_id);
00206     }
00207 
00208   // restore error reporting:
00209 #if HAVE_HDF5_18
00210   H5Eset_auto (H5E_DEFAULT, err_func, err_func_data);
00211 #else
00212   H5Eset_auto (err_func, err_func_data);
00213 #endif
00214   return retval;
00215 }
00216 
00217 
00218 
00219 
00220 // The following subroutines creates an HDF5 representations of the way
00221 // we will store Octave complex types (pairs of floating-point numbers).
00222 // NUM_TYPE is the HDF5 numeric type to use for storage (e.g.
00223 // H5T_NATIVE_DOUBLE to save as 'double'). Note that any necessary
00224 // conversions are handled automatically by HDF5.
00225 
00226 hid_t
00227 hdf5_make_complex_type (hid_t num_type)
00228 {
00229   hid_t type_id = H5Tcreate (H5T_COMPOUND, sizeof (double) * 2);
00230 
00231   H5Tinsert (type_id, "real", 0 * sizeof (double), num_type);
00232   H5Tinsert (type_id, "imag", 1 * sizeof (double), num_type);
00233 
00234   return type_id;
00235 }
00236 
00237 // This function is designed to be passed to H5Giterate, which calls it
00238 // on each data item in an HDF5 file.  For the item whose name is NAME in
00239 // the group GROUP_ID, this function sets dv->tc to an Octave representation
00240 // of that item.  (dv must be a pointer to hdf5_callback_data.)  (It also
00241 // sets the other fields of dv).
00242 //
00243 // It returns 1 on success (in which case H5Giterate stops and returns),
00244 // -1 on error, and 0 to tell H5Giterate to continue on to the next item
00245 // (e.g. if NAME was a data type we don't recognize).
00246 
00247 herr_t
00248 hdf5_read_next_data (hid_t group_id, const char *name, void *dv)
00249 {
00250   hdf5_callback_data *d = static_cast <hdf5_callback_data *> (dv);
00251   hid_t type_id = -1, type_class_id = -1, data_id = -1, subgroup_id = -1,
00252     space_id = -1;
00253 
00254   H5G_stat_t info;
00255   herr_t retval = 0;
00256   bool ident_valid = valid_identifier (name);
00257 
00258   std::string vname = name;
00259 
00260   // Allow identifiers as all digits so we can load lists saved by
00261   // earlier versions of Octave.
00262 
00263   if (! ident_valid )
00264     {
00265       // fix the identifier, replacing invalid chars with underscores
00266       vname = make_valid_identifier (vname);
00267 
00268       // check again (in case vname was null, empty, or some such thing):
00269       ident_valid = valid_identifier (vname);
00270     }
00271 
00272   H5Gget_objinfo (group_id, name, 1, &info);
00273 
00274   if (info.type == H5G_GROUP && ident_valid)
00275     {
00276 #if HAVE_HDF5_18
00277       subgroup_id = H5Gopen (group_id, name, H5P_DEFAULT);
00278 #else
00279       subgroup_id = H5Gopen (group_id, name);
00280 #endif
00281 
00282       if (subgroup_id < 0)
00283         {
00284           retval = subgroup_id;
00285           goto done;
00286         }
00287 
00288       if (hdf5_check_attr (subgroup_id, "OCTAVE_NEW_FORMAT"))
00289         {
00290 #if HAVE_HDF5_18
00291           data_id = H5Dopen (subgroup_id, "type", H5P_DEFAULT);
00292 #else
00293           data_id = H5Dopen (subgroup_id, "type");
00294 #endif
00295 
00296           if (data_id < 0)
00297             {
00298               retval = data_id;
00299               goto done;
00300             }
00301 
00302           type_id = H5Dget_type (data_id);
00303 
00304           type_class_id = H5Tget_class (type_id);
00305 
00306           if (type_class_id != H5T_STRING)
00307             goto done;
00308 
00309           space_id = H5Dget_space (data_id);
00310           hsize_t rank = H5Sget_simple_extent_ndims (space_id);
00311 
00312           if (rank != 0)
00313             goto done;
00314 
00315           int slen = H5Tget_size (type_id);
00316           if (slen < 0)
00317             goto done;
00318 
00319           OCTAVE_LOCAL_BUFFER (char, typ, slen);
00320 
00321           // create datatype for (null-terminated) string to read into:
00322           hid_t st_id = H5Tcopy (H5T_C_S1);
00323           H5Tset_size (st_id, slen);
00324 
00325           if (H5Dread (data_id, st_id, H5S_ALL, H5S_ALL, H5P_DEFAULT,
00326                        typ) < 0)
00327             goto done;
00328 
00329           H5Tclose (st_id);
00330           H5Dclose (data_id);
00331 
00332           d->tc = octave_value_typeinfo::lookup_type (typ);
00333 
00334           retval = (d->tc.load_hdf5 (subgroup_id, "value") ? 1 : -1);
00335 
00336           // check for OCTAVE_GLOBAL attribute:
00337           d->global = hdf5_check_attr (subgroup_id, "OCTAVE_GLOBAL");
00338 
00339           H5Gclose (subgroup_id);
00340         }
00341       else
00342         {
00343           // an HDF5 group is treated as an octave structure by
00344           // default (since that preserves name information), and an
00345           // octave list otherwise.
00346 
00347           if (hdf5_check_attr (subgroup_id, "OCTAVE_LIST"))
00348             d->tc = octave_value_typeinfo::lookup_type ("list");
00349           else
00350             d->tc = octave_value_typeinfo::lookup_type ("struct");
00351 
00352           // check for OCTAVE_GLOBAL attribute:
00353           d->global = hdf5_check_attr (subgroup_id, "OCTAVE_GLOBAL");
00354 
00355           H5Gclose (subgroup_id);
00356 
00357           retval = (d->tc.load_hdf5 (group_id, name) ? 1 : -1);
00358         }
00359 
00360     }
00361   else if (info.type == H5G_DATASET && ident_valid)
00362     {
00363       // For backwards compatiability.
00364 #if HAVE_HDF5_18
00365       data_id = H5Dopen (group_id, name, H5P_DEFAULT);
00366 #else
00367       data_id = H5Dopen (group_id, name);
00368 #endif
00369 
00370       if (data_id < 0)
00371         {
00372           retval = data_id;
00373           goto done;
00374         }
00375 
00376       type_id = H5Dget_type (data_id);
00377 
00378       type_class_id = H5Tget_class (type_id);
00379 
00380       if (type_class_id == H5T_FLOAT)
00381         {
00382           space_id = H5Dget_space (data_id);
00383 
00384           hsize_t rank = H5Sget_simple_extent_ndims (space_id);
00385 
00386           if (rank == 0)
00387             d->tc = octave_value_typeinfo::lookup_type ("scalar");
00388           else
00389             d->tc = octave_value_typeinfo::lookup_type ("matrix");
00390 
00391           H5Sclose (space_id);
00392         }
00393       else if (type_class_id == H5T_INTEGER)
00394         {
00395           // What integer type do we really have..
00396           std::string int_typ;
00397 #ifdef HAVE_H5T_GET_NATIVE_TYPE
00398           // FIXME test this code and activated with an autoconf
00399           // test!! It is also incorrect for 64-bit indexing!!
00400 
00401           switch (H5Tget_native_type (type_id, H5T_DIR_ASCEND))
00402             {
00403             case H5T_NATIVE_CHAR:
00404               int_typ = "int8 ";
00405               break;
00406 
00407             case H5T_NATIVE_SHORT:
00408               int_typ = "int16 ";
00409               break;
00410 
00411             case H5T_NATIVE_INT:
00412             case H5T_NATIVE_LONG:
00413               int_typ = "int32 ";
00414               break;
00415 
00416             case H5T_NATIVE_LLONG:
00417               int_typ = "int64 ";
00418               break;
00419 
00420             case H5T_NATIVE_UCHAR:
00421               int_typ = "uint8 ";
00422               break;
00423 
00424             case H5T_NATIVE_USHORT:
00425               int_typ = "uint16 ";
00426               break;
00427 
00428             case H5T_NATIVE_UINT:
00429             case H5T_NATIVE_ULONG:
00430               int_typ = "uint32 ";
00431               break;
00432 
00433             case H5T_NATIVE_ULLONG:
00434               int_typ = "uint64 ";
00435               break;
00436             }
00437 #else
00438           hid_t int_sign = H5Tget_sign (type_id);
00439 
00440           if (int_sign == H5T_SGN_ERROR)
00441             warning ("load: can't read '%s' (unknown datatype)", name);
00442           else
00443             {
00444               if (int_sign == H5T_SGN_NONE)
00445                 int_typ.append ("u");
00446               int_typ.append ("int");
00447 
00448               int slen = H5Tget_size (type_id);
00449               if (slen < 0)
00450                 warning ("load: can't read '%s' (unknown datatype)", name);
00451               else
00452                 {
00453                   switch (slen)
00454                     {
00455                     case 1:
00456                       int_typ.append ("8 ");
00457                       break;
00458 
00459                     case 2:
00460                       int_typ.append ("16 ");
00461                       break;
00462 
00463                     case 4:
00464                       int_typ.append ("32 ");
00465                       break;
00466 
00467                     case 8:
00468                       int_typ.append ("64 ");
00469                       break;
00470 
00471                     default:
00472                       warning ("load: can't read '%s' (unknown datatype)",
00473                                name);
00474                       int_typ = "";
00475                       break;
00476                     }
00477                 }
00478             }
00479 #endif
00480           if (int_typ == "")
00481             warning ("load: can't read '%s' (unknown datatype)", name);
00482           else
00483             {
00484               // Matrix or scalar?
00485               space_id = H5Dget_space (data_id);
00486 
00487               hsize_t rank = H5Sget_simple_extent_ndims (space_id);
00488 
00489               if (rank == 0)
00490                 int_typ.append ("scalar");
00491               else
00492                 int_typ.append ("matrix");
00493 
00494               d->tc = octave_value_typeinfo::lookup_type (int_typ);
00495               H5Sclose (space_id);
00496             }
00497         }
00498       else if (type_class_id == H5T_STRING)
00499         d->tc = octave_value_typeinfo::lookup_type ("string");
00500       else if (type_class_id == H5T_COMPOUND)
00501         {
00502           hid_t complex_type = hdf5_make_complex_type (H5T_NATIVE_DOUBLE);
00503 
00504           if (hdf5_types_compatible (type_id, complex_type))
00505             {
00506               // read complex matrix or scalar variable
00507               space_id = H5Dget_space (data_id);
00508               hsize_t rank = H5Sget_simple_extent_ndims (space_id);
00509 
00510               if (rank == 0)
00511                 d->tc = octave_value_typeinfo::lookup_type ("complex scalar");
00512               else
00513                 d->tc = octave_value_typeinfo::lookup_type ("complex matrix");
00514 
00515               H5Sclose (space_id);
00516             }
00517           else
00518             // Assume that if its not complex its a range. If its not
00519             // it'll be rejected later in the range code
00520             d->tc = octave_value_typeinfo::lookup_type ("range");
00521 
00522           H5Tclose (complex_type);
00523         }
00524       else
00525         {
00526           warning ("load: can't read '%s' (unknown datatype)", name);
00527           retval = 0; // unknown datatype; skip
00528         }
00529 
00530       // check for OCTAVE_GLOBAL attribute:
00531       d->global = hdf5_check_attr (data_id, "OCTAVE_GLOBAL");
00532 
00533       H5Tclose (type_id);
00534       H5Dclose (data_id);
00535 
00536       retval = (d->tc.load_hdf5 (group_id, name) ? 1 : -1);
00537     }
00538 
00539   if (!ident_valid)
00540     {
00541       // should we attempt to handle invalid identifiers by converting
00542       // bad characters to '_', say?
00543       warning ("load: skipping invalid identifier '%s' in hdf5 file",
00544                name);
00545     }
00546 
00547  done:
00548   if (retval < 0)
00549     error ("load: error while reading hdf5 item %s", name);
00550 
00551   if (retval > 0)
00552     {
00553       // get documentation string, if any:
00554       int comment_length = H5Gget_comment (group_id, name, 0, 0);
00555 
00556       if (comment_length > 1)
00557         {
00558           OCTAVE_LOCAL_BUFFER (char, tdoc, comment_length);
00559           H5Gget_comment (group_id, name, comment_length, tdoc);
00560           d->doc = tdoc;
00561         }
00562       else if (vname != name)
00563         {
00564           // the name was changed; store the original name
00565           // as the documentation string:
00566           d->doc = name;
00567         }
00568 
00569       // copy name (actually, vname):
00570       d->name = vname;
00571     }
00572 
00573   return retval;
00574 }
00575 
00576 // Read the next Octave variable from the stream IS, which must really be
00577 // an hdf5_ifstream.  Return the variable value in tc, its doc string
00578 // in doc, and whether it is global in global.  The return value is
00579 // the name of the variable, or NULL if none were found or there was
00580 // and error.
00581 std::string
00582 read_hdf5_data (std::istream& is, const std::string& /* filename */,
00583                 bool& global, octave_value& tc, std::string& doc)
00584 {
00585   std::string retval;
00586 
00587   doc.resize (0);
00588 
00589   hdf5_ifstream& hs = dynamic_cast<hdf5_ifstream&> (is);
00590   hdf5_callback_data d;
00591 
00592   herr_t H5Giterate_retval = -1;
00593 
00594   hsize_t num_obj = 0;
00595 #if HAVE_HDF5_18
00596   hid_t group_id = H5Gopen (hs.file_id, "/", H5P_DEFAULT);
00597 #else
00598   hid_t group_id = H5Gopen (hs.file_id, "/");
00599 #endif
00600   H5Gget_num_objs (group_id, &num_obj);
00601   H5Gclose (group_id);
00602   if (hs.current_item < static_cast<int> (num_obj))
00603     H5Giterate_retval = H5Giterate (hs.file_id, "/", &hs.current_item,
00604                                     hdf5_read_next_data, &d);
00605 
00606   if (H5Giterate_retval > 0)
00607     {
00608       global = d.global;
00609       tc = d.tc;
00610       doc = d.doc;
00611     }
00612   else
00613     {
00614       // an error occurred (H5Giterate_retval < 0) or there are no
00615       // more datasets print an error message if retval < 0?
00616       // hdf5_read_next_data already printed one, probably.
00617     }
00618 
00619   if (! d.name.empty ())
00620     retval = d.name;
00621 
00622   return retval;
00623 }
00624 
00625 // Add an attribute named attr_name to loc_id (a simple scalar
00626 // attribute with value 1).  Return value is >= 0 on success.
00627 herr_t
00628 hdf5_add_attr (hid_t loc_id, const char *attr_name)
00629 {
00630   herr_t retval = 0;
00631 
00632   hid_t as_id = H5Screate (H5S_SCALAR);
00633 
00634   if (as_id >= 0)
00635     {
00636 #if HAVE_HDF5_18
00637       hid_t a_id = H5Acreate (loc_id, attr_name, H5T_NATIVE_UCHAR,
00638                               as_id, H5P_DEFAULT, H5P_DEFAULT);
00639 #else
00640       hid_t a_id = H5Acreate (loc_id, attr_name,
00641                               H5T_NATIVE_UCHAR, as_id, H5P_DEFAULT);
00642 #endif
00643       if (a_id >= 0)
00644         {
00645           unsigned char attr_val = 1;
00646 
00647           retval = H5Awrite (a_id, H5T_NATIVE_UCHAR, &attr_val);
00648 
00649           H5Aclose (a_id);
00650         }
00651       else
00652         retval = a_id;
00653 
00654       H5Sclose (as_id);
00655     }
00656   else
00657     retval = as_id;
00658 
00659   return retval;
00660 }
00661 
00662 herr_t
00663 hdf5_add_scalar_attr (hid_t loc_id, hid_t type_id,
00664                       const char *attr_name, void *buf)
00665 {
00666   herr_t retval = 0;
00667 
00668   hid_t as_id = H5Screate (H5S_SCALAR);
00669 
00670   if (as_id >= 0)
00671     {
00672 #if HAVE_HDF5_18
00673       hid_t a_id = H5Acreate (loc_id, attr_name, type_id,
00674                               as_id, H5P_DEFAULT, H5P_DEFAULT);
00675 #else
00676       hid_t a_id = H5Acreate (loc_id, attr_name,
00677                               type_id, as_id, H5P_DEFAULT);
00678 #endif
00679       if (a_id >= 0)
00680         {
00681           retval = H5Awrite (a_id, type_id, buf);
00682 
00683           H5Aclose (a_id);
00684         }
00685       else
00686         retval = a_id;
00687 
00688       H5Sclose (as_id);
00689     }
00690   else
00691     retval = as_id;
00692 
00693   return retval;
00694 }
00695 
00696 // Save an empty matrix, if needed. Returns
00697 //    > 0  Saved empty matrix
00698 //    = 0  Not an empty matrix; did nothing
00699 //    < 0  Error condition
00700 int
00701 save_hdf5_empty (hid_t loc_id, const char *name, const dim_vector d)
00702 {
00703   hsize_t sz = d.length ();
00704   OCTAVE_LOCAL_BUFFER (octave_idx_type, dims, sz);
00705   bool empty = false;
00706   hid_t space_hid = -1, data_hid = -1;
00707   int retval;
00708   for (hsize_t i = 0; i < sz; i++)
00709     {
00710       dims[i] = d(i);
00711       if (dims[i] < 1)
00712         empty = true;
00713     }
00714 
00715   if (!empty)
00716     return 0;
00717 
00718   space_hid = H5Screate_simple (1, &sz, 0);
00719   if (space_hid < 0) return space_hid;
00720 #if HAVE_HDF5_18
00721   data_hid = H5Dcreate (loc_id, name, H5T_NATIVE_IDX, space_hid,
00722                         H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
00723 #else
00724   data_hid = H5Dcreate (loc_id, name, H5T_NATIVE_IDX, space_hid,
00725                         H5P_DEFAULT);
00726 #endif
00727   if (data_hid < 0)
00728     {
00729       H5Sclose (space_hid);
00730       return data_hid;
00731     }
00732 
00733   retval = H5Dwrite (data_hid, H5T_NATIVE_IDX, H5S_ALL, H5S_ALL,
00734                      H5P_DEFAULT, dims) >= 0;
00735 
00736   H5Dclose (data_hid);
00737   H5Sclose (space_hid);
00738 
00739   if (retval >= 0)
00740     retval = hdf5_add_attr (loc_id, "OCTAVE_EMPTY_MATRIX");
00741 
00742   return (retval == 0 ? 1 : retval);
00743 }
00744 
00745 // Load an empty matrix, if needed. Returns
00746 //    > 0  loaded empty matrix, dimensions returned
00747 //    = 0  Not an empty matrix; did nothing
00748 //    < 0  Error condition
00749 int
00750 load_hdf5_empty (hid_t loc_id, const char *name, dim_vector &d)
00751 {
00752   if (!hdf5_check_attr(loc_id, "OCTAVE_EMPTY_MATRIX"))
00753     return 0;
00754 
00755   hsize_t hdims, maxdims;
00756 #if HAVE_HDF5_18
00757   hid_t data_hid = H5Dopen (loc_id, name, H5P_DEFAULT);
00758 #else
00759   hid_t data_hid = H5Dopen (loc_id, name);
00760 #endif
00761   hid_t space_id = H5Dget_space (data_hid);
00762   H5Sget_simple_extent_dims (space_id, &hdims, &maxdims);
00763   int retval;
00764 
00765   OCTAVE_LOCAL_BUFFER (octave_idx_type, dims, hdims);
00766 
00767   retval = H5Dread (data_hid, H5T_NATIVE_IDX, H5S_ALL, H5S_ALL,
00768                     H5P_DEFAULT, dims);
00769   if (retval >= 0)
00770     {
00771       d.resize (hdims);
00772       for (hsize_t i = 0; i < hdims; i++)
00773         d(i) = dims[i];
00774     }
00775 
00776   H5Sclose (space_id);
00777   H5Dclose (data_hid);
00778 
00779   return (retval == 0 ? hdims : retval);
00780 }
00781 
00782 // save_type_to_hdf5 is not currently used, since hdf5 doesn't yet support
00783 // automatic float<->integer conversions:
00784 
00785 #if HAVE_HDF5_INT2FLOAT_CONVERSIONS
00786 
00787 // return the HDF5 type id corresponding to the Octave save_type
00788 
00789 hid_t
00790 save_type_to_hdf5 (save_type st)
00791 {
00792   switch (st)
00793     {
00794     case LS_U_CHAR:
00795       return H5T_NATIVE_UCHAR;
00796 
00797     case LS_U_SHORT:
00798       return H5T_NATIVE_USHORT;
00799 
00800     case LS_U_INT:
00801       return H5T_NATIVE_UINT;
00802 
00803     case LS_CHAR:
00804       return H5T_NATIVE_CHAR;
00805 
00806     case LS_SHORT:
00807       return H5T_NATIVE_SHORT;
00808 
00809     case LS_INT:
00810       return H5T_NATIVE_INT;
00811 
00812     case LS_FLOAT:
00813       return H5T_NATIVE_FLOAT;
00814 
00815     case LS_DOUBLE:
00816     default:
00817       return H5T_NATIVE_DOUBLE;
00818     }
00819 }
00820 #endif /* HAVE_HDF5_INT2FLOAT_CONVERSIONS */
00821 
00822 // Add the data from TC to the HDF5 location loc_id, which could
00823 // be either a file or a group within a file.  Return true if
00824 // successful.  This function calls itself recursively for lists
00825 // (stored as HDF5 groups).
00826 
00827 bool
00828 add_hdf5_data (hid_t loc_id, const octave_value& tc,
00829                const std::string& name, const std::string& doc,
00830                bool mark_as_global, bool save_as_floats)
00831 {
00832   hsize_t dims[3];
00833   hid_t type_id = -1, space_id = -1, data_id = -1, data_type_id = -1;
00834   bool retval = false;
00835   octave_value val = tc;
00836   // FIXME: diagonal & permutation matrices currently don't know how to save
00837   // themselves, so we convert them first to normal matrices using A = A(:,:).
00838   // This is a temporary hack.
00839   if (val.is_diag_matrix () || val.is_perm_matrix ()
00840       || val.type_id () == octave_lazy_index::static_type_id ())
00841     val = val.full_value ();
00842 
00843   std::string t = val.type_name();
00844 #if HAVE_HDF5_18
00845   data_id = H5Gcreate (loc_id, name.c_str (), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
00846 #else
00847   data_id = H5Gcreate (loc_id, name.c_str (), 0);
00848 #endif
00849   if (data_id < 0)
00850     goto error_cleanup;
00851 
00852   // attach the type of the variable
00853   type_id = H5Tcopy (H5T_C_S1); H5Tset_size (type_id, t.length () + 1);
00854   if (type_id < 0)
00855     goto error_cleanup;
00856 
00857   dims[0] = 0;
00858   space_id = H5Screate_simple (0 , dims, 0);
00859   if (space_id < 0)
00860     goto error_cleanup;
00861 #if HAVE_HDF5_18
00862   data_type_id = H5Dcreate (data_id, "type",  type_id, space_id,
00863                             H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
00864 #else
00865   data_type_id = H5Dcreate (data_id, "type",  type_id, space_id, H5P_DEFAULT);
00866 #endif
00867   if (data_type_id < 0 || H5Dwrite (data_type_id, type_id, H5S_ALL, H5S_ALL,
00868                                     H5P_DEFAULT, t.c_str ()) < 0)
00869     goto error_cleanup;
00870 
00871   // Now call the real function to save the variable
00872   retval = val.save_hdf5 (data_id, "value", save_as_floats);
00873 
00874   // attach doc string as comment:
00875   if (retval && doc.length () > 0
00876       && H5Gset_comment (loc_id, name.c_str (), doc.c_str ()) < 0)
00877     retval = false;
00878 
00879   // if it's global, add an attribute "OCTAVE_GLOBAL" with value 1
00880   if (retval && mark_as_global)
00881     retval = hdf5_add_attr (data_id, "OCTAVE_GLOBAL") >= 0;
00882 
00883   // We are saving in the new variable format, so mark it
00884   if (retval)
00885     retval = hdf5_add_attr (data_id, "OCTAVE_NEW_FORMAT") >= 0;
00886 
00887  error_cleanup:
00888 
00889   if (data_type_id >= 0)
00890     H5Dclose (data_type_id);
00891 
00892   if (type_id >= 0)
00893     H5Tclose (type_id);
00894 
00895   if (space_id >= 0)
00896     H5Sclose (space_id);
00897 
00898   if (data_id >= 0)
00899     H5Gclose (data_id);
00900 
00901   if (! retval)
00902     error ("save: error while writing '%s' to hdf5 file", name.c_str ());
00903 
00904   return retval;
00905 }
00906 
00907 // Write data from TC in HDF5 (binary) format to the stream OS,
00908 // which must be an hdf5_ofstream, returning true on success.
00909 
00910 bool
00911 save_hdf5_data (std::ostream& os, const octave_value& tc,
00912                 const std::string& name, const std::string& doc,
00913                 bool mark_as_global, bool save_as_floats)
00914 {
00915   hdf5_ofstream& hs = dynamic_cast<hdf5_ofstream&> (os);
00916 
00917   return add_hdf5_data (hs.file_id, tc, name, doc,
00918                         mark_as_global, save_as_floats);
00919 }
00920 
00921 #endif
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines