changeset 8212:ebf6f6a0f9a7

Allow saving/loading of classes. Add saveobj and loadobj methods
author David Bateman <dbateman@free.fr>
date Thu, 09 Oct 2008 20:09:13 +0100
parents 851803f7bb4d
children d5e08881bba8
files scripts/ChangeLog scripts/general/Makefile.in scripts/general/display.m scripts/general/loadobj.m scripts/general/saveobj.m src/ChangeLog src/ls-mat5.cc src/ls-oct-ascii.h src/ov-class.cc src/ov-class.h
diffstat 10 files changed, 475 insertions(+), 129 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/ChangeLog	Sun Oct 12 08:44:55 2008 +0200
+++ b/scripts/ChangeLog	Thu Oct 09 20:09:13 2008 +0100
@@ -24,6 +24,11 @@
 
 	* plot/__axis_label__.m: Inherit font properties from axes.
 
+2008-10-09  David Bateman  <dbateman@free.fr>
+
+	* general/loadobj.m, general/saveobj.m, general/display: New functions
+	* general/Makefile.in (SOURCES): Add then here.
+	
 2008-10-08  John W. Eaton  <jwe@octave.org>
 
 	* miscellaneous/fileparts.m: Handle "/file" properly.
--- a/scripts/general/Makefile.in	Sun Oct 12 08:44:55 2008 +0200
+++ b/scripts/general/Makefile.in	Thu Oct 09 20:09:13 2008 +0100
@@ -36,17 +36,17 @@
 SOURCES = __isequal__.m __splinen__.m accumarray.m arrayfun.m \
   bicubic.m bitcmp.m bitget.m bitset.m blkdiag.m cart2pol.m \
   cart2sph.m cellidx.m cell2mat.m celldisp.m circshift.m common_size.m \
-  cplxpair.m cumtrapz.m dblquad.m deal.m del2.m diff.m flipdim.m fliplr.m \
-  flipud.m genvarname.m gradient.m idivide.m ind2sub.m int2str.m \
+  cplxpair.m cumtrapz.m dblquad.m deal.m del2.m diff.m display.m flipdim.m \
+  fliplr.m flipud.m genvarname.m gradient.m idivide.m ind2sub.m int2str.m \
   interp1.m interp1q.m interp2.m interp3.m interpn.m interpft.m \
   is_duplicate_entry.m isa.m isdefinite.m isdir.m isequal.m \
   isequalwithequalnans.m isscalar.m issquare.m issymmetric.m \
-  isvector.m logical.m logspace.m mod.m nargchk.m \
+  isvector.m loadobj.m logical.m logspace.m mod.m nargchk.m \
   nargoutchk.m nextpow2.m nthroot.m num2str.m perror.m pol2cart.m \
   polyarea.m postpad.m prepad.m quadgk.m quadl.m quadv.m randperm.m rat.m \
