diff src/ls-hdf5.cc @ 4687:e95c86d48732

[project @ 2004-01-06 21:53:34 by jwe]
author jwe
date Tue, 06 Jan 2004 21:53:34 +0000
parents f6d6335c08f6
children fcab389ad291
line wrap: on
line diff
--- a/src/ls-hdf5.cc	Tue Jan 06 19:31:57 2004 +0000
+++ b/src/ls-hdf5.cc	Tue Jan 06 21:53:34 2004 +0000
@@ -73,9 +73,6 @@
 #include "ls-utils.h"
 #include "ls-hdf5.h"
 
-// this is only used for HDF5 import
-// try to convert s into a valid identifier, replacing invalid chars with "_":
-
 static std::string
 make_valid_identifier (const std::string& nm)
 {
@@ -98,25 +95,6 @@
   return retval;
 }
 
-static bool
-ident_is_all_digits (const std::string& id)
-{
-  bool retval = true;
-
-  size_t len = 0;
-
-  for (size_t i = 0; i < len; i++)
-    {
-      if (! isdigit (id[i]))
-	{
-	  retval = false;
-	  break;
-	}
-    }
-
-  return retval;
-}
-
 // Define this to 1 if/when HDF5 supports automatic conversion between
 // integer and floating-point binary data:
 #define HAVE_HDF5_INT2FLOAT_CONVERSIONS 0
@@ -148,110 +126,6 @@
   return true;
 }
 
-// Import a multidimensional (rank >= 3) dataset whose id is data_id, into tc.
-// This works by calling itself recursively, building up lists of lists
-//  of lists ... of 2d matrices.  rank and dims are the rank and dimensions
-//  of the dataset.  type_id is the datatype to read into.  If it is
-//  H5T_NATIVE_DOUBLE, we are reading a real matrix.  Otherwise, type_id
-//  is assumed to be a complex type for reading a complex matrix.
-//
-//  Upon entry, we should have curdim = rank - 1, start = an array
-//  of length rank = all zeros, and count = an array of length rank =
-//  all ones except for the first two dimensions which equal the corresponding
-//  entries in dims[]. 
-//
-//  Note that we process the dimensions in reverse order, reflecting
-//  the fact that Octave is uses column-major (Fortran-order) data while
-//  HDF5 is row-major.  This means that the HDF5 file is read
-//  non-contiguously, but on the other hand means that for a 3d array
-//  we get a list of xy-plane slices, which seems nice.  We could change
-//  this behavior without much trouble; what is the best thing to do?
-//
-//  Returns a positive value upon success.
-
-static herr_t
-hdf5_import_multidim (hid_t data_id, hid_t space_id, hsize_t rank,
-		      const hsize_t *dims, hsize_t curdim,
-		      hssize_t *start, const hsize_t *count,
-		      hid_t type_id, octave_value &tc)
-{
-  herr_t retval = 1;
-
-  if (rank < 3 || curdim < 1 || curdim >= rank)
-    return -1;
-
-  if (curdim == 1)
-    {
-      // import 2d dataset for 1st 2 dims directly as a matrix
-      int nr, nc;    // rows and columns
-      nc = dims[0];  // octave uses column-major & HDF5 uses row-major
-      nr = dims[1];
-
-      hid_t mem_space_id = H5Screate_simple (2, dims, 0);
-
-      if (mem_space_id < 0)
-	return -1;
-
-      if (H5Sselect_all (mem_space_id) < 0)
-	return -1;
-    
-      if (H5Sselect_hyperslab (space_id, H5S_SELECT_SET,
-			       start, 0, count, 0) < 0)
-	{
-	  H5Sclose (mem_space_id);
-	  return -1;
-	}
-    
-      if (type_id == H5T_NATIVE_DOUBLE)
-	{
-	  // real matrix
-	  Matrix m (nr, nc);
-	  double *re = m.fortran_vec ();
-	  if (H5Dread (data_id, type_id, mem_space_id, space_id,
-		       H5P_DEFAULT, (void *) re) < 0)
-	    retval = -1;  // error
-	  else
-	    tc = m;
-	}
-      else
-	{
-	  // assume that we are using complex numbers
-	  // complex matrix
-	  ComplexMatrix m (nr, nc);
-	  Complex *reim = m.fortran_vec ();
-	  if (H5Dread (data_id, type_id, mem_space_id, space_id,
-		       H5P_DEFAULT, (void *) X_CAST (double *, reim)) < 0)
-	    retval = -1;  // error
-	  else
-	    tc = m;
-	}
-    
-      H5Sclose (mem_space_id);
-
-    }
-  else
-    {
-      octave_value_list lst;
-
-      for (hsize_t i = 0; i < dims[curdim]; ++i)
-	{
-	  octave_value slice;
-	  start[curdim] = i;
-	  retval = hdf5_import_multidim (data_id, space_id, rank,
-					 dims, curdim-1, start, count,
-					 type_id, slice);
-	  if (retval < 0)
-	    break;
-	  lst.append (slice);
-	}
-
-      if (retval > 0)
-	tc = octave_value (lst);
-    }
-
-  return retval;
-}
-
 // Return true if loc_id has the attribute named attr_name, and false
 // otherwise.
 
@@ -288,13 +162,13 @@
   return retval;
 }
 
-// The following two subroutines create HDF5 representations of the way
-// we will store Octave complex and range types (pairs and triplets of
-// floating-point numbers, respectively).  NUM_TYPE is the HDF5 numeric
-// type to use for storage (e.g. H5T_NATIVE_DOUBLE to save as 'double').
-// Note that any necessary conversions are handled automatically by HDF5.
+// The following subroutines creates an HDF5 representations of the way
+// we will store Octave complex types (pairs of floating-point numbers).
+// NUM_TYPE is the HDF5 numeric type to use for storage (e.g. 
+// H5T_NATIVE_DOUBLE to save as 'double'). Note that any necessary 
+// conversions are handled automatically by HDF5.
 
-static hid_t
+hid_t
 hdf5_make_complex_type (hid_t num_type)
 {
   hid_t type_id = H5Tcreate (H5T_COMPOUND, sizeof (double) * 2);
@@ -305,52 +179,6 @@
   return type_id;
 }
 
-static hid_t
-hdf5_make_range_type (hid_t num_type)
-{
-  hid_t type_id = H5Tcreate (H5T_COMPOUND, sizeof (double) * 3);
-
-  H5Tinsert (type_id, "base", 0 * sizeof (double), num_type);
-  H5Tinsert (type_id, "limit", 1 * sizeof (double), num_type);
-  H5Tinsert (type_id, "increment", 2 * sizeof (double), num_type);
-
-  return type_id;
-}
-
-// Callback data structure for passing data to hdf5_read_next_data, below.
-
-struct
-hdf5_callback_data
-{
-  hdf5_callback_data (void)
-    : name (), global (false), tc (), doc (),
-      complex_type (hdf5_make_complex_type (H5T_NATIVE_DOUBLE)),
-      range_type (hdf5_make_range_type (H5T_NATIVE_DOUBLE)),
-      import (false) { }
-
-  // the following fields are set by hdf5_read_data on successful return:
-
-  // the name of the variable
-  std::string name;
-
-  // whether it is global
-  bool global;
-
-  // the value of the variable, in Octave form
-  octave_value tc;
-
-  // a documentation string (NULL if none)
-  std::string doc;
-
-  // the following fields are input to hdf5_read_data:
-
-  // HDF5 rep's of complex and range type
-  hid_t complex_type, range_type;
-
-  // whether to try extra hard to import "foreign" data
-  bool import;
-};
-
 // This variable, set in read_hdf5_data(), tells whether we are using
 // a version of HDF5 with a buggy H5Giterate (i.e. which neglects to
 // increment the index parameter to the next unread item).
@@ -366,10 +194,12 @@
 // -1 on error, and 0 to tell H5Giterate to continue on to the next item
 // (e.g. if NAME was a data type we don't recognize).
 