-  rem.m repmat.m rot90.m rotdim.m runlength.m shift.m shiftdim.m sortrows.m \
-  sph2cart.m strerror.m structfun.m sub2ind.m subsindex.m triplequad.m \
-  trapz.m tril.m triu.m
+  rem.m repmat.m rot90.m rotdim.m runlength.m saveobj.m shift.m shiftdim.m \
+  sortrows.m sph2cart.m strerror.m structfun.m sub2ind.m subsindex.m \
+  triplequad.m trapz.m tril.m triu.m
 
 DISTFILES = $(addprefix $(srcdir)/, Makefile.in $(SOURCES))
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/general/display.m	Thu Oct 09 20:09:13 2008 +0100
@@ -0,0 +1,37 @@
+## Copyright (C) 2008 David Bateman
+##
+## This file is part of Octave.
+##
+## Octave is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or (at
+## your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} {} display (@var{a})
+## Display the contents of an object. If @var{a} is an object of the
+## class "myclass", then @code{display} is called in a case like
+##
+## @example
+## myclass (@dots{})
+## @end example
+##
+## @noindent
+## where Octave is requried to display the contents of a variable of the
+## type "myclass".
+##
+## @seealso{class, subsref, subsasgn}
+## @end deftypefn
+
+function idx = display (a)
+  error ("display: not defined for class \"%s\"", class(a));
+endfunction
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/general/loadobj.m	Thu Oct 09 20:09:13 2008 +0100
@@ -0,0 +1,41 @@
+## Copyright (C) 2008 David Bateman
+##
+## This file is part of Octave.
+##
+## Octave is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or (at
+## your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} {@var{b} =} loadobj (@var{a})
+## Methof of a class to manipulate an object after loading it tfrom a file. 
+## The function @code{loadobj} is called when the object @var{a} is loaded 
+## using the @code{load} function. An example of the use of @code{saveobj}
+## might be to add fields to an object that don't make sense to be saved.
+## For example
+##
+## @example
+## @group
+## function b = loadobj (a)
+##   b = a;
+##   b.addmssingfield = addfield (b;
+## endfunction
+## @end group
+## @end example
+##
+## @seealso{saveobj, class}
+## @end deftypefn
+
+function b = loadobj (a)
+  error ("loadobj: not defined for class \"%s\"", class(a));
+endfunction
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/general/saveobj.m	Thu Oct 09 20:09:13 2008 +0100
@@ -0,0 +1,44 @@
+## Copyright (C) 2008 David Bateman
+##
+## This file is part of Octave.
+##
+## Octave is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or (at
+## your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} {@var{b} =} saveobj (@var{a})
+## Method of a class to manipulate an object prior to saving it to a file. 
+## The function @code{saveobj} is called when the object @var{a} is saved 
+## using the @code{save} function. An example of the use of @code{saveobj}
+## might be to remove fields of the object that don't make sense to be saved
+## or it might be used to ensure that certain fields of the object are
+## initialized before the object is saved. For example
+##
+## @example
+## @group
+## function b = saveobj (a)
+##   b = a;
+##   if (isempty (b.field))
+##      b.field = initfield(b);
+##   endif
+## endfunction
+## @end group
+## @end example
+##
+## @seealso{loadobj, class}
+## @end deftypefn
+
+function b = saveobj (a)
+  error ("saveobj: not defined for class \"%s\"", class(a));
+endfunction
--- a/src/ChangeLog	Sun Oct 12 08:44:55 2008 +0200
+++ b/src/ChangeLog	Thu Oct 09 20:09:13 2008 +0100
@@ -36,6 +36,27 @@
 	(F__go_axes_init__): Flag error if handle is deleted during
 	initialization due.
 	
+2008-10-09  David Bateman  <dbateman@free.fr>
+
+	* ov-class.cc (Octave_map octave_class::map_value (void) const): 
+	Remove.
+	(bool octave_class::save_ascii (std::ostream&), 
+	bool octave_class::load_ascii (std::istream&),
+	bool octave_class::save_binary (std::ostream&, bool&),
+	bool octave_class::save_binary (std::ostream&, bool&),
+	bool octave_class::save_hdf5 (hid_t, const char *, bool),
+	bool octave_class::load_hdf5 (hid_t, const char *, bool)):
+	Allow saving and reloading of classes.
+	* ov-class. (Octave_map octave_class::map_value (void) const): 
+	Remove.
+	* ls-mat.cc (std::string read_mat5_binary_element (std::istream&, 
+	const std::string&, bool, bool&, octave_value&), 
+	int save_mat5_element_length (const octave_value&, const std::string&,
+	bool, bool)): Allow saving and loading of classes. 
+	* ls-oct-ascii.h (template <class T> bool extract_keyword 
+	(std::istream&, const char *, T&, const bool)): Initialize value with
+	null constructor rather than 0.
+	
 2008-10-07  David Bateman  <dbateman@free.fr>
 
 	* graphics.cc (F__go_delete__): Allow arrays of graphic handles.
--- a/src/ls-mat5.cc	Sun Oct 12 08:44:55 2008 +0200
+++ b/src/ls-mat5.cc	Thu Oct 09 20:09:13 2008 +0100
@@ -58,6 +58,7 @@
 #include "oct-obj.h"
 #include "oct-map.h"
 #include "ov-cell.h"
+#include "ov-class.h"
 #include "ov-fcn-inline.h"
 #include "pager.h"
 #include "pt-exp.h"
@@ -1099,8 +1100,18 @@
 	      }
 	    else
 	      {
-		warning ("load: objects are not implemented");
-		goto skip_ahead;
+		tc = new octave_class (m, classname);
+
+		if (load_path::find_method (classname, "loadobj") != 
+		    std::string())
+		  {
+		    octave_value_list tmp = feval ("loadobj", tc, 1);
+
+		    if (! error_state)
+		      tc = tmp(0);
+		    else
+		      goto data_read_error;
+		  }
 	      }
 	  }
 	else
@@ -1794,7 +1805,7 @@
       ret += save_mat5_array_length (m.fortran_vec (), m.nelem (),
 				     save_as_floats);
     }