-static herr_t
+herr_t
 hdf5_read_next_data (hid_t group_id, const char *name, void *dv)
 {
   hdf5_callback_data *d = static_cast <hdf5_callback_data *> (dv);
+  hid_t type_id = -1, type_class_id = -1, data_id = -1, subgroup_id = -1,
+    space_id = -1;
 
   H5G_stat_t info;
   herr_t retval = 0;
@@ -380,7 +210,7 @@
   // Allow identifiers as all digits so we can load lists saved by
   // earlier versions of Octave.
 
-  if (! ident_valid && (d->import || ident_is_all_digits (vname)))
+  if (! ident_valid )
     {
       // fix the identifier, replacing invalid chars with underscores
       vname = make_valid_identifier (vname);
@@ -391,297 +221,9 @@
 
   H5Gget_objinfo (group_id, name, 1, &info);
 
-  if (info.type == H5G_DATASET && ident_valid)
+  if (info.type == H5G_GROUP && ident_valid)
     {
-      retval = 1;
-
-      hid_t data_id = H5Dopen (group_id, name);
-
-      if (data_id < 0)
-	{
-	  retval = data_id;
-
-	  goto done;
-	}
-
-      hid_t type_id = H5Dget_type (data_id);
-
-      hid_t type_class_id = H5Tget_class (type_id);
-
-#if HAVE_HDF5_INT2FLOAT_CONVERSIONS
-      if (type_class_id == H5T_INTEGER || type_class_id == H5T_FLOAT)
-	{
-#else
-      // hdf5 doesn't (yet) support automatic float/integer conversions
-      if (type_class_id == H5T_FLOAT)
-	{
-#endif
-	  // read real matrix or scalar variable
-
-	  hid_t space_id = H5Dget_space (data_id);
-
-	  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
-
-	  if (rank == 0)
-	    {
-	      // real scalar:
-	      double dtmp;
-	      if (H5Dread (data_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, 
-			   H5P_DEFAULT, (void *) &dtmp) < 0)
-		retval = -1;  // error
-	      else
-		d->tc = dtmp;
-	    }
-	  else if (rank > 0 && rank <= 2)
-	    {
-	      // real matrix
-	      OCTAVE_LOCAL_BUFFER (hsize_t, dims, rank);
-	      OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
-
-	      H5Sget_simple_extent_dims (space_id, dims, maxdims);
-
-	      int nr, nc;  // rows and columns
-	      // octave uses column-major & HDF5 uses row-major
-	      nc = dims[0];
-	      nr = rank > 1 ? dims[1] : 1;
-	      Matrix m (nr, nc);
-	      double *re = m.fortran_vec ();
-	      if (H5Dread (data_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, 
-			   H5P_DEFAULT, (void *) re) < 0)
-		retval = -1;  // error
-	      else
-		d->tc = m;
-	    }
-	  else if (rank >= 3 && d->import)
-	    {
-	      OCTAVE_LOCAL_BUFFER (hsize_t, dims, rank);
-	      OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
-
-	      H5Sget_simple_extent_dims (space_id, dims, maxdims);
-
-	      OCTAVE_LOCAL_BUFFER (hssize_t, start, rank);
-	      OCTAVE_LOCAL_BUFFER (hsize_t, count, rank);
-
-	      for (hsize_t i = 0; i < rank; ++i)
-		{
-		  start[i] = 0;
-		  count[i] = 1;
-		}
-	      count[0] = dims[0];
-	      count[1] = dims[1];
-	      retval = hdf5_import_multidim (data_id, space_id,
-					     rank, dims, rank-1,
-					     start, count,
-					     H5T_NATIVE_DOUBLE, d->tc);
-	    }
-	  else
-	    {
-	      warning ("load: can't read %d-dim. hdf5 dataset %s",
-		       rank, name);
-	      retval = 0;  // skip; we can't read 3+ dimensional datasets
-	    }
-
-	  H5Sclose (space_id);
-	}
-      else if (type_class_id == H5T_STRING)
-	{
-	  // read string variable
-	  hid_t space_id = H5Dget_space (data_id);
-	  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
-
-	  if (rank == 0)
-	    {
-	      // a single string:
-	      int slen = H5Tget_size (type_id);
-	      if (slen < 0)
-		retval = -1;  // error
-	      else
-		{
-		  OCTAVE_LOCAL_BUFFER (char, s, slen);
-		  // create datatype for (null-terminated) string
-		  // to read into:
-		  hid_t st_id = H5Tcopy (H5T_C_S1);
-		  H5Tset_size (st_id, slen);
-		  if (H5Dread (data_id, st_id, H5S_ALL, H5S_ALL, 
-			       H5P_DEFAULT, (void *) s) < 0)
-		    {
-		      retval = -1;  // error
-		    }
-		  else
-		    d->tc = s;
-
-		  H5Tclose (st_id);
-		}
-	    }
-	  else if (rank == 1)
-	    {
-	      // string vector
-	      hsize_t elements, maxdim;
-	      H5Sget_simple_extent_dims (space_id, &elements, &maxdim);
-	      int slen = H5Tget_size (type_id);
-	      if (slen < 0)
-		retval = -1;  // error
-	      else
-		{
-		  // hdf5 string arrays store strings of all the
-		  // same physical length (I think), which is
-		  // slightly wasteful, but oh well.
-
-		  OCTAVE_LOCAL_BUFFER (char, s, elements * slen);
-
-		  // create datatype for (null-terminated) string
-		  // to read into:
-		  hid_t st_id = H5Tcopy (H5T_C_S1);
-		  H5Tset_size (st_id, slen);
-
-		  if (H5Dread (data_id, st_id, H5S_ALL, H5S_ALL, 
-			       H5P_DEFAULT, (void *) s) < 0)
-		    retval = -1;  // error
-		  else
-		    {
-		      charMatrix chm (elements, slen - 1);
-		      for (hsize_t i = 0; i < elements; ++i)
-			{
-			  chm.insert (s + i*slen, i, 0);
-			}
-		      d->tc = octave_value (chm, true);
-		    }
-
-		  H5Tclose (st_id);
-		}
-	    }
-	  else
-	    {
-	      warning ("load: can't read %d-dim. hdf5 string vector %s",
-		       rank, name); 
-	      // skip; we can't read higher-dimensional string vectors
-	      retval = 0;
-	    }
-	}
-      else if (type_class_id == H5T_COMPOUND)
-	{
-	  // check for complex or range data:
-
-	  if (hdf5_types_compatible (type_id, d->complex_type))
-	    {
-	      // read complex matrix or scalar variable
-
-	      hid_t space_id = H5Dget_space (data_id);
-	      hsize_t rank = H5Sget_simple_extent_ndims (space_id);
-
-	      if (rank == 0)
-		{
-		  // complex scalar:
-		  Complex ctmp;
-		  if (H5Dread (data_id, d->complex_type, H5S_ALL,
-			       H5S_ALL, H5P_DEFAULT,
-			       (void *) X_CAST (double *, &ctmp)) < 0)
-		    retval = -1;  // error
-		  else
-		    d->tc = ctmp;
-		}
-	      else if (rank > 0 && rank <= 2)
-		{
-		  // complex matrix
-		  OCTAVE_LOCAL_BUFFER (hsize_t, dims, rank);
-		  OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
-		  H5Sget_simple_extent_dims (space_id, dims, maxdims);
-		  int nr, nc;  // rows and columns
-		  // octave uses column-major & HDF5 uses row-major
-		  nc = dims[0];
-		  nr = rank > 1 ? dims[1] : 1;
-		  ComplexMatrix m (nr, nc);
-		  Complex *reim = m.fortran_vec ();
-		  if (H5Dread (data_id, d->complex_type, H5S_ALL,
-			       H5S_ALL, H5P_DEFAULT,
-			       (void *) X_CAST (double *, reim)) < 0)
-		    retval = -1;  // error
-		  else
-		    d->tc = m;
-		}
-	      else if (rank >= 3 && d->import)
-		{
-		  OCTAVE_LOCAL_BUFFER (hsize_t, dims, rank);
-		  OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
-		  H5Sget_simple_extent_dims (space_id, dims, maxdims);
-		  OCTAVE_LOCAL_BUFFER (hssize_t, start, rank);
-		  OCTAVE_LOCAL_BUFFER (hsize_t, count, rank);
-		  for (hsize_t i = 0; i < rank; ++i)
-		    {
-		      start[i] = 0;
-		      count[i] = 1;
-		    }
-		  count[0] = dims[0];
-		  count[1] = dims[1];
-		  retval = hdf5_import_multidim (data_id, space_id,
-						 rank, dims, rank-1,
-						 start, count,
-						 d->complex_type,
-						 d->tc);
-		}
-	      else
-		{
-		  warning ("load: can't read %d-dim. hdf5 dataset %s",
-			   rank, name);
-		  // skip; we can't read 3+ dimensional datasets
-		  retval = 0;
-		}
-	      H5Sclose (space_id);
-	    }
-	  else if (hdf5_types_compatible (type_id, d->range_type))
-	    {
-	      // read range variable:
-	      hid_t space_id = H5Dget_space (data_id);
-	      hsize_t rank = H5Sget_simple_extent_ndims (space_id);
-
-	      if (rank == 0)
-		{
-		  double rangevals[3];
-		  if (H5Dread (data_id, d->range_type, H5S_ALL, H5S_ALL, 
-			       H5P_DEFAULT, (void *) rangevals) < 0)
-		    retval = -1;  // error
-		  else
-		    {
-		      Range r (rangevals[0], rangevals[1], rangevals[2]);
-		      d->tc = r;
-		    }
-		}
-	      else
-		{
-		  warning ("load: can't read range array `%s' in hdf5 file",
-			   name);
-		  // skip; we can't read arrays of range variables
-		  retval = 0;
-		}
-
-	      H5Sclose (space_id);
-	    }
-	  else
-	    {
-	      warning ("load: can't read `%s' (unknown compound datatype)",
-		       name);
-	      retval = 0; // unknown datatype; skip.
-	    }
-	}
-      else
-	{
-	  warning ("load: can't read `%s' (unknown datatype)", name);
-	  retval = 0; // unknown datatype; skip
-	}
-
-      H5Tclose (type_id);
-
-      // check for OCTAVE_GLOBAL attribute:
-      d->global = hdf5_check_attr (data_id, "OCTAVE_GLOBAL");
-
-      H5Dclose (data_id);
-    }
-  else if (info.type == H5G_GROUP && ident_valid)
-    {
-      // read in group as a list or a structure
-      retval = 1;
-
-      hid_t subgroup_id = H5Gopen (group_id, name);
+      subgroup_id = H5Gopen (group_id, name);
 
       if (subgroup_id < 0)
 	{
@@ -689,56 +231,153 @@
 	  goto done;
 	}
 
-      // an HDF5 group is treated as an octave structure by
-      // default (since that preserves name information), and an
-      // octave list otherwise.
-
-      bool is_list = hdf5_check_attr (subgroup_id, "OCTAVE_LIST");
-
-      hdf5_callback_data dsub;
-
-      dsub.complex_type = d->complex_type;
-      dsub.range_type = d->range_type;
-      dsub.import = d->import;
+      if (hdf5_check_attr (subgroup_id, "OCTAVE_NEW_FORMAT"))
+	{
+	  data_id = H5Dopen (subgroup_id, "type");
 
-      herr_t retval2;
-      octave_value_list lst;
-      Octave_map m;
-      int current_item = 0;
-      while ((retval2 = H5Giterate (group_id, name, &current_item,
-				    hdf5_read_next_data, &dsub)) > 0)
-	{
-	  if (is_list)
-	    lst.append (dsub.tc);
-	  else
+	  if (data_id < 0)
 	    {
-	      octave_value ov = dsub.tc;
-
-	      if (ov.is_list ())
-		m.assign (dsub.name, octave_value (ov.list_value ()));
-	      else
-		m.assign (dsub.name, ov);
+	      retval = data_id;
+	      goto done;
 	    }
 
-	  if (have_h5giterate_bug)
-	    current_item++;  // H5Giterate returned the last index processed
+	  type_id = H5Dget_type (data_id);
+
+	  type_class_id = H5Tget_class (type_id);
+
+	  if (type_class_id != H5T_STRING)
+	    goto done;
+	  
+	  space_id = H5Dget_space (data_id);
+	  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
+
+	  if (rank != 0)
+	    goto done;
+
+	  int slen = H5Tget_size (type_id);
+	  if (slen < 0)
+	    goto done;
+
+	  OCTAVE_LOCAL_BUFFER (char, typ, slen);
+
+	  // create datatype for (null-terminated) string to read into:
+	  hid_t st_id = H5Tcopy (H5T_C_S1);
+	  H5Tset_size (st_id, slen);
+
+	  if (H5Dread (data_id, st_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, 
+		       (void *) typ) < 0)
+	    goto done;
+
+	  H5Tclose (st_id);
+	  H5Dclose (data_id);
+
+	  d->tc = octave_value_typeinfo::lookup_type (typ);
+
+	  retval = (d->tc.load_hdf5 (subgroup_id, "value", 
+		have_h5giterate_bug) ? 1 : -1);
+
+	  // check for OCTAVE_GLOBAL attribute:
+	  d->global = hdf5_check_attr (subgroup_id, "OCTAVE_GLOBAL");
+
+	  H5Gclose (subgroup_id);
 	}
-
-      if (retval2 < 0)
-	retval = retval2;
       else
 	{
-	  d->global = hdf5_check_attr (group_id, "OCTAVE_GLOBAL");
+	  // an HDF5 group is treated as an octave structure by
+	  // default (since that preserves name information), and an
+	  // octave list otherwise.
+
+	  if (hdf5_check_attr (subgroup_id, "OCTAVE_LIST"))
+	    d->tc = octave_value_typeinfo::lookup_type ("list");
+	  else
+	    d->tc = octave_value_typeinfo::lookup_type ("cell");
+	  
+	  // check for OCTAVE_GLOBAL attribute:
+	  d->global = hdf5_check_attr (subgroup_id, "OCTAVE_GLOBAL");
+
+	  H5Gclose (subgroup_id);
 
-	  if (is_list)
-	    d->tc = octave_value (lst);
-	  else
-	    d->tc = m;
+	  retval = (d->tc.load_hdf5 (group_id, name, have_h5giterate_bug) 
+		    ? 1 : -1);
+	}
+
+    }
+  else if (info.type == H5G_DATASET && ident_valid)
+    {
+      // For backwards compatiability.
+      data_id = H5Dopen (group_id, name);
+
+      if (data_id < 0)
+	{
+	  retval = data_id;
+	  goto done;
 	}
 
-      H5Gclose (subgroup_id);
+      type_id = H5Dget_type (data_id);
+      
+      type_class_id = H5Tget_class (type_id);
+
+#if HAVE_HDF5_INT2FLOAT_CONVERSIONS
+      if (type_class_id == H5T_INTEGER || type_class_id == H5T_FLOAT)
+#else
+      // hdf5 doesn't (yet) support automatic float/integer conversions
+      if (type_class_id == H5T_FLOAT)
+#endif
+	{
+	  space_id = H5Dget_space (data_id);
+
+	  hsize_t rank = H5Sget_simple_extent_ndims (space_id);
+	  
+	  if (rank == 0)
+	    d->tc = octave_value_typeinfo::lookup_type ("scalar");
+	  else
+	    d->tc = octave_value_typeinfo::lookup_type ("matrix");
+
+	  H5Sclose (space_id);
+	}
+      else if (type_class_id == H5T_STRING)
+	d->tc = octave_value_typeinfo::lookup_type ("string");
+      else if (type_class_id == H5T_COMPOUND)
+	{
+	  hid_t complex_type = hdf5_make_complex_type (H5T_NATIVE_DOUBLE);
+
+	  if (hdf5_types_compatible (type_id, complex_type))
+	    {
+	      // read complex matrix or scalar variable
+	      space_id = H5Dget_space (data_id);
+	      hsize_t rank = H5Sget_simple_extent_ndims (space_id);
+		  
+	      if (rank == 0)
+		d->tc = octave_value_typeinfo::lookup_type ("complex scalar");
+	      else
+		d->tc = octave_value_typeinfo::lookup_type ("complex matrix");
+
+	      H5Sclose (space_id);
+	    }
+	  else
+	    // Assume that if its not complex its a range. If its not
+	    // it'll be rejected later in the range code
+	    d->tc = octave_value_typeinfo::lookup_type ("range");
+
+	  H5Tclose (complex_type);
+	}
+      else
+	{
+	  warning ("load: can't read `%s' (unknown datatype)", name);
+	  retval = 0; // unknown datatype; skip
+	}
+      
+      // check for OCTAVE_GLOBAL attribute:
+      d->global = hdf5_check_attr (data_id, "OCTAVE_GLOBAL");
+
+      H5Tclose (type_id);
+      H5Dclose (data_id);
+
+      retval = (d->tc.load_hdf5 (group_id, name, have_h5giterate_bug) 
+		? 1 : -1);
     }
-  else if (! ident_valid)
+
+  if (!ident_valid)
     {
       // should we attempt to handle invalid identifiers by converting
       // bad characters to '_', say?
@@ -747,10 +386,9 @@
     }
 
  done:
-
   if (retval < 0)
     error ("load: error while reading hdf5 item %s", name);
-
+  
   if (retval > 0)
     {
       // get documentation string, if any:
@@ -764,7 +402,7 @@
 	}
       else if (vname != name)
 	{
-	  // the name was changed by import; store the original name
+	  // the name was changed; store the original name
 	  // as the documentation string:
 	  d->doc = name;
 	}
@@ -780,13 +418,10 @@
 // an hdf5_ifstream.  Return the variable value in tc, its doc string
 // in doc, and whether it is global in global.  The return value is
 // the name of the variable, or NULL if none were found or there was
-// and error.  If import is true, we try extra hard to import "foreign"
-// datasets (not created by Octave), although we usually do a reasonable
-// job anyway.  (c.f. load -import documentation.)
+// and error.
 std::string
-read_hdf5_data (std::istream& is,
-		const std::string& /* filename */, bool& global,
-		octave_value& tc, std::string& doc, bool import)
+read_hdf5_data (std::istream& is, const std::string& /* filename */, 
+		bool& global, octave_value& tc, std::string& doc)
 {
   std::string retval;
 
@@ -795,8 +430,6 @@
   hdf5_ifstream& hs = (hdf5_ifstream&) is;
   hdf5_callback_data d;
 
-  d.import = import;
-
   // Versions of HDF5 prior to 1.2.2 had a bug in H5Giterate where it
   // would return the index of the last item processed instead of the
   // next item to be processed, forcing us to increment the index manually.
@@ -835,9 +468,6 @@
       // hdf5_read_next_data already printed one, probably.
     }
 
-  H5Tclose (d.complex_type);
-  H5Tclose (d.range_type);
-
   if (! d.name.empty ())
     retval = d.name;
 
@@ -877,7 +507,6 @@
   return retval;
 }
 
-
 // save_type_to_hdf5 is not currently used, since hdf5 doesn't yet support
 // automatic float<->integer conversions:
 
@@ -885,7 +514,7 @@
 
 // return the HDF5 type id corresponding to the Octave save_type
 
-static hid_t
+hid_t
 save_type_to_hdf5 (save_type st)
 {
   switch (st)
@@ -923,297 +552,68 @@
 // successful.  This function calls itself recursively for lists
 // (stored as HDF5 groups).
 
-static bool
+bool
 add_hdf5_data (hid_t loc_id, const octave_value& tc,
 	       const std::string& name, const std::string& doc,
 	       bool mark_as_global, bool save_as_floats)
 {
   hsize_t dims[3];
-  hid_t type_id = -1, space_id = -1, data_id = -1;
-  bool data_is_group = 0;
-  bool retval = 0;
-
-  if (tc.is_string ())
-    {
-      int nr = tc.rows ();
-      charMatrix chm = tc.char_matrix_value ();
-      int nc = chm.cols ();
-
-      // create datatype for (null-terminated) string to write from:
-      type_id = H5Tcopy (H5T_C_S1); H5Tset_size (type_id, nc + 1);
-      if (type_id < 0)
-	goto error_cleanup;
-
-      dims[0] = nr;
-      space_id = H5Screate_simple (nr > 0 ? 1 : 0, dims, (hsize_t*) 0);
-      if (space_id < 0)
-	goto error_cleanup;
-
-      data_id = H5Dcreate (loc_id, name.c_str (), 
-			   type_id, space_id, H5P_DEFAULT);
-      if (data_id < 0)
-	goto error_cleanup;
-
-      OCTAVE_LOCAL_BUFFER (char, s, nr * (nc + 1));
-
-      for (int i = 0; i < nr; ++i)
-	{
-	  std::string tstr = chm.row_as_string (i);
-	  strcpy (s + i * (nc+1), tstr.c_str ());
-	}
-
-      if (H5Dwrite (data_id, type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT,
-		    (void*) s) < 0) {
-	goto error_cleanup;
-      }
-    }
-  else if (tc.is_range ())
-    {
-      space_id = H5Screate_simple (0, dims, (hsize_t*) 0);
-      if (space_id < 0)
-	goto error_cleanup;
-
-      type_id = hdf5_make_range_type (H5T_NATIVE_DOUBLE);
-      if (type_id < 0)
-	goto error_cleanup;
-
-      data_id = H5Dcreate (loc_id, name.c_str (), 
-			   type_id, space_id, H5P_DEFAULT);
-      if (data_id < 0)
-	goto error_cleanup;
-    
-      Range r = tc.range_value ();
-      double range_vals[3];
-      range_vals[0] = r.base ();
-      range_vals[1] = r.limit ();
-      range_vals[2] = r.inc ();
+  hid_t type_id = -1, space_id = -1, data_id = -1, data_type_id = -1;
+  bool retval = false;
+  octave_value val = tc;
+  std::string t = tc.type_name();
 
-      if (H5Dwrite (data_id, type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT,
-		    (void*) range_vals) < 0)
-	goto error_cleanup;
-    }
-  else if (tc.is_real_scalar ())
-    {
-      space_id = H5Screate_simple (0, dims, (hsize_t*) 0);
-      if (space_id < 0) goto error_cleanup;
-
-      data_id = H5Dcreate (loc_id, name.c_str (), 
-			   H5T_NATIVE_DOUBLE, space_id, H5P_DEFAULT);
-      if (data_id < 0)
-	goto error_cleanup;
-
-      double tmp = tc.double_value ();
-      if (H5Dwrite (data_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL,
-		    H5P_DEFAULT, (void*) &tmp) < 0)
-	goto error_cleanup;
-    }
-  else if (tc.is_real_matrix ())
-    {
-      Matrix m = tc.matrix_value ();
-      dims[1] = m.rows ();    // Octave uses column-major, while
-      dims[0] = m.columns (); // HDF5 uses row-major ordering
-
-      space_id = H5Screate_simple (dims[1] > 1 ?2:1, dims, (hsize_t*) 0);
-      if (space_id < 0)
-	goto error_cleanup;
-
-      hid_t save_type_id = H5T_NATIVE_DOUBLE;
-
-      if (save_as_floats)
-	{
-	  if (m.too_large_for_float ())
-	    {
-	      warning ("save: some values too large to save as floats --");
-	      warning ("save: saving as doubles instead");
-	    }
-	  else
-	    save_type_id = H5T_NATIVE_FLOAT;
-	}
-#if HAVE_HDF5_INT2FLOAT_CONVERSIONS
-      // hdf5 currently doesn't support float/integer conversions
-      else
-	{
-	  double max_val, min_val;
-
-	  if (m.all_integers (max_val, min_val))
-	    save_type_id
-	      = save_type_to_hdf5 (get_save_type (max_val, min_val));
-	}
-#endif /* HAVE_HDF5_INT2FLOAT_CONVERSIONS */
-
-      data_id = H5Dcreate (loc_id, name.c_str (), 
-			   save_type_id, space_id, H5P_DEFAULT);
-      if (data_id < 0)
-	goto error_cleanup;
-    
-      double *mtmp = m.fortran_vec ();
-      if (H5Dwrite (data_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL,
-		    H5P_DEFAULT, (void*) mtmp) < 0)
-	goto error_cleanup;
-    }
-  else if (tc.is_complex_scalar ())
-    {
-      space_id = H5Screate_simple (0, dims, (hsize_t*) 0);
-      if (space_id < 0)
-	goto error_cleanup;
+  data_id = H5Gcreate (loc_id, name.c_str (), 0);
+  if (data_id < 0)
+    goto error_cleanup;
 
-      type_id = hdf5_make_complex_type (H5T_NATIVE_DOUBLE);
-      if (type_id < 0)
-	goto error_cleanup;
-
-      data_id = H5Dcreate (loc_id, name.c_str (), 
-			   type_id, space_id, H5P_DEFAULT);
-      if (data_id < 0)
-	goto error_cleanup;
-
-      Complex tmp = tc.complex_value ();
-      if (H5Dwrite (data_id, type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT,
-		    (void*) X_CAST (double*, &tmp)) < 0)
-	goto error_cleanup;
-    }
-  else if (tc.is_complex_matrix ())
-    {
-      ComplexMatrix m = tc.complex_matrix_value ();
-
-      dims[1] = m.rows ();    // Octave uses column-major, while
-      dims[0] = m.columns (); // HDF5 uses row-major ordering
-
-      space_id = H5Screate_simple (dims[1] > 1 ?2:1, dims, (hsize_t*) 0);
-      if (space_id < 0)
-	goto error_cleanup;
-
-      hid_t save_type_id = H5T_NATIVE_DOUBLE;
-
-      if (save_as_floats)
-	{
-	  if (m.too_large_for_float ())
-	    {
-	      warning ("save: some values too large to save as floats --");
-	      warning ("save: saving as doubles instead");
-	    }
-	  else
-	    save_type_id = H5T_NATIVE_FLOAT;
-	}
-#if HAVE_HDF5_INT2FLOAT_CONVERSIONS
-      // hdf5 currently doesn't support float/integer conversions
-      else
-	{
-	  double max_val, min_val;
-
-	  if (m.all_integers (max_val, min_val))
-	    save_type_id
-	      = save_type_to_hdf5 (get_save_type (max_val, min_val));
-	}
-#endif /* HAVE_HDF5_INT2FLOAT_CONVERSIONS */
-
-      type_id = hdf5_make_complex_type (save_type_id);
-      if (type_id < 0) goto error_cleanup;
-
-      data_id = H5Dcreate (loc_id, name.c_str (), 
-			   type_id, space_id, H5P_DEFAULT);
-      if (data_id < 0)
-	goto error_cleanup;
-    
-      hid_t complex_type_id = hdf5_make_complex_type (H5T_NATIVE_DOUBLE);
-      if (complex_type_id < 0)
-	goto error_cleanup;
+  // attach the type of the variable
+  type_id = H5Tcopy (H5T_C_S1); H5Tset_size (type_id, t.length () + 1);
+  if (type_id < 0)
+    goto error_cleanup;
 
-      Complex *mtmp = m.fortran_vec ();
-      if (H5Dwrite (data_id, complex_type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT,
-		    (void*) X_CAST (double *, mtmp)) < 0)
-	{
-	  H5Tclose (complex_type_id);
-	  goto error_cleanup;
-	}
-
-      H5Tclose (complex_type_id);
-    }
-  else if (tc.is_list ())
-    {
-      data_id = H5Gcreate (loc_id, name.c_str (), 0);
-      if (data_id < 0)
-	goto error_cleanup;
-
-      data_is_group = 1;
-
-      // recursively add each element of the list to this group
-      octave_value_list lst = tc.list_value ();
-
-      for (int i = 0; i < lst.length (); ++i)
-	{
-	  // should we use lst.name_tags () to label the elements?
-	  char s[20];
-	  sprintf (s, "_%d", i);
-	  bool retval2 = add_hdf5_data (data_id, lst (i), s, "",
-					false, save_as_floats);
-	  if (! retval2)
-	    goto error_cleanup;
-	}
+  dims[0] = 0;
+  space_id = H5Screate_simple (0 , dims, (hsize_t*) 0);
+  if (space_id < 0)
+    goto error_cleanup;
 
-      // mark with an attribute "OCTAVE_LIST" with value 1
-      // to distinguish from structures (also stored as HDF5 groups):
-      if (hdf5_add_attr (data_id, "OCTAVE_LIST") < 0)
-	goto error_cleanup;
-    }
-  else if (tc.is_map ())
-    {
-      // an Octave structure
-      data_id = H5Gcreate (loc_id, name.c_str (), 0);
-      if (data_id < 0)
-	goto error_cleanup;
-
-      data_is_group = 1;
+  data_type_id = H5Dcreate (data_id, "type",  type_id, space_id, H5P_DEFAULT);
+  if (data_type_id < 0 || H5Dwrite (data_type_id, type_id, H5S_ALL, H5S_ALL, 
+				    H5P_DEFAULT, (void*) t.c_str ()) < 0)
+    goto error_cleanup;
 
-      // recursively add each element of the structure to this group
-      const Octave_map m = tc.map_value ();
-      Octave_map::const_iterator i = m.begin ();
-      while (i != m.end ())
-	{
-	  // XXX FIXME XXX -- if the length of the structure array is
-	  // 1, should we really create a list object?
-	  bool retval2 = add_hdf5_data (data_id, octave_value (m.contents (i)),
-					m.key (i), "", false, save_as_floats);
-	  if (! retval2)
-	    goto error_cleanup;
-
-	  i++;
-	}
-    }
-  else
-    {
-      gripe_wrong_type_arg ("save", tc, false);
-      goto error_cleanup;
-    }
+  // Now call the real function to save the variable
+  retval = val.save_hdf5 (data_id, "value", save_as_floats);
 
   // attach doc string as comment:
-  if (doc.length () > 0
+  if (retval && doc.length () > 0
       && H5Gset_comment (loc_id, name.c_str (), doc.c_str ()) < 0)
-    goto error_cleanup;
-
-  retval = 1;
+    retval = false;
 
   // if it's global, add an attribute "OCTAVE_GLOBAL" with value 1
-  if (mark_as_global)
+  if (retval && mark_as_global)
     retval = hdf5_add_attr (data_id, "OCTAVE_GLOBAL") >= 0;
 
+  // We are saving in the new variable format, so mark it
+  if (retval)
+    retval = hdf5_add_attr (data_id, "OCTAVE_NEW_FORMAT") >= 0;
+
  error_cleanup:
 
-  if (! retval)
-    error ("save: error while writing `%s' to hdf5 file", name.c_str ());
+  if (data_type_id >= 0)
+    H5Dclose (data_type_id);
 
-  if (data_id >= 0)
-    {
-      if (data_is_group)
-	H5Gclose (data_id);
-      else
-	H5Dclose (data_id);
-    }
+  if (type_id >= 0)
+    H5Tclose (type_id);
 
   if (space_id >= 0)
     H5Sclose (space_id);
 
-  if (type_id >= 0)
-    H5Tclose (type_id);
+  if (data_id >= 0)
+    H5Gclose (data_id);
+
+  if (! retval)
+    error ("save: error while writing `%s' to hdf5 file", name.c_str ());
 
   return retval;
 }