-  else if (tc.is_map () || tc.is_inline_function ()) 
+  else if (tc.is_map () || tc.is_inline_function () || tc.is_object ()) 
     {
       int fieldcnt = 0;
       const Octave_map m = tc.map_value ();
@@ -1803,6 +1814,12 @@
       if (tc.is_inline_function ())
 	// length of "inline" is 6
 	ret += 8 + PAD (6 > max_namelen ? max_namelen : 6);
+      else if (tc.is_object ())
+	{
+	  int classlen = tc.class_name (). length ();
+
+	  ret += 8 + PAD (classlen > max_namelen ? max_namelen : classlen);
+	}
 
       for (Octave_map::const_iterator i = m.begin (); i != m.end (); i++)
 	fieldcnt++;
@@ -1942,7 +1959,7 @@
     flags |= MAT_FILE_STRUCT_CLASS;
   else if (tc.is_cell ())
     flags |= MAT_FILE_CELL_CLASS;
-  else if (tc.is_inline_function ())
+  else if (tc.is_inline_function () || tc.is_object ())
     flags |= MAT_FILE_OBJECT_CLASS;
   else
     {
@@ -2131,12 +2148,11 @@
       write_mat5_array (os, ::real (m_cmplx), save_as_floats);
       write_mat5_array (os, ::imag (m_cmplx), save_as_floats);
     }
-  else if (tc.is_map () || tc.is_inline_function()) 
+  else if (tc.is_map () || tc.is_inline_function() || tc.is_object ()) 
     {
-      const Octave_map m = tc.map_value ();
-      if (tc.is_inline_function ())
+      if (tc.is_inline_function () || tc.is_object ())
 	{
-	  std::string classname = "inline";
+	  std::string classname = tc.is_object() ? tc.class_name () : "inline";
 	  int namelen = classname.length ();
 
 	  if (namelen > max_namelen)
@@ -2151,6 +2167,20 @@
 	  os.write (paddedname, paddedlength);
 	}
 
+      Octave_map m;
+
+      if (tc.is_object () &&
+	  load_path::find_method (tc.class_name (), "saveobj") != std::string())
+	{
+	  octave_value_list tmp = feval ("saveobj", tc, 1);
+	  if (! error_state)
+	    m = tmp(0).map_value ();
+	  else
+	    goto error_cleanup;
+	}
+      else
+	m = tc.map_value ();
+
       // an Octave structure */
       // recursively write each element of the structure
       {
--- a/src/ls-oct-ascii.h	Sun Oct 12 08:44:55 2008 +0200
+++ b/src/ls-oct-ascii.h	Thu Oct 09 20:09:13 2008 +0100
@@ -72,7 +72,7 @@
 		 const bool next_only = false)
 {
   bool status = false;
-  value = 0;
+  value = T();
 
   char c;
   while (is.get (c))
--- a/src/ov-class.cc	Sun Oct 12 08:44:55 2008 +0200
+++ b/src/ov-class.cc	Thu Oct 09 20:09:13 2008 +0100
@@ -614,14 +614,6 @@
   return retval;
 }
 
-Octave_map
-octave_class::map_value (void) const
-{
-  Octave_map retval;
-  gripe_wrong_type_arg ("octave_class::map_value()", type_name ());
-  return retval;
-}
-
 string_vector
 octave_class::map_keys (void) const
 {
@@ -688,68 +680,31 @@
     }
 }
 
-bool 
-octave_class::save_ascii (std::ostream&, bool&)
-{
-  gripe_wrong_type_arg ("octave_class::save_ascii()", type_name ());
-  return false;
-}
-
-bool 
-octave_class::load_ascii (std::istream&)
-{
-  gripe_wrong_type_arg ("octave_class::load_ascii()", type_name ());
-  return false;
-}
-
-bool 
-octave_class::save_binary (std::ostream&, bool&)
-{
-  gripe_wrong_type_arg ("octave_class::save_binary()", type_name ());
-  return false;
-}
-
-bool 
-octave_class::load_binary (std::istream&, bool,
-				oct_mach_info::float_format)
+bool
+octave_class::save_ascii (std::ostream& os)
 {
-  gripe_wrong_type_arg ("octave_class::load_binary()", type_name ());
-  return false;
-}
-
-#if defined (HAVE_HDF5)
-
-bool
-octave_class::save_hdf5 (hid_t, const char *, bool)
-{
-  gripe_wrong_type_arg ("octave_class::save_binary()", type_name ());
-
-  return false;
-}
+  os << "# classname: " << class_name () << "\n";
+  Octave_map m;
+  if (load_path::find_method (class_name (), "saveobj") != std::string())
+    {
+      octave_value in = new octave_class (*this);
+      octave_value_list tmp = feval ("saveobj", in, 1);
+      if (! error_state)
+	m = tmp(0).map_value ();
+      else
+	return false;
+    }
+  else
+    m = map_value ();
 
-bool 
-octave_class::load_hdf5 (hid_t, const char *, bool)
-{
-  gripe_wrong_type_arg ("octave_class::load_binary()", type_name ());
-
-  return false;
-}
-
-#endif
-
-#if 0
-bool
-octave_class::save_ascii (std::ostream& os, bool& infnan_warned)
-{
-  Octave_map m = map_value ();
-  os << "# length: " << m.length () << "\n";
+  os << "# length: " << m.nfields () << "\n";
 
   Octave_map::iterator i = m.begin ();
   while (i != m.end ())
     {
       octave_value val = map.contents (i);
 
-      bool b = save_ascii_data (os, val, m.key (i), infnan_warned, false, 0);
+      bool b = save_ascii_data (os, val, m.key (i), false, 0);
       
       if (! b)
 	return os;
@@ -764,54 +719,82 @@
 octave_class::load_ascii (std::istream& is)
 {
   octave_idx_type len = 0;
+  std::string classname;
   bool success = true;
 
-  if (extract_keyword (is, "length", len) && len >= 0)
+  if (extract_keyword (is, "classname", classname) && classname != "")
     {
-      if (len > 0)
+      if (extract_keyword (is, "length", len) && len >= 0)
 	{
-	  Octave_map m (map);
+	  if (len > 0)
+	    {
+	      Octave_map m (map);
 
-	  for (octave_idx_type j = 0; j < len; j++)
-	    {
-	      octave_value t2;
-	      bool dummy;
+	      for (octave_idx_type j = 0; j < len; j++)
+		{
+		  octave_value t2;
+		  bool dummy;
 
-	      // recurse to read cell elements
-	      std::string nm
-		= read_ascii_data (is, std::string (), dummy, t2, j);
+		  // recurse to read cell elements
+		  std::string nm
+		    = read_ascii_data (is, std::string (), dummy, t2, j);
 
-	      if (!is)
-		break;
+		  if (!is)
+		    break;
 
-	      Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
+		  Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
 
-	      if (error_state)
-		{
-		  error ("load: internal error loading class elements");
-		  return false;
+		  if (error_state)
+		    {
+		      error ("load: internal error loading class elements");
+		      return false;
+		    }
+
+		  m.assign (nm, tcell);
 		}
 
-	      m.assign (nm, tcell);
-	    }
+	      if (is) 
+		{
+		  map = m;
+		  c_name = classname;
+
+		  if (load_path::find_method (classname, "loadobj") != 
+		      std::string())
+		    {
+		      octave_value in = new octave_class (*this);
+		      octave_value_list tmp = feval ("loadobj", in, 1);
 
-	  if (is) 
-	    map = m;
-	  else
-	    {
-	      error ("load: failed to load class");
-	      success = false;
+		      if (! error_state)
+			map = tmp(0).map_value ();
+		      else
+			success = false;
+		    }
+		}
+	      else
+		{
+		  error ("load: failed to load class");
+		  success = false;
+		}
 	    }
+	  else if (len == 0 )
+	    {
+	      map = Octave_map (dim_vector (1, 1));
+	      c_name = classname;
+	    }
+	  else
+	    panic_impossible ();
 	}
-      else if (len == 0 )
-	map = Octave_map (dim_vector (1, 1));
-      else
-	panic_impossible ();
+      else 
+	{
+	  error ("load: failed to extract number of elements in class");
+	  success = false;
+	}
     }
-  else {
-    error ("load: failed to extract number of elements in class");
-    success = false;
-  }
+  else
+    {
+      error ("load: failed to extract name of class");
+      success = false;
+    }
 
   return success;
 }
@@ -819,9 +802,25 @@
 bool 
 octave_class::save_binary (std::ostream& os, bool& save_as_floats)
 {
-  Octave_map m = map_value ();
+  int32_t classname_len = class_name().length ();
+
+  os.write (reinterpret_cast<char *> (&classname_len), 4);
+  os << class_name ();
 
-  int32_t len = m.length();
+  Octave_map m;
+  if (load_path::find_method (class_name (), "saveobj") != std::string())
+    {
+      octave_value in = new octave_class (*this);
+      octave_value_list tmp = feval ("saveobj", in, 1);
+      if (! error_state)
+	m = tmp(0).map_value ();
+      else
+	return false;
+    }
+  else
+    m = map_value ();
+
+  int32_t len = m.nfields();
   os.write (reinterpret_cast<char *> (&len), 4);
   
   Octave_map::iterator i = m.begin ();
@@ -845,6 +844,23 @@
 			    oct_mach_info::float_format fmt)
 {
   bool success = true;
+
+  int32_t classname_len;
+
+  is.read (reinterpret_cast<char *> (&classname_len), 4);
+  if (! is)
+    return false;
+  else if (swap)
+    swap_bytes<4> (&classname_len);
+
+  {
+    OCTAVE_LOCAL_BUFFER (char, classname, classname_len+1);
+    classname[classname_len] = '\0';
+    if (! is.read (reinterpret_cast<char *> (classname), classname_len))
+      return false;
+    c_name = classname;
+  }
+
   int32_t len;
   if (! is.read (reinterpret_cast<char *> (&len), 4))
     return false;
@@ -880,7 +896,20 @@
 	}
 
       if (is) 
-	map = m;
+	{
+	  map = m;
+
+	  if (load_path::find_method (class_name(), "loadobj") != std::string())
+	    {
+	      octave_value in = new octave_class (*this);
+	      octave_value_list tmp = feval ("loadobj", in, 1);
+
+	      if (! error_state)
+		map = tmp(0).map_value ();
+	      else
+		success = false;
+	    }
+	}
       else
 	{
 	  error ("load: failed to load class");
@@ -900,14 +929,53 @@
 bool
 octave_class::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats)
 {
+  hsize_t hdims[3];
+  hid_t group_hid = -1;
+  hid_t type_hid = -1;
+  hid_t space_hid = -1;
+  hid_t class_hid = -1;
   hid_t data_hid = -1;
+  Octave_map m;
+  Octave_map::iterator i;
+
+  group_hid = H5Gcreate (loc_id, name, 0);
+  if (group_hid < 0)
+    goto error_cleanup;
+
+  // Add the class name to the group
+  type_hid = H5Tcopy (H5T_C_S1); H5Tset_size (type_hid, c_name.length () + 1);
+  if (type_hid < 0)
+    goto error_cleanup;
 
-  data_hid = H5Gcreate (loc_id, name, 0);
-  if (data_hid < 0) return false;
+  hdims[0] = 0;
+  space_hid = H5Screate_simple (0 , hdims, 0);
+  if (space_hid < 0)
+    goto error_cleanup;
+
+  class_hid = H5Dcreate (group_hid, "classname",  type_hid, space_hid,
+			 H5P_DEFAULT);
+  if (class_hid < 0 || H5Dwrite (class_hid, type_hid, H5S_ALL, H5S_ALL, 
+				    H5P_DEFAULT, c_name.c_str ()) < 0)
+    goto error_cleanup;
+
+  data_hid = H5Gcreate (group_hid, "value", 0);
+  if (data_hid < 0)
+    goto error_cleanup;
+
+  if (load_path::find_method (class_name (), "saveobj") != std::string())
+    {
+      octave_value in = new octave_class (*this);
+      octave_value_list tmp = feval ("saveobj", in, 1);
+      if (! error_state)
+	m = tmp(0).map_value ();
+      else
+	goto error_cleanup;
+    }
+  else
+    m = map_value ();
 
   // recursively add each element of the class to this group
-  Octave_map m = map_value ();
-  Octave_map::iterator i = m.begin ();
+  i = m.begin ();
   while (i != m.end ())
     {
       octave_value val = map.contents (i);
@@ -921,7 +989,22 @@
       i++;
     }
 
-  H5Gclose (data_hid);
+ error_cleanup:
+
+  if (data_hid > 0)
+    H5Gclose (data_hid);
+
+  if (class_hid > 0)
+    H5Dclose (class_hid);
+
+  if (space_hid > 0)
+    H5Sclose (space_hid);
+
+  if (type_hid > 0)
+    H5Tclose (type_hid);
+
+  if (group_hid > 0)
+    H5Gclose (group_hid);
 
   return true;
 }
@@ -932,22 +1015,87 @@
 {
   bool retval = false;
 
+  hid_t group_hid = -1;
+  hid_t data_hid = -1;
+  hid_t type_hid = -1;
+  hid_t type_class_hid = -1;
+  hid_t space_hid = -1;
+  hid_t subgroup_hid = -1; 
+  hid_t st_id = -1;
+
   hdf5_callback_data dsub;
 
   herr_t retval2 = 0;
   Octave_map m (dim_vector (1, 1));
   int current_item = 0;
+  hsize_t num_obj = 0;
+  int slen = 0;
+  hsize_t rank = 0;
+
+  group_hid = H5Gopen (loc_id, name);
+  if (group_hid < 0)
+    goto error_cleanup;
+
+  
+  data_hid = H5Dopen (group_hid, "classname");
+
+  if (data_hid < 0)
+    goto error_cleanup;
+
+  type_hid = H5Dget_type (data_hid);
+
+  type_class_hid = H5Tget_class (type_hid);
+
+  if (type_class_hid != H5T_STRING)
+    goto error_cleanup;
+	  
+  space_hid = H5Dget_space (data_hid);
+  rank = H5Sget_simple_extent_ndims (space_hid);
+
+  if (rank != 0)
+    goto error_cleanup;
+
+  slen = H5Tget_size (type_hid);
+  if (slen < 0)
+    goto error_cleanup;
+
+  // do-while loop here to prevent goto crossing initialization of classname
+  do
+    {
+      OCTAVE_LOCAL_BUFFER (char, classname, slen);
+
+      // create datatype for (null-terminated) string to read into:
+      st_id = H5Tcopy (H5T_C_S1);
+      H5Tset_size (st_id, slen);
+
+      if (H5Dread (data_hid, st_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, 
+		   classname) < 0)
+	{
+	  H5Tclose (st_id);
+	  H5Dclose (data_hid);
+	  H5Gclose (group_hid);
+	  return false;
+	}
+     
+      H5Tclose (st_id);
+      H5Dclose (data_hid);
+      data_hid = -1;
+
+      c_name = classname;
+    }
+  while (0);
+
+
 #ifdef HAVE_H5GGET_NUM_OBJS
-  hsize_t num_obj = 0;
-  hid_t group_id = H5Gopen (loc_id, name); 
-  H5Gget_num_objs (group_id, &num_obj);
-  H5Gclose (group_id);
+  subgroup_hid = H5Gopen (group_hid, name); 
+  H5Gget_num_objs (subgroup_hid, &num_obj);
+  H5Gclose (subgroup_hid);
 
   while (current_item < static_cast<int> (num_obj)
-	 && (retval2 = H5Giterate (loc_id, name, &current_item,
+	 && (retval2 = H5Giterate (group_hid, name, &current_item,
 				   hdf5_read_next_data, &dsub)) > 0)
 #else
-  while ((retval2 = H5Giterate (loc_id, name, &current_item,
+  while ((retval2 = H5Giterate (group_hid, name, &current_item,
 				hdf5_read_next_data, &dsub)) > 0)
 #endif
     {
@@ -970,16 +1118,36 @@
   if (retval2 >= 0)
     {
       map = m;
-      retval = true;
+
+      if (load_path::find_method (class_name(), "loadobj") != std::string())
+	{
+	  octave_value in = new octave_class (*this);
+	  octave_value_list tmp = feval ("loadobj", in, 1);
+
+	  if (! error_state)
+	    {
+	      map = tmp(0).map_value ();
+	      retval = true;
+	    }
+	  else
+	    retval = false;
+	}
+      else
+	retval = true;
     }
   
+ error_cleanup:
+  if (data_hid > 0)
+    H5Dclose (data_hid);
+
+  if (data_hid > 0)
+    H5Gclose (group_hid);
+
   return retval;
 }
 
 #endif
 
-#endif
-
 mxArray *
 octave_class::as_mxArray (void) const
 {
--- a/src/ov-class.h	Sun Oct 12 08:44:55 2008 +0200
+++ b/src/ov-class.h	Thu Oct 09 20:09:13 2008 +0100
@@ -110,7 +110,7 @@
 
   bool is_object (void) const { return true; }
 
-  Octave_map map_value (void) const;
+  Octave_map map_value (void) const { return map; }
 
   string_vector map_keys (void) const;
 
@@ -123,7 +123,7 @@
   void print_with_name (std::ostream& os, const std::string& name, 
 			bool print_padding = true) const;
 
-  bool save_ascii (std::ostream& os, bool& infnan_warned);
+  bool save_ascii (std::ostream& os);
 
   bool load_ascii (std::istream& is);