diff --git a/bob/io/__init__.py b/bob/io/__init__.py
index 2ab1e28b150f0549def9963e9e87de3fdd6b2579..edbb4090fca046b19d22d3982711084621bff3be 100644
--- a/bob/io/__init__.py
+++ b/bob/io/__init__.py
@@ -1,3 +1,4 @@
 # see https://docs.python.org/3/library/pkgutil.html
 from pkgutil import extend_path
+
 __path__ = extend_path(__path__, __name__)
diff --git a/bob/io/base/__init__.py b/bob/io/base/__init__.py
index dbe34b9e2e60149ed198e8d6da2d299479eb897b..a32b34115daf0aacdafa2abb5832035de9695613 100644
--- a/bob/io/base/__init__.py
+++ b/bob/io/base/__init__.py
@@ -1,512 +1,431 @@
 # import Libraries of other lib packages
-import numpy
-import bob.core
+import numpy as np
+import h5py
+from pygments import format
+import imageio
+import cv2
+from PIL import Image
+from .utils import to_bob
 
-# import our own Library
-import bob.extension
-bob.extension.load_bob_library('bob.io.base', __file__)
-
-from ._library import File as _File_C, HDF5File as _HDF5File_C, extensions
-from . import version
-from .version import module as __version__
-from .version import api as __api_version__
 
 import os
 
 
-class File(_File_C):
-  __doc__ = _File_C.__doc__
-
-  def __enter__(self):
-    return self
-
-  def __exit__(self, type, value, traceback):
-    self.close()
-
-
-class HDF5File(_HDF5File_C):
-  __doc__ = _HDF5File_C.__doc__
-
-  def __enter__(self):
-    return self
-
-  def __exit__(self, type, value, traceback):
-    return self.close()
-
-  def __contains__(self, x):
-    __doc__ = self.has_key.__doc__
-    return self.has_key(x)
-
-  def __iter__(self):
-    __doc__ = self.keys.__doc__
-    return iter(self.keys())
-
-  def __getitem__(self, name):
-    __doc__ = self.get.__doc__
-    return self.get(name)
-
-  def __setitem__(self, name, value):
-    __doc__ = self.set.__doc__
-    return self.set(name, value)
-
-  def values(self):
-    '''Yields the datasets contained in the current directory.
-
-    Yields
-    -------
-    object
-        The datasets that are being read.
-    '''
-    return (self[key] for key in self)
-
-  def items(self):
-    '''Yields the keys and the datasets contained in the current directory.
-
-    Yields
-    -------
-    tuple
-        The key and the datasets that are being read in a tuple.
-    '''
-    return ((key, self[key]) for key in self)
+hdf5_extensions = [".hdf5", ".h5", ".hdf", ".hdf5", ".h5", ".hdf", ".hdf5"]
+image_extensions = [
+    ".jpg",
+    ".jpeg",
+    ".png",
+    ".bmp",
+    ".gif",
+    ".tif",
+    ".tiff",
+    ".pgm",
+    ".pbm",
+    ".pnm",
+    ".ppm",
+]
 
 
 def _is_string(s):
-  """Returns ``True`` if the given object is a string
+    """Returns ``True`` if the given object is a string
 
-  This method can be used with Python-2.x or 3.x and returns a string
-  respecting each environment's constraints.
-  """
+    This method can be used with Python-2.x or 3.x and returns a string
+    respecting each environment's constraints.
+    """
 
-  from sys import version_info
+    from sys import version_info
 
-  return (version_info[0] < 3 and isinstance(s, (str, unicode))) or \
-      isinstance(s, (bytes, str))
+    return (version_info[0] < 3 and isinstance(s, (str, unicode))) or isinstance(
+        s, (bytes, str)
+    )
 
 
-@numpy.deprecate(new_name="os.makedirs(directory, exist_ok=True)")
+@np.deprecate(new_name="os.makedirs(directory, exist_ok=True)")
 def create_directories_safe(directory, dryrun=False):
-  """Creates a directory if it does not exists, with concurrent access support.
-  This function will also create any parent directories that might be required.
-  If the dryrun option is selected, it does not actually create the directory,
-  but just writes the (Linux) command that would have been executed.
-
-  **Parameters:**
-
-  ``directory`` : str
-    The directory that you want to create.
-
-  ``dryrun`` : bool
-    Only ``print`` the command to console, but do not execute it.
-  """
-  if dryrun:
-    print("[dry-run] mkdir -p '%s'" % directory)
-  else:
-    os.makedirs(directory, exist_ok=True)
-
-
-def load(inputs):
-  """load(inputs) -> data
-
-  Loads the contents of a file, an iterable of files, or an iterable of
-  :py:class:`bob.io.base.File`'s into a :py:class:`numpy.ndarray`.
-
-  **Parameters:**
-
-  ``inputs`` : various types
-
-    This might represent several different entities:
-
-    1. The name of a file (full path) from where to load the data. In this
-       case, this assumes that the file contains an array and returns a loaded
-       numpy ndarray.
-    2. An iterable of filenames to be loaded in memory. In this case, this
-       would assume that each file contains a single 1D sample or a set of 1D
-       samples, load them in memory and concatenate them into a single and
-       returned 2D :py:class:`numpy.ndarray`.
-    3. An iterable of :py:class:`File`. In this case, this would assume
-       that each :py:class:`File` contains a single 1D sample or a set
-       of 1D samples, load them in memory if required and concatenate them into
-       a single and returned 2D :py:class:`numpy.ndarray`.
-    4. An iterable with mixed filenames and :py:class:`File`. In this
-       case, this would returned a 2D :py:class:`numpy.ndarray`, as described
-       by points 2 and 3 above.
-
-  **Returns:**
-
-  ``data`` : :py:class:`numpy.ndarray`
-    The data loaded from the given ``inputs``.
-  """
-
-  from collections.abc import Iterable
-  import numpy
-  if _is_string(inputs):
-    if not os.path.exists(inputs):
-      raise RuntimeError(f"`{inputs}' does not exist!")
-    return File(inputs, 'r').read()
-  elif isinstance(inputs, Iterable):
-    retval = []
-    for obj in inputs:
-      if _is_string(obj):
-        retval.append(load(obj))
-      elif isinstance(obj, File):
-        retval.append(obj.read())
-      else:
-        raise TypeError(
-            "Iterable contains an object which is not a filename nor a "
-            "bob.io.base.File.")
-    return numpy.vstack(retval)
-  else:
-    raise TypeError(
-        "Unexpected input object. This function is expecting a filename, "
-        "or an iterable of filenames and/or bob.io.base.File's")
-
-
-def merge(filenames):
-  """merge(filenames) -> files
+    """Creates a directory if it does not exists, with concurrent access support.
+    This function will also create any parent directories that might be required.
+    If the dryrun option is selected, it does not actually create the directory,
+    but just writes the (Linux) command that would have been executed.
 
-  Converts an iterable of filenames into an iterable over read-only
-  :py:class:`bob.io.base.File`'s.
+    **Parameters:**
 
-  **Parameters:**
+    ``directory`` : str
+      The directory that you want to create.
 
-  ``filenames`` : str or [str]
-
-    A list of file names.
-    This might represent:
-
-    1. A single filename. In this case, an iterable with a single
-       :py:class:`File` is returned.
-    2. An iterable of filenames to be converted into an iterable of
-       :py:class:`File`'s.
-
-  **Returns:**
+    ``dryrun`` : bool
+      Only ``print`` the command to console, but do not execute it.
+    """
+    if dryrun:
+        print("[dry-run] mkdir -p '%s'" % directory)
+    else:
+        os.makedirs(directory, exist_ok=True)
 
-  ``files`` : [:py:class:`File`]
-    The list of files.
-  """
 
-  from collections import Iterable
-  from .utils import is_string
-  if is_string(filenames):
-    return [File(filenames, 'r')]
-  elif isinstance(filenames, Iterable):
-    return [File(k, 'r') for k in filenames]
-  else:
-    raise TypeError(
-        "Unexpected input object. This function is expecting an "
-        "iterable of filenames.")
+def open_file(filename):
+    """open_file(filename) -> file
 
+    Opens a file for reading.
 
-def save(array, filename, create_directories=False):
-  """Saves the contents of an array-like object to file.
+    Parameters
+    ----------
 
-  Effectively, this is the same as creating a :py:class:`File` object
-  with the mode flag set to ``'w'`` (write with truncation) and calling
-  :py:meth:`File.write` passing ``array`` as parameter.
+    ``filename`` : str
+      The name of the file to open.
 
-  Parameters:
 
-  ``array`` : array_like
-    The array-like object to be saved on the file
+    """
 
-  ``filename`` : str
-    The name of the file where you need the contents saved to
+    def check_gray(img):
+        # Checking for gray scaled images
+        if (
+            img.ndim > 2
+            and np.allclose(img[:, :, 0], img[:, :, 1])
+            and np.allclose(img[:, :, 0], img[:, :, 2])
+        ):
+            img = img[:, :, 0]
+        return img
 
-  ``create_directories`` : bool
-    Automatically generate the directories if required (defaults to ``False``
-    because of compatibility reasons; might change in future to default to
-    ``True``)
-  """
-  # create directory if not existent yet
-  if create_directories:
-    create_directories_safe(os.path.dirname(filename))
+    extension = os.path.splitext(filename)[1]  # get the extension
 
-  # requires data is c-contiguous and aligned, will create a copy otherwise
-  array = numpy.require(array, requirements=('C_CONTIGUOUS', 'ALIGNED'))
+    if extension in hdf5_extensions:
+        with h5py.File(filename, "r") as f:
+            if "array" not in f.keys():
+                raise RuntimeError(
+                    "The file '%s' does not contain the key 'array'" % filename
+                )
 
-  return File(filename, 'w').write(array)
+            return np.array(f["array"])
+    elif extension in image_extensions:
 
-# Just to make it homogenous with the C++ API
-write = save
-read = load
+        img = imageio.imread(filename)
 
+        # PNGs have a 4th channel, which we don't want
+        # Alpha channels for instance have to be ignored
+        if extension.lower() == ".png":
+            img = img[:, :, 0:3]
 
-def append(array, filename):
-  """append(array, filename) -> position
-
-  Appends the contents of an array-like object to file.
+        img = check_gray(img)
+        return img if img.ndim == 2 else to_bob(img)
+    else:
+        raise RuntimeError(f"Unknown file extension: {extension}")
 
-  Effectively, this is the same as creating a :py:class:`File` object
-  with the mode flag set to ``'a'`` (append) and calling
-  :py:meth:`File.append` passing ``array`` as parameter.
 
-  **Parameters:**
+def write_file(filename, data, format="pillow"):
+    """
+    write_file(filename, data) -> None
 
-  ``array`` : array_like
-    The array-like object to be saved on the file
+    Writes the contents of a :py:class:`numpy.ndarray` to a file.
 
-  ``filename`` : str
-    The name of the file where you need the contents saved to
+    Parameters
+    ----------
 
-  **Returns:**
+    ``filename`` : str
+      The name of the file to write to.
 
-  ``position`` : int
-    See :py:meth:`File.append`
-  """
+    ``data`` : :py:class:`numpy.ndarray`
+      The data to write to the file.
 
-  # requires data is c-contiguous and aligned, will create a copy otherwise
-  array = numpy.require(array, requirements=('C_CONTIGUOUS', 'ALIGNED'))
+    ``format`` : str
+      The format to use to read the file. By default imageio selects the appropriate for you based on the filename and its contents
 
-  return File(filename, 'a').append(array)
 
+    """
 
-def peek(filename):
-  """peek(filename) -> dtype, shape, stride
+    extension = os.path.splitext(filename)[1]  # get the extension
 
-  Returns the type of array (frame or sample) saved in the given file.
+    if extension in hdf5_extensions:
+        with h5py.File(filename, "w") as f:
+            f["array"] = data
+    elif extension in image_extensions:
+        # Pillow is the format with the best support for all image formats
+        imageio.imwrite(filename, data, format=format)
+    else:
+        raise RuntimeError(f"Unknown file extension: {extension}")
 
-  Effectively, this is the same as creating a :py:class:`File` object
-  with the mode flag set to `r` (read-only) and calling
-  :py:meth:`File.describe`.
 
-  **Parameters**:
+def load(inputs):
+    """load(inputs) -> data
+
+    Loads the contents of a file, an iterable of files, or an iterable of
+    :py:class:`bob.io.base.File`'s into a :py:class:`numpy.ndarray`.
+
+    **Parameters:**
+
+    ``inputs`` : various types
+
+      This might represent several different entities:
+
+      1. The name of a file (full path) from where to load the data. In this
+         case, this assumes that the file contains an array and returns a loaded
+         numpy ndarray.
+      2. An iterable of filenames to be loaded in memory. In this case, this
+         would assume that each file contains a single 1D sample or a set of 1D
+         samples, load them in memory and concatenate them into a single and
+         returned 2D :py:class:`numpy.ndarray`.
+      3. An iterable of :py:class:`File`. In this case, this would assume
+         that each :py:class:`File` contains a single 1D sample or a set
+         of 1D samples, load them in memory if required and concatenate them into
+         a single and returned 2D :py:class:`numpy.ndarray`.
+      4. An iterable with mixed filenames and :py:class:`File`. In this
+         case, this would returned a 2D :py:class:`numpy.ndarray`, as described
+         by points 2 and 3 above.
+
+    **Returns:**
+
+    ``data`` : :py:class:`numpy.ndarray`
+      The data loaded from the given ``inputs``.
+    """
+
+    from collections.abc import Iterable
+    import numpy
+
+    if _is_string(inputs):
+        if not os.path.exists(inputs):
+            raise RuntimeError(f"`{inputs}' does not exist!")
+        return open_file(inputs)
+
+    elif isinstance(inputs, Iterable):
+        retval = []
+        for obj in inputs:
+            if _is_string(obj):
+                retval.append(load(obj))
+            # elif isinstance(obj, File):
+            #    retval.append(obj.read())
+            else:
+                raise TypeError(
+                    "Iterable contains an object which is not a filename nor a "
+                    "bob.io.base.File."
+                )
+        return numpy.vstack(retval)
+    else:
+        raise TypeError(
+            "Unexpected input object. This function is expecting a filename, "
+            "or an iterable of filenames and/or bob.io.base.File's"
+        )
 
-  ``filename`` : str
-    The name of the file to peek information from
 
-  **Returns:**
+def save(array, filename, create_directories=False):
+    """Saves the contents of an array-like object to file.
 
-  ``dtype, shape, stride`` : see :py:meth:`File.describe`
-  """
-  return File(filename, 'r').describe()
+    Effectively, this is the same as creating a :py:class:`File` object
+    with the mode flag set to ``'w'`` (write with truncation) and calling
+    :py:meth:`File.write` passing ``array`` as parameter.
 
+    Parameters:
 
-def peek_all(filename):
-  """peek_all(filename) -> dtype, shape, stride
+    ``array`` : array_like
+      The array-like object to be saved on the file
 
-  Returns the type of array (for full readouts) saved in the given file.
+    ``filename`` : str
+      The name of the file where you need the contents saved to
 
-  Effectively, this is the same as creating a :py:class:`File` object
-  with the mode flag set to ``'r'`` (read-only) and returning
-  ``File.describe`` with its parameter ``all`` set to ``True``.
+    ``create_directories`` : bool
+      Automatically generate the directories if required (defaults to ``False``
+      because of compatibility reasons; might change in future to default to
+      ``True``)
+    """
+    # create directory if not existent yet
+    if create_directories:
+        create_directories_safe(os.path.dirname(filename))
 
-  **Parameters:**
+    # requires data is c-contiguous and aligned, will create a copy otherwise
+    array = np.require(array, requirements=("C_CONTIGUOUS", "ALIGNED"))
 
-  ``filename`` : str
-    The name of the file to peek information from
+    write_file(filename, array)
 
-  **Returns:**
 
-  ``dtype, shape, stride`` : see :py:meth:`File.describe`
-  """
-  return File(filename, 'r').describe(all=True)
+# Just to make it homogenous with the C++ API
+write = save
+read = load
 
 
 # Keeps compatibility with the previously existing API
-open = File
-
-
-def get_config():
-  """Returns a string containing the configuration information.
-  """
-  return bob.extension.get_config(__name__, version.externals, version.api)
+# open = File
 
 
 def get_include_directories():
-  """get_include_directories() -> includes
-
-  Returns a list of include directories for dependent libraries, such as HDF5.
-  This function is automatically used by
-  :py:func:`bob.extension.get_bob_libraries` to retrieve the non-standard
-  include directories that are required to use the C bindings of this library
-  in dependent classes. You shouldn't normally need to call this function by
-  hand.
-
-  **Returns:**
-
-  ``includes`` : [str]
-    The list of non-standard include directories required to use the C bindings
-    of this class. For now, only the directory for the HDF5 headers are
-    returned.
-  """
-  # try to use pkg_config first
-  try:
-    from bob.extension.utils import find_header
-    # locate pkg-config on our own
-    header = 'hdf5.h'
-    candidates = find_header(header)
-    if not candidates:
-      raise RuntimeError(
-          "could not find %s's `%s' - have you installed %s on this "
-          "machine?" % ('hdf5', header, 'hdf5'))
-
-    return [os.path.dirname(candidates[0])]
-  except RuntimeError:
-    from bob.extension import pkgconfig
-    pkg = pkgconfig('hdf5')
-    return pkg.include_directories()
-
-
-def get_macros():
-  """get_macros() -> macros
-
-  Returns a list of preprocessor macros, such as ``(HAVE_HDF5, 1)``. This
-  function is automatically used by :py:func:`bob.extension.get_bob_libraries`
-  to retrieve the prerpocessor definitions that are required to use the C
-  bindings of this library in dependent classes. You shouldn't normally need to
-  call this function by hand.
-
-  **Returns:**
-
-  ``macros`` : [(str,str)]
-    The list of preprocessor macros required to use the C bindings of this
-    class. For now, only ``('HAVE_HDF5', '1')`` is returned, when applicable.
-  """
-  # get include directories
-  if get_include_directories():
-    return [('HAVE_HDF5', '1')]
+    """get_include_directories() -> includes
+
+    Returns a list of include directories for dependent libraries, such as HDF5.
+    This function is automatically used by
+    :py:func:`bob.extension.get_bob_libraries` to retrieve the non-standard
+    include directories that are required to use the C bindings of this library
+    in dependent classes. You shouldn't normally need to call this function by
+    hand.
+
+    **Returns:**
+
+    ``includes`` : [str]
+      The list of non-standard include directories required to use the C bindings
+      of this class. For now, only the directory for the HDF5 headers are
+      returned.
+    """
+    # try to use pkg_config first
+    try:
+        from bob.extension.utils import find_header
+
+        # locate pkg-config on our own
+        header = "hdf5.h"
+        candidates = find_header(header)
+        if not candidates:
+            raise RuntimeError(
+                "could not find %s's `%s' - have you installed %s on this "
+                "machine?" % ("hdf5", header, "hdf5")
+            )
+
+        return [os.path.dirname(candidates[0])]
+    except RuntimeError:
+        from bob.extension import pkgconfig
+
+        pkg = pkgconfig("hdf5")
+        return pkg.include_directories()
 
 
 def _generate_features(reader, paths, same_size=False):
-  """Load and stack features in a memory efficient way. This function is
-  meant to be used inside :py:func:`vstack_features`.
-
-  Parameters
-  ----------
-  reader : ``collections.Callable``
-    See the documentation of :py:func:`vstack_features`.
-  paths : ``collections.Iterable``
-    See the documentation of :py:func:`vstack_features`.
-  same_size : :obj:`bool`, optional
-    See the documentation of :py:func:`vstack_features`.
-
-  Yields
-  ------
-  object
-    The first object returned is a tuple of :py:class:`numpy.dtype` of
-    features and the shape of the first feature. The rest of objects are
-    the actual values in features. The features are returned in C order.
-  """
-
-  shape_determined = False
-  for i, path in enumerate(paths):
-
-    feature = numpy.atleast_2d(reader(path))
-    feature = numpy.ascontiguousarray(feature)
-    if not shape_determined:
-      shape_determined = True
-      dtype = feature.dtype
-      shape = list(feature.shape)
-      yield (dtype, shape)
-    else:
-      # make sure all features have the same shape and dtype
-      if same_size:
-        assert shape == list(feature.shape), f"Expected feature shape of {shape}, got {feature.shape}"
-      else:
-        assert shape[1:] == list(feature.shape[1:]), f"Ignoring first dimension, expected feature shape of {shape}, got {feature.shape}"
-      assert dtype == feature.dtype
+    """Load and stack features in a memory efficient way. This function is
+    meant to be used inside :py:func:`vstack_features`.
+
+    Parameters
+    ----------
+    reader : ``collections.Callable``
+      See the documentation of :py:func:`vstack_features`.
+    paths : ``collections.Iterable``
+      See the documentation of :py:func:`vstack_features`.
+    same_size : :obj:`bool`, optional
+      See the documentation of :py:func:`vstack_features`.
 
-    if same_size:
-      yield (feature.ravel(),)
-    else:
-      for feat in feature:
-        yield (feat.ravel(),)
+    Yields
+    ------
+    object
+      The first object returned is a tuple of :py:class:`numpy.dtype` of
+      features and the shape of the first feature. The rest of objects are
+      the actual values in features. The features are returned in C order.
+    """
+
+    shape_determined = False
+    for i, path in enumerate(paths):
+
+        feature = np.atleast_2d(reader(path))
+        feature = np.ascontiguousarray(feature)
+        if not shape_determined:
+            shape_determined = True
+            dtype = feature.dtype
+            shape = list(feature.shape)
+            yield (dtype, shape)
+        else:
+            # make sure all features have the same shape and dtype
+            if same_size:
+                assert shape == list(
+                    feature.shape
+                ), f"Expected feature shape of {shape}, got {feature.shape}"
+            else:
+                assert shape[1:] == list(
+                    feature.shape[1:]
+                ), f"Ignoring first dimension, expected feature shape of {shape}, got {feature.shape}"
+            assert dtype == feature.dtype
+
+        if same_size:
+            yield (feature.ravel(),)
+        else:
+            for feat in feature:
+                yield (feat.ravel(),)
 
 
 def vstack_features(reader, paths, same_size=False, dtype=None):
-  """Stacks all features in a memory efficient way.
-
-  Parameters
-  ----------
-  reader : ``collections.Callable``
-    The function to load the features. The function should only take one
-    argument ``path`` and return loaded features. Use :any:`functools.partial`
-    to accommodate your reader to this format.
-    The features returned by ``reader`` are expected to have the same
-    :py:class:`numpy.dtype` and the same shape except for their first
-    dimension. First dimension should correspond to the number of samples.
-  paths : ``collections.Iterable``
-    An iterable of paths to iterate on. Whatever is inside path is given to
-    ``reader`` so they do not need to be necessarily paths to actual files.
-    If ``same_size`` is ``True``, ``len(paths)`` must be valid.
-  same_size : :obj:`bool`, optional
-    If ``True``, it assumes that arrays inside all the paths are the same
-    shape. If you know the features are the same size in all paths, set this
-    to ``True`` to improve the performance.
-  dtype : :py:class:`numpy.dtype`, optional
-    If provided, the data will be casted to this format.
-
-  Returns
-  -------
-  numpy.ndarray
-    The read features with the shape ``(n_samples, *features_shape[1:])``.
-
-  Examples
-  --------
-  This function in a simple way is equivalent to calling
-  ``numpy.vstack([reader(p) for p in paths])``.
-
-  >>> import numpy
-  >>> from bob.io.base import vstack_features
-  >>> def reader(path):
-  ...     # in each file, there are 5 samples and features are 2 dimensional.
-  ...     return numpy.arange(10).reshape(5,2)
-  >>> paths = ['path1', 'path2']
-  >>> all_features = vstack_features(reader, paths)
-  >>> numpy.allclose(all_features, numpy.array(
-  ...     [[0, 1],
-  ...      [2, 3],
-  ...      [4, 5],
-  ...      [6, 7],
-  ...      [8, 9],
-  ...      [0, 1],
-  ...      [2, 3],
-  ...      [4, 5],
-  ...      [6, 7],
-  ...      [8, 9]]))
-  True
-  >>> all_features_with_more_memory = numpy.vstack([reader(p) for p in paths])
-  >>> numpy.allclose(all_features, all_features_with_more_memory)
-  True
-
-  You can allocate the array at once to improve the performance if you know
-  that all features in paths have the same shape and you know the total number
-  of the paths:
-
-  >>> all_features = vstack_features(reader, paths, same_size=True)
-  >>> numpy.allclose(all_features, numpy.array(
-  ...     [[0, 1],
-  ...      [2, 3],
-  ...      [4, 5],
-  ...      [6, 7],
-  ...      [8, 9],
-  ...      [0, 1],
-  ...      [2, 3],
-  ...      [4, 5],
-  ...      [6, 7],
-  ...      [8, 9]]))
-  True
-  """
-  iterable = _generate_features(reader, paths, same_size)
-  data_dtype, shape = next(iterable)
-  if dtype is None:
-    dtype = data_dtype
-  if same_size:
-    # numpy black magic: https://stackoverflow.com/a/12473478/1286165
-    field_dtype = [("", (dtype, (numpy.prod(shape),)))]
-    total_size = len(paths)
-    all_features = numpy.fromiter(iterable, field_dtype, total_size)
-  else:
-    field_dtype = [("", (dtype, (numpy.prod(shape[1:]),)))]
-    all_features = numpy.fromiter(iterable, field_dtype)
-
-  # go from a field array to a normal array
-  all_features = all_features.view(dtype)
-  # the shape is assumed to be (n_samples, ...) it can be (5, 2) or (5, 3, 4).
-  shape = list(shape)
-  shape[0] = -1
-  return numpy.reshape(all_features, shape, order="C")
+    """Stacks all features in a memory efficient way.
+
+    Parameters
+    ----------
+    reader : ``collections.Callable``
+      The function to load the features. The function should only take one
+      argument ``path`` and return loaded features. Use :any:`functools.partial`
+      to accommodate your reader to this format.
+      The features returned by ``reader`` are expected to have the same
+      :py:class:`numpy.dtype` and the same shape except for their first
+      dimension. First dimension should correspond to the number of samples.
+    paths : ``collections.Iterable``
+      An iterable of paths to iterate on. Whatever is inside path is given to
+      ``reader`` so they do not need to be necessarily paths to actual files.
+      If ``same_size`` is ``True``, ``len(paths)`` must be valid.
+    same_size : :obj:`bool`, optional
+      If ``True``, it assumes that arrays inside all the paths are the same
+      shape. If you know the features are the same size in all paths, set this
+      to ``True`` to improve the performance.
+    dtype : :py:class:`numpy.dtype`, optional
+      If provided, the data will be casted to this format.
+
+    Returns
+    -------
+    numpy.ndarray
+      The read features with the shape ``(n_samples, *features_shape[1:])``.
+
+    Examples
+    --------
+    This function in a simple way is equivalent to calling
+    ``numpy.vstack([reader(p) for p in paths])``.
+
+    >>> import numpy
+    >>> from bob.io.base import vstack_features
+    >>> def reader(path):
+    ...     # in each file, there are 5 samples and features are 2 dimensional.
+    ...     return numpy.arange(10).reshape(5,2)
+    >>> paths = ['path1', 'path2']
+    >>> all_features = vstack_features(reader, paths)
+    >>> numpy.allclose(all_features, numpy.array(
+    ...     [[0, 1],
+    ...      [2, 3],
+    ...      [4, 5],
+    ...      [6, 7],
+    ...      [8, 9],
+    ...      [0, 1],
+    ...      [2, 3],
+    ...      [4, 5],
+    ...      [6, 7],
+    ...      [8, 9]]))
+    True
+    >>> all_features_with_more_memory = numpy.vstack([reader(p) for p in paths])
+    >>> numpy.allclose(all_features, all_features_with_more_memory)
+    True
+
+    You can allocate the array at once to improve the performance if you know
+    that all features in paths have the same shape and you know the total number
+    of the paths:
+
+    >>> all_features = vstack_features(reader, paths, same_size=True)
+    >>> numpy.allclose(all_features, numpy.array(
+    ...     [[0, 1],
+    ...      [2, 3],
+    ...      [4, 5],
+    ...      [6, 7],
+    ...      [8, 9],
+    ...      [0, 1],
+    ...      [2, 3],
+    ...      [4, 5],
+    ...      [6, 7],
+    ...      [8, 9]]))
+    True
+    """
+    iterable = _generate_features(reader, paths, same_size)
+    data_dtype, shape = next(iterable)
+    if dtype is None:
+        dtype = data_dtype
+    if same_size:
+        # numpy black magic: https://stackoverflow.com/a/12473478/1286165
+        field_dtype = [("", (dtype, (np.prod(shape),)))]
+        total_size = len(paths)
+        all_features = np.fromiter(iterable, field_dtype, total_size)
+    else:
+        field_dtype = [("", (dtype, (np.prod(shape[1:]),)))]
+        all_features = np.fromiter(iterable, field_dtype)
+
+    # go from a field array to a normal array
+    all_features = all_features.view(dtype)
+    # the shape is assumed to be (n_samples, ...) it can be (5, 2) or (5, 3, 4).
+    shape = list(shape)
+    shape[0] = -1
+    return np.reshape(all_features, shape, order="C")
 
 
 # gets sphinx autodoc done right - don't remove it
-__all__ = [_ for _ in dir() if not _.startswith('_')]
+__all__ = [_ for _ in dir() if not _.startswith("_")]
diff --git a/bob/io/base/bobskin.cpp b/bob/io/base/bobskin.cpp
deleted file mode 100644
index 494bdafc26fe3520f67b7a5f826d8a9982ba3557..0000000000000000000000000000000000000000
--- a/bob/io/base/bobskin.cpp
+++ /dev/null
@@ -1,159 +0,0 @@
-/**
- * @author Andre Anjos <andre.anjos@idiap.ch>
- * @date Wed  6 Nov 07:57:57 2013
- *
- * @brief Implementation of our bobskin class
- */
-
-#include "bobskin.h"
-#include <stdexcept>
-
-bobskin::bobskin(PyObject* array, bob::io::base::array::ElementType eltype) {
-
-  if (!PyArray_CheckExact(array)) {
-    PyErr_SetString(PyExc_TypeError, "input object to bobskin constructor is not (exactly) a numpy.ndarray");
-    throw std::runtime_error("error is already set");
-  }
-
-  m_type.set<npy_intp>(eltype, PyArray_NDIM((PyArrayObject*)array),
-      PyArray_DIMS((PyArrayObject*)array),
-      PyArray_STRIDES((PyArrayObject*)array));
-
-  m_ptr = PyArray_DATA((PyArrayObject*)array);
-
-}
-
-bobskin::bobskin(PyArrayObject* array, bob::io::base::array::ElementType eltype) {
-
-  m_type.set<npy_intp>(eltype, PyArray_NDIM((PyArrayObject*)array),
-      PyArray_DIMS((PyArrayObject*)array),
-      PyArray_STRIDES((PyArrayObject*)array));
-
-  m_ptr = PyArray_DATA((PyArrayObject*)array);
-
-}
-
-static bob::io::base::array::ElementType signed_integer_type(int bits) {
-  switch(bits) {
-    case 8:
-      return bob::io::base::array::t_int8;
-    case 16:
-      return bob::io::base::array::t_int16;
-    case 32:
-      return bob::io::base::array::t_int32;
-    case 64:
-      return bob::io::base::array::t_int64;
-    default:
-      PyErr_Format(PyExc_TypeError, "unsupported signed integer element type with %d bits", bits);
-  }
-  return bob::io::base::array::t_unknown;
-}
-
-static bob::io::base::array::ElementType unsigned_integer_type(int bits) {
-  switch(bits) {
-    case 8:
-      return bob::io::base::array::t_uint8;
-    case 16:
-      return bob::io::base::array::t_uint16;
-    case 32:
-      return bob::io::base::array::t_uint32;
-    case 64:
-      return bob::io::base::array::t_uint64;
-    default:
-      PyErr_Format(PyExc_TypeError, "unsupported unsigned signed integer element type with %d bits", bits);
-  }
-  return bob::io::base::array::t_unknown;
-}
-
-static bob::io::base::array::ElementType num_to_type (int num) {
-  switch(num) {
-    case NPY_BOOL:
-      return bob::io::base::array::t_bool;
-
-    //signed integers
-    case NPY_BYTE:
-      return signed_integer_type(NPY_BITSOF_CHAR);
-    case NPY_SHORT:
-      return signed_integer_type(NPY_BITSOF_SHORT);
-    case NPY_INT:
-      return signed_integer_type(NPY_BITSOF_INT);
-    case NPY_LONG:
-      return signed_integer_type(NPY_BITSOF_LONG);
-    case NPY_LONGLONG:
-      return signed_integer_type(NPY_BITSOF_LONGLONG);
-
-    //unsigned integers
-    case NPY_UBYTE:
-      return unsigned_integer_type(NPY_BITSOF_CHAR);
-    case NPY_USHORT:
-      return unsigned_integer_type(NPY_BITSOF_SHORT);
-    case NPY_UINT:
-      return unsigned_integer_type(NPY_BITSOF_INT);
-    case NPY_ULONG:
-      return unsigned_integer_type(NPY_BITSOF_LONG);
-    case NPY_ULONGLONG:
-      return unsigned_integer_type(NPY_BITSOF_LONGLONG);
-
-    //floats
-    case NPY_FLOAT32:
-      return bob::io::base::array::t_float32;
-    case NPY_FLOAT64:
-      return bob::io::base::array::t_float64;
-#ifdef NPY_FLOAT128
-    case NPY_FLOAT128:
-      return bob::io::base::array::t_float128;
-#endif
-
-    //complex
-    case NPY_COMPLEX64:
-      return bob::io::base::array::t_complex64;
-    case NPY_COMPLEX128:
-      return bob::io::base::array::t_complex128;
-#ifdef NPY_COMPLEX256
-    case NPY_COMPLEX256:
-      return bob::io::base::array::t_complex256;
-#endif
-
-    default:
-      PyErr_Format(PyExc_TypeError, "unsupported NumPy element type (%d)", num);
-  }
-
-  return bob::io::base::array::t_unknown;
-}
-
-bobskin::bobskin(PyBlitzArrayObject* array) {
-  bob::io::base::array::ElementType eltype = num_to_type(array->type_num);
-  if (eltype == bob::io::base::array::t_unknown) {
-    throw std::runtime_error("error is already set");
-  }
-  m_type.set<Py_ssize_t>(num_to_type(array->type_num), array->ndim,
-      array->shape, array->stride);
-  m_ptr = array->data;
-}
-
-bobskin::~bobskin() { }
-
-void bobskin::set(const interface&) {
-  PyErr_SetString(PyExc_NotImplementedError, "setting C++ bobskin with (const interface&) is not implemented - DEBUG ME!");
-  throw std::runtime_error("error is already set");
-}
-
-void bobskin::set(boost::shared_ptr<interface>) {
-  PyErr_SetString(PyExc_NotImplementedError, "setting C++ bobskin with (boost::shared_ptr<interface>) is not implemented - DEBUG ME!");
-  throw std::runtime_error("error is already set");
-}
-
-void bobskin::set (const bob::io::base::array::typeinfo&) {
-  PyErr_SetString(PyExc_NotImplementedError, "setting C++ bobskin with (const typeinfo&) implemented - DEBUG ME!");
-  throw std::runtime_error("error is already set");
-}
-
-boost::shared_ptr<void> bobskin::owner() {
-  PyErr_SetString(PyExc_NotImplementedError, "acquiring non-const owner from C++ bobskin is not implemented - DEBUG ME!");
-  throw std::runtime_error("error is already set");
-}
-
-boost::shared_ptr<const void> bobskin::owner() const {
-  PyErr_SetString(PyExc_NotImplementedError, "acquiring const owner from C++ bobskin is not implemented - DEBUG ME!");
-  throw std::runtime_error("error is already set");
-}
diff --git a/bob/io/base/bobskin.h b/bob/io/base/bobskin.h
deleted file mode 100644
index d18cf6e40e1d70cc5daa15e6c1f71ff0f50c6225..0000000000000000000000000000000000000000
--- a/bob/io/base/bobskin.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/**
- * @author Andre Anjos <andre.anjos@idiap.ch>
- * @date Tue  5 Nov 22:09:07 2013
- *
- * @brief A pythonic version of bob::io::base::array::interface, with minimal
- * functionality.
- */
-
-#ifndef PYTHON_BOB_IO_BOBSKIN_H
-#define PYTHON_BOB_IO_BOBSKIN_H
-
-#include <Python.h>
-
-#include <bob.io.base/array.h>
-
-#include <bob.blitz/capi.h>
-
-
-/**
- * Wraps a PyArrayObject such that we can access it from bob::io
- */
-class bobskin: public bob::io::base::array::interface {
-
-  public: //api
-
-    /**
-     * @brief Builds a new skin from an array like object
-     */
-    bobskin(PyObject* array, bob::io::base::array::ElementType eltype);
-
-    /**
-     * @brief Builds a new skin from a numpy array object
-     */
-    bobskin(PyArrayObject* array, bob::io::base::array::ElementType eltype);
-
-    /**
-     * @brief Builds a new skin around a blitz array object
-     */
-    bobskin(PyBlitzArrayObject* array);
-
-    /**
-     * @brief By default, the interface is never freed. You must override
-     * this method to do something special for your class type.
-     */
-    virtual ~bobskin();
-
-    /**
-     * @brief Copies the data from another interface.
-     */
-    virtual void set(const interface& other);
-
-    /**
-     * @brief Refers to the data of another interface.
-     */
-    virtual void set(boost::shared_ptr<interface> other);
-
-    /**
-     * @brief Re-allocates this interface taking into consideration new
-     * requirements. The internal memory should be considered uninitialized.
-     */
-    virtual void set (const bob::io::base::array::typeinfo& req);
-
-    /**
-     * @brief Type information for this interface.
-     */
-    virtual const bob::io::base::array::typeinfo& type() const { return m_type; }
-
-    /**
-     * @brief Borrows a reference from the underlying memory. This means
-     * this object continues to be responsible for deleting the memory and
-     * you should make sure that it outlives the usage of the returned
-     * pointer.
-     */
-    virtual void* ptr() { return m_ptr; }
-    virtual const void* ptr() const { return m_ptr; }
-
-    /**
-     * @brief Returns a representation of the internal cache using shared
-     * pointers.
-     */
-    virtual boost::shared_ptr<void> owner();
-    virtual boost::shared_ptr<const void> owner() const;
-
-  private: //representation
-
-    bob::io::base::array::typeinfo m_type; ///< type information
-    void* m_ptr; ///< pointer to the data
-
-};
-
-#endif /* PYTHON_BOB_IO_BOBSKIN_H */
diff --git a/bob/io/base/codec.cpp b/bob/io/base/codec.cpp
deleted file mode 100644
index bfc3eb94de0f9b29371f3d4b9c6a85f45837b441..0000000000000000000000000000000000000000
--- a/bob/io/base/codec.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * @author Andre Anjos <andre.anjos@idiap.ch>
- * @date Wed 14 May 11:53:36 2014 CEST
- *
- * @brief Bindings to bob::io::base::CodecRegistry
- */
-
-#define BOB_IO_BASE_MODULE
-#include <bob.io.base/api.h>
-
-int PyBobIoCodec_Register (const char* extension, const char* description, bob::io::base::file_factory_t factory) {
-  boost::shared_ptr<bob::io::base::CodecRegistry> instance =
-    bob::io::base::CodecRegistry::instance();
-
-  if (instance->isRegistered(extension)) {
-    PyErr_Format(PyExc_RuntimeError, "codec for extension `%s' is already registered with description `%s' - in order to register a new codec for such an extension, first unregister the existing codec", extension, PyBobIoCodec_GetDescription(extension));
-    return 0;
-  }
-
-  instance->registerExtension(extension, description, factory);
-  return 1;
-}
-
-int PyBobIoCodec_Deregister (const char* extension) {
-  boost::shared_ptr<bob::io::base::CodecRegistry> instance =
-    bob::io::base::CodecRegistry::instance();
-
-  if (!instance->isRegistered(extension)) {
-    PyErr_Format(PyExc_RuntimeError, "there is no codec registered for extension `%s'", extension);
-    return 0;
-  }
-
-  instance->deregisterExtension(extension);
-  return 1;
-}
-
-int PyBobIoCodec_IsRegistered (const char* extension) {
-  boost::shared_ptr<bob::io::base::CodecRegistry> instance =
-    bob::io::base::CodecRegistry::instance();
-  if (instance->isRegistered(extension)) return 1;
-  return 0;
-}
-
-const char* PyBobIoCodec_GetDescription (const char* extension) {
-  boost::shared_ptr<bob::io::base::CodecRegistry> instance =
-    bob::io::base::CodecRegistry::instance();
-  return instance->getDescription(extension);
-}
diff --git a/bob/io/base/cpp/CodecRegistry.cpp b/bob/io/base/cpp/CodecRegistry.cpp
deleted file mode 100644
index 1f6c6d05c19187cda37d8bfc1255d24b54a0a9cf..0000000000000000000000000000000000000000
--- a/bob/io/base/cpp/CodecRegistry.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/**
- * @date Tue Oct 25 23:25:46 2011 +0200
- * @author Andre Anjos <andre.anjos@idiap.ch>
- *
- * @brief Implements the CodecRegistry class.
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#include <vector>
-
-#include <boost/filesystem.hpp>
-#include <boost/format.hpp>
-
-#include <bob.io.base/CodecRegistry.h>
-
-#include <bob.core/logging.h>
-
-boost::shared_ptr<bob::io::base::CodecRegistry> bob::io::base::CodecRegistry::instance() {
-  static boost::shared_ptr<bob::io::base::CodecRegistry> s_instance(new CodecRegistry());
-  return s_instance;
-}
-
-void bob::io::base::CodecRegistry::deregisterExtension(const char* ext) {
-  s_extension2codec.erase(ext);
-  s_extension2description.erase(ext);
-}
-
-const char* bob::io::base::CodecRegistry::getDescription(const char* ext) {
-  auto it = s_extension2description.find(ext);
-  if (it == s_extension2description.end()) return 0;
-  return it->second.c_str();
-}
-
-void bob::io::base::CodecRegistry::deregisterFactory(bob::io::base::file_factory_t factory) {
-
-  std::vector<std::string> to_remove;
-  for (auto it = s_extension2codec.begin(); it != s_extension2codec.end(); ++it) {
-    if (it->second == factory) to_remove.push_back(it->first);
-  }
-
-  for (auto it = to_remove.begin(); it != to_remove.end(); ++it) {
-    s_extension2codec.erase(*it);
-    s_extension2description.erase(*it);
-  }
-
-}
-
-void bob::io::base::CodecRegistry::registerExtension(const char* extension,
-    const char* description, bob::io::base::file_factory_t codec) {
-
-  auto it = s_extension2codec.find(extension);
-
-  if (it == s_extension2codec.end()) {
-    s_extension2codec[extension] = codec;
-    s_extension2description[extension] = description;
-  }
-  else if (!s_ignore) {
-    boost::format m("extension already registered: %s - ignoring second registration with description `%s'");
-    m % extension % description;
-    bob::core::error << m.str() << std::endl;
-    throw std::runtime_error(m.str());
-  }
-
-}
-
-bool bob::io::base::CodecRegistry::isRegistered(const char* ext) {
-  std::string extension(ext);
-  std::string lower_extension = extension;
-  std::transform(extension.begin(), extension.end(), lower_extension.begin(), ::tolower);
-  return (s_extension2codec.find(lower_extension) != s_extension2codec.end());
-}
-
-bob::io::base::file_factory_t bob::io::base::CodecRegistry::findByExtension (const char* ext) {
-
-  std::string extension(ext);
-  std::string lower_extension = extension;
-  std::transform(extension.begin(), extension.end(), lower_extension.begin(), ::tolower);
-
-  std::map<std::string, bob::io::base::file_factory_t >::iterator it =
-    s_extension2codec.find(lower_extension);
-
-  if (it == s_extension2codec.end()) {
-    boost::format m("unregistered extension: %s");
-    m % lower_extension;
-    throw std::runtime_error(m.str());
-  }
-
-  return it->second;
-
-}
-
-bob::io::base::file_factory_t bob::io::base::CodecRegistry::findByFilenameExtension
-(const char* filename) {
-
-  return findByExtension(boost::filesystem::path(filename).extension().c_str());
-
-}
diff --git a/bob/io/base/cpp/File.cpp b/bob/io/base/cpp/File.cpp
deleted file mode 100644
index bbdfedfe7e2a5d3dc733e2c6360e933475c0ad4d..0000000000000000000000000000000000000000
--- a/bob/io/base/cpp/File.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-/**
- * @date Tue Oct 25 23:25:46 2011 +0200
- * @author Andre Anjos <andre.anjos@idiap.ch>
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#include <bob.io.base/File.h>
-
-bob::io::base::File::~File() { }
diff --git a/bob/io/base/cpp/HDF5ArrayFile.cpp b/bob/io/base/cpp/HDF5ArrayFile.cpp
deleted file mode 100644
index 8a9aa97f888fa38ea24ea37e85d74c883ed646b3..0000000000000000000000000000000000000000
--- a/bob/io/base/cpp/HDF5ArrayFile.cpp
+++ /dev/null
@@ -1,222 +0,0 @@
-/**
- * @date Tue Oct 25 23:25:46 2011 +0200
- * @author Andre Anjos <andre.anjos@idiap.ch>
- *
- * @brief Implements the HDF5 (.hdf5) array codec
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#include <boost/make_shared.hpp>
-#include <boost/filesystem.hpp>
-#include <boost/format.hpp>
-
-#include <bob.io.base/CodecRegistry.h>
-#include <bob.io.base/HDF5File.h>
-
-/**
- * Read and write arrays in HDF5 format
- */
-class HDF5ArrayFile: public bob::io::base::File {
-
-  public:
-
-    HDF5ArrayFile (const char* filename, bob::io::base::HDF5File::mode_t mode):
-      m_file(filename, mode),
-      m_filename(filename),
-      m_size_arrayset(0),
-      m_newfile(true) {
-
-        //tries to update the current descriptors
-        std::vector<std::string> paths;
-        m_file.paths(paths);
-
-        if (paths.size()) { //file contains data, read it and establish defaults
-          m_path = paths[0]; ///< locks on a path name from now on...
-          m_newfile = false; ///< blocks re-initialization
-
-          //arrayset reading
-          const bob::io::base::HDF5Descriptor& desc_arrayset = m_file.describe(m_path)[0];
-          desc_arrayset.type.copy_to(m_type_arrayset);
-          m_size_arrayset = desc_arrayset.size;
-
-          //array reading
-          const bob::io::base::HDF5Descriptor& desc_array = m_file.describe(m_path)[1];
-          desc_array.type.copy_to(m_type_array);
-
-          //if m_type_all has extent == 1 on the first dimension and dimension
-          //0 is expandable, collapse that
-          if (m_type_array.shape[0] == 1 && desc_arrayset.expandable)
-          {
-            m_type_array = m_type_arrayset;
-          }
-        }
-
-        else {
-          //default path in case the file is new or has been truncated
-          m_path = "/array";
-        }
-
-      }
-
-    virtual ~HDF5ArrayFile() { }
-
-    virtual const char* filename() const {
-      return m_filename.c_str();
-    }
-
-    virtual const bob::io::base::array::typeinfo& type_all () const {
-      return m_type_array;
-    }
-
-    virtual const bob::io::base::array::typeinfo& type () const {
-      return m_type_arrayset;
-    }
-
-    virtual size_t size() const {
-      return m_size_arrayset;
-    }
-
-    virtual const char* name() const {
-      return s_codecname.c_str();
-    }
-
-    virtual void read_all(bob::io::base::array::interface& buffer) {
-
-      if(m_newfile) {
-        boost::format f("uninitialized HDF5 file at '%s' cannot be read");
-        f % m_filename;
-        throw std::runtime_error(f.str());
-      }
-
-      if(!buffer.type().is_compatible(m_type_array)) buffer.set(m_type_array);
-
-      m_file.read_buffer(m_path, 0, buffer.type(), buffer.ptr());
-    }
-
-    virtual void read(bob::io::base::array::interface& buffer, size_t index) {
-
-      if(m_newfile) {
-        boost::format f("uninitialized HDF5 file at '%s' cannot be read");
-        f % m_filename;
-        throw std::runtime_error(f.str());
-      }
-
-      if(!buffer.type().is_compatible(m_type_arrayset)) buffer.set(m_type_arrayset);
-
-      m_file.read_buffer(m_path, index, buffer.type(), buffer.ptr());
-    }
-
-    virtual size_t append (const bob::io::base::array::interface& buffer) {
-
-      if (m_newfile) {
-        //creates non-compressible, extensible dataset on HDF5 file
-        m_newfile = false;
-        m_file.create(m_path, buffer.type(), true, 0);
-        m_file.describe(m_path)[0].type.copy_to(m_type_arrayset);
-        m_file.describe(m_path)[1].type.copy_to(m_type_array);
-
-        //if m_type_all has extent == 1 on the first dimension, collapse that
-        if (m_type_array.shape[0] == 1) m_type_array = m_type_arrayset;
-      }
-
-      m_file.extend_buffer(m_path, buffer.type(), buffer.ptr());
-      ++m_size_arrayset;
-      //needs to flush the data to the file
-      return m_size_arrayset - 1; ///< index of this object in the file
-
-    }
-
-    virtual void write (const bob::io::base::array::interface& buffer) {
-
-      if (!m_newfile) {
-        boost::format f("cannot perform single (array-style) write on file/dataset at '%s' that have already been initialized -- try to use a new file");
-        f % m_filename;
-        throw std::runtime_error(f.str());
-      }
-
-      m_newfile = false;
-      m_file.create(m_path, buffer.type(), false, 0);
-
-      m_file.describe(m_path)[0].type.copy_to(m_type_arrayset);
-      m_file.describe(m_path)[1].type.copy_to(m_type_array);
-
-      //if m_type_all has extent == 1 on the first dimension, collapse that
-      if (m_type_array.shape[0] == 1) m_type_array = m_type_arrayset;
-
-      //otherwise, all must be in place...
-      m_file.write_buffer(m_path, 0, buffer.type(), buffer.ptr());
-    }
-
-  private: //representation
-
-    bob::io::base::HDF5File m_file;
-    std::string  m_filename;
-    bob::io::base::array::typeinfo m_type_array;    ///< type for reading all data at once
-    bob::io::base::array::typeinfo m_type_arrayset; ///< type for reading data by sub-arrays
-    size_t       m_size_arrayset; ///< number of arrays in arrayset mode
-    std::string  m_path; ///< default path to use
-    bool         m_newfile; ///< path check optimization
-
-    static std::string  s_codecname;
-
-};
-
-std::string HDF5ArrayFile::s_codecname = "bob.hdf5";
-
-/**
- * From this point onwards we have the registration procedure. If you are
- * looking at this file for a coding example, just follow the procedure bellow,
- * minus local modifications you may need to apply.
- */
-
-/**
- * This defines the factory method F that can create codecs of this type.
- *
- * Here are the meanings of the mode flag that should be respected by your
- * factory implementation:
- *
- * 'r': opens for reading only - no modifications can occur; it is an
- *      error to open a file that does not exist for read-only operations.
- * 'w': opens for reading and writing, but truncates the file if it
- *      exists; it is not an error to open files that do not exist with
- *      this flag.
- * 'a': opens for reading and writing - any type of modification can
- *      occur. If the file does not exist, this flag is effectively like
- *      'w'.
- *
- * Returns a newly allocated File object that can read and write data to the
- * file using a specific backend.
- *
- * @note: This method can be static.
- */
-static boost::shared_ptr<bob::io::base::File> make_file (const char* path, char mode) {
-
-  bob::io::base::HDF5File::mode_t h5mode;
-  if (mode == 'r') h5mode = bob::io::base::HDF5File::in;
-  else if (mode == 'w') h5mode = bob::io::base::HDF5File::trunc;
-  else if (mode == 'a') h5mode = bob::io::base::HDF5File::inout;
-  else throw std::runtime_error("unsupported file opening mode");
-
-  return boost::make_shared<HDF5ArrayFile>(path, h5mode);
-
-}
-
-/**
- * Takes care of codec registration per se.
- */
-static bool register_codec() {
-  static const char* description = "Hierarchical Data Format v5 (default)";
-
-  boost::shared_ptr<bob::io::base::CodecRegistry> instance =
-    bob::io::base::CodecRegistry::instance();
-
-  instance->registerExtension(".h5", description, &make_file);
-  instance->registerExtension(".hdf5", description, &make_file);
-  instance->registerExtension(".hdf", description, &make_file);
-
-  return true;
-
-}
-
-static bool codec_registered = register_codec();
diff --git a/bob/io/base/cpp/HDF5Attribute.cpp b/bob/io/base/cpp/HDF5Attribute.cpp
deleted file mode 100644
index 0a782042d4193fee0cd8c312709baf4103d7406e..0000000000000000000000000000000000000000
--- a/bob/io/base/cpp/HDF5Attribute.cpp
+++ /dev/null
@@ -1,243 +0,0 @@
-/**
- * @author Andre Anjos <andre.anjos@idiap.ch>
- * @date Fri  2 Mar 08:23:47 2012
- *
- * @brief Implements attribute read/write for HDF5 files
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#include <boost/format.hpp>
-
-#include <bob.core/logging.h>
-
-#include <bob.io.base/HDF5Attribute.h>
-
-static std::runtime_error status_error(const char* f, herr_t s) {
-  boost::format m("call to HDF5 C-function %s() returned error %d. HDF5 error statck follows:\n%s");
-  m % f % s % bob::io::base::format_hdf5_error();
-  return std::runtime_error(m.str());
-}
-
-bool bob::io::base::detail::hdf5::has_attribute(const boost::shared_ptr<hid_t> location,
-    const std::string& name) {
-  return H5Aexists(*location, name.c_str());
-}
-
-/**
- * Opens an "auto-destructible" HDF5 dataspace
- */
-static void delete_h5dataspace (hid_t* p) {
-  if (*p >= 0) {
-    herr_t err = H5Sclose(*p);
-    if (err < 0) {
-      bob::core::error << "H5Sclose() exited with an error (" << err << "). The stack trace follows:" << std::endl;
-      bob::core::error << bob::io::base::format_hdf5_error() << std::endl;
-    }
-  }
-  delete p;
-}
-
-static boost::shared_ptr<hid_t> open_memspace(const bob::io::base::HDF5Shape& s) {
-  boost::shared_ptr<hid_t> retval(new hid_t(-1), std::ptr_fun(delete_h5dataspace));
-  *retval = H5Screate_simple(s.n(), s.get(), 0);
-  if (*retval < 0) throw status_error("H5Screate_simple", *retval);
-  return retval;
-}
-
-/**
- * Opens the memory space of attribute
- */
-static boost::shared_ptr<hid_t> get_memspace(hid_t attr) {
-  boost::shared_ptr<hid_t> retval(new hid_t(-1), std::ptr_fun(delete_h5dataspace));
-  *retval = H5Aget_space(attr);
-  if (*retval < 0) throw status_error("H5Aget_space", *retval);
-  return retval;
-}
-
-/**
- * Auto-destructing HDF5 type
- */
-static void delete_h5type (hid_t* p) {
-  if (*p >= 0) {
-    herr_t err = H5Tclose(*p);
-    if (err < 0) {
-      bob::core::error << "H5Tclose() exited with an error (" << err << "). The stack trace follows:" << std::endl;
-      bob::core::error << bob::io::base::format_hdf5_error() << std::endl;
-    }
-  }
-  delete p;
-}
-
-/**
- * Gets datatype of attribute
- */
-static boost::shared_ptr<hid_t> get_type(hid_t attr) {
-  boost::shared_ptr<hid_t> retval(new hid_t(-1), std::ptr_fun(delete_h5type));
-  *retval = H5Aget_type(attr);
-  if (*retval < 0) throw status_error("H5Aget_type", *retval);
-  return retval;
-}
-
-/**
- * Figures out the extents of an attribute
- */
-static bob::io::base::HDF5Shape get_extents(hid_t space) {
-  int rank = H5Sget_simple_extent_ndims(space);
-  if (rank < 0) throw status_error("H5Sget_simple_extent_ndims", rank);
-  //is at least a list of scalars, but could be a list of arrays
-  bob::io::base::HDF5Shape shape(rank);
-  herr_t status = H5Sget_simple_extent_dims(space, shape.get(), 0);
-  if (status < 0) throw status_error("H5Sget_simple_extent_dims",status);
-  return shape;
-}
-
-/**
- * Opens an "auto-destructible" HDF5 attribute
- */
-static void delete_h5attribute (hid_t* p) {
-  if (*p >= 0) {
-    herr_t err = H5Aclose(*p);
-    if (err < 0) {
-      bob::core::error << "H5Aclose() exited with an error (" << err << "). The stack trace follows:" << std::endl;
-      bob::core::error << bob::io::base::format_hdf5_error() << std::endl;
-    }
-  }
-  delete p;
-}
-
-static boost::shared_ptr<hid_t> open_attribute
-(const boost::shared_ptr<hid_t> location, const std::string& name,
- const bob::io::base::HDF5Type& t) {
-
-  boost::shared_ptr<hid_t> retval(new hid_t(-1),
-      std::ptr_fun(delete_h5attribute));
-
-  *retval = H5Aopen(*location, name.c_str(), H5P_DEFAULT);
-
-  if (*retval < 0) throw status_error("H5Aopen", *retval);
-
-  //checks if the opened attribute is compatible w/ the expected type
-  bob::io::base::HDF5Type expected;
-  boost::shared_ptr<hid_t> atype = get_type(*retval);
-  if (H5Tget_class(*atype) == H5T_STRING) {
-    expected = bob::io::base::HDF5Type(atype);
-  }
-  else {
-    boost::shared_ptr<hid_t> aspace = get_memspace(*retval);
-    bob::io::base::HDF5Shape shape = get_extents(*aspace);
-    expected = bob::io::base::HDF5Type(atype, shape);
-  }
-
-  if (expected != t) {
-    boost::format m("Trying to access attribute '%s' with incompatible buffer - expected `%s', but you gave me `%s'");
-    m % name % expected.str() % t.str();
-    throw std::runtime_error(m.str());
-  }
-
-  return retval;
-}
-
-void bob::io::base::detail::hdf5::delete_attribute (boost::shared_ptr<hid_t> location,
-    const std::string& name) {
-  herr_t err = H5Adelete(*location, name.c_str());
-  if (err < 0) throw status_error("H5Adelete", err);
-}
-
-void bob::io::base::detail::hdf5::read_attribute (const boost::shared_ptr<hid_t> location,
-    const std::string& name, const bob::io::base::HDF5Type& dest,
-    void* buffer) {
-  boost::shared_ptr<hid_t> attribute = open_attribute(location, name, dest);
-  herr_t err = H5Aread(*attribute, *dest.htype(), buffer);
-  if (err < 0) throw status_error("H5Aread", err);
-}
-
-void bob::io::base::detail::hdf5::gettype_attribute (const boost::shared_ptr<hid_t> location,
-    const std::string& name, bob::io::base::HDF5Type& type) {
-
-  boost::shared_ptr<hid_t> attr(new hid_t(-1),
-      std::ptr_fun(delete_h5attribute));
-
-  *attr = H5Aopen(*location, name.c_str(), H5P_DEFAULT);
-
-  if (*attr < 0) throw status_error("H5Aopen", *attr);
-
-  boost::shared_ptr<hid_t> atype = get_type(*attr);
-  if (H5Tget_class(*atype) == H5T_STRING) {
-    type = bob::io::base::HDF5Type(atype);
-  }
-  else {
-    boost::shared_ptr<hid_t> aspace = get_memspace(*attr);
-    bob::io::base::HDF5Shape shape = get_extents(*aspace);
-    type = bob::io::base::HDF5Type(atype, shape);
-  }
-}
-
-static boost::shared_ptr<hid_t> create_attribute(boost::shared_ptr<hid_t> loc,
-    const std::string& name, const bob::io::base::HDF5Type& t,
-    boost::shared_ptr<hid_t> space) {
-
-  boost::shared_ptr<hid_t> retval(new hid_t(-1),
-      std::ptr_fun(delete_h5attribute));
-
-  *retval = H5Acreate2(*loc, name.c_str(), *t.htype(), *space, H5P_DEFAULT,
-      H5P_DEFAULT);
-
-  if (*retval < 0) throw status_error("H5Acreate", *retval);
-  return retval;
-}
-
-void bob::io::base::detail::hdf5::write_attribute (boost::shared_ptr<hid_t> location,
-    const std::string& name, const bob::io::base::HDF5Type& dest, const void* buffer)
-{
-  boost::shared_ptr<hid_t> dataspace;
-  //strings have to be treated slightly differently
-  if (dest.type() == bob::io::base::s) {
-    hsize_t strings = 1;
-    HDF5Shape shape(1, &strings);
-    dataspace = open_memspace(shape);
-  }
-  else {
-    dataspace = open_memspace(dest.shape());
-  }
-
-  if (bob::io::base::detail::hdf5::has_attribute(location, name)) bob::io::base::detail::hdf5::delete_attribute(location, name);
-  boost::shared_ptr<hid_t> attribute =
-    create_attribute(location, name, dest, dataspace);
-
-  /* Write the attribute data. */
-  herr_t err = H5Awrite(*attribute, *dest.htype(), buffer);
-  if (err < 0) throw status_error("H5Awrite", err);
-}
-
-static herr_t attr_iterator (hid_t obj, const char* name, const H5A_info_t*,
-    void* cookie) {
-  std::map<std::string, bob::io::base::HDF5Type>& dict =
-    *static_cast<std::map<std::string, bob::io::base::HDF5Type>*>(cookie);
-
-  boost::shared_ptr<hid_t> attr(new hid_t(-1),
-      std::ptr_fun(delete_h5attribute));
-
-  *attr = H5Aopen(obj, name, H5P_DEFAULT);
-
-  if (*attr < 0) throw status_error("H5Aopen", *attr);
-
-  boost::shared_ptr<hid_t> atype = get_type(*attr);
-  if (H5Tget_class(*atype) == H5T_STRING) {
-    dict[name] = bob::io::base::HDF5Type(atype);
-  }
-  else {
-    boost::shared_ptr<hid_t> aspace = get_memspace(*attr);
-    bob::io::base::HDF5Shape shape = get_extents(*aspace);
-    dict[name] = bob::io::base::HDF5Type(atype, shape);
-  }
-
-  return 0;
-}
-
-void bob::io::base::detail::hdf5::list_attributes(boost::shared_ptr<hid_t> location,
-    std::map<std::string, bob::io::base::HDF5Type>& attributes) {
-  hsize_t offset=0;
-  H5Aiterate2(*location, H5_INDEX_NAME, H5_ITER_NATIVE, &offset, attr_iterator,
-      static_cast<void*>(&attributes));
-}
diff --git a/bob/io/base/cpp/HDF5Dataset.cpp b/bob/io/base/cpp/HDF5Dataset.cpp
deleted file mode 100644
index 9fb6a0a232db5efbfa7f71e3e206cb22534419ab..0000000000000000000000000000000000000000
--- a/bob/io/base/cpp/HDF5Dataset.cpp
+++ /dev/null
@@ -1,612 +0,0 @@
-/**
- * @author Andre Anjos <andre.anjos@idiap.ch>
- * @date Wed 29 Feb 17:51:21 2012
- *
- * @brief Implementation of the Dataset class
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#include <boost/format.hpp>
-#include <boost/make_shared.hpp>
-#include <boost/shared_array.hpp>
-
-#include <bob.core/logging.h>
-
-#include <bob.io.base/HDF5Utils.h>
-#include <bob.io.base/HDF5Group.h>
-#include <bob.io.base/HDF5Dataset.h>
-
-static std::runtime_error status_error(const char* f, herr_t s) {
-  boost::format m("call to HDF5 C-function %s() returned error %d. HDF5 error statck follows:\n%s");
-  m % f % s % bob::io::base::format_hdf5_error();
-  return std::runtime_error(m.str());
-}
-
-/**
- * Opens an "auto-destructible" HDF5 dataset
- */
-static void delete_h5dataset (hid_t* p) {
-  if (*p >= 0) {
-    herr_t err = H5Dclose(*p);
-    if (err < 0) {
-      bob::core::error << "H5Dclose() exited with an error (" << err << "). The stack trace follows:" << std::endl;
-      bob::core::error << bob::io::base::format_hdf5_error() << std::endl;
-    }
-  }
-  delete p;
-}
-
-static boost::shared_ptr<hid_t> open_dataset
-(boost::shared_ptr<bob::io::base::detail::hdf5::Group>& par, const std::string& name) {
-  if (!name.size() || name == "." || name == "..") {
-    boost::format m("Cannot open dataset with illegal name `%s' at `%s:%s'");
-    m % name % par->file()->filename() % par->path();
-    throw std::runtime_error(m.str());
-  }
-
-  boost::shared_ptr<hid_t> retval(new hid_t(-1),
-      std::ptr_fun(delete_h5dataset));
-  *retval = H5Dopen2(*par->location(), name.c_str(), H5P_DEFAULT);
-  if (*retval < 0) {
-    throw status_error("H5Dopen2", *retval);
-  }
-  return retval;
-}
-
-/**
- * Opens an "auto-destructible" HDF5 datatype
- */
-static void delete_h5datatype (hid_t* p) {
-  if (*p >= 0) {
-    herr_t err = H5Tclose(*p);
-    if (err < 0) {
-      bob::core::error << "H5Tclose() exited with an error (" << err << "). The stack trace follows:" << std::endl;
-      bob::core::error << bob::io::base::format_hdf5_error() << std::endl;
-    }
-  }
-  delete p;
-}
-
-static boost::shared_ptr<hid_t> open_datatype
-(const boost::shared_ptr<hid_t>& ds) {
-  boost::shared_ptr<hid_t> retval(new hid_t(-1),
-      std::ptr_fun(delete_h5datatype));
-  *retval = H5Dget_type(*ds);
-  if (*retval < 0) {
-    throw status_error("H5Dget_type", *retval);
-  }
-  return retval;
-}
-
-/**
- * Opens an "auto-destructible" HDF5 property list
- */
-static void delete_h5plist (hid_t* p) {
-  if (*p >= 0) {
-    herr_t err = H5Pclose(*p);
-    if (err < 0) {
-      bob::core::error << "H5Pclose() exited with an error (" << err << "). The stack trace follows:" << std::endl;
-      bob::core::error << bob::io::base::format_hdf5_error() << std::endl;
-    }
-  }
-  delete p;
-}
-
-static boost::shared_ptr<hid_t> open_plist(hid_t classid) {
-  boost::shared_ptr<hid_t> retval(new hid_t(-1), std::ptr_fun(delete_h5plist));
-  *retval = H5Pcreate(classid);
-  if (*retval < 0) {
-    throw status_error("H5Pcreate", *retval);
-  }
-  return retval;
-}
-
-/**
- * Opens an "auto-destructible" HDF5 dataspace
- */
-static void delete_h5dataspace (hid_t* p) {
-  if (*p >= 0) {
-    herr_t err = H5Sclose(*p);
-    if (err < 0) {
-      bob::core::error << "H5Sclose() exited with an error (" << err << "). The stack trace follows:" << std::endl;
-      bob::core::error << bob::io::base::format_hdf5_error() << std::endl;
-    }
-  }
-  delete p;
-}
-
-static boost::shared_ptr<hid_t> open_filespace
-(const boost::shared_ptr<hid_t>& ds) {
-  boost::shared_ptr<hid_t> retval(new hid_t(-1), std::ptr_fun(delete_h5dataspace));
-  *retval = H5Dget_space(*ds);
-  if (*retval < 0) throw status_error("H5Dget_space", *retval);
-  return retval;
-}
-
-static boost::shared_ptr<hid_t> open_memspace(const bob::io::base::HDF5Shape& sh) {
-  boost::shared_ptr<hid_t> retval(new hid_t(-1), std::ptr_fun(delete_h5dataspace));
-  *retval = H5Screate_simple(sh.n(), sh.get(), 0);
-  if (*retval < 0) throw status_error("H5Screate_simple", *retval);
-  return retval;
-}
-
-static void set_memspace(boost::shared_ptr<hid_t> s, const bob::io::base::HDF5Shape& sh) {
-  herr_t status = H5Sset_extent_simple(*s, sh.n(), sh.get(), 0);
-  if (status < 0) throw status_error("H5Sset_extent_simple", status);
-}
-
-/**
- * Figures out if a dataset is expandible
- */
-static bool is_extensible(boost::shared_ptr<hid_t>& space) {
-
-  //has unlimited size on first dimension?
-  int rank = H5Sget_simple_extent_ndims(*space);
-  if (rank < 0) throw status_error("H5Sget_simple_extent_ndims", rank);
-
-  bob::io::base::HDF5Shape maxshape(rank);
-  herr_t status = H5Sget_simple_extent_dims(*space, 0, maxshape.get());
-  if (status < 0) throw status_error("H5Sget_simple_extent_dims",status);
-
-  return (maxshape[0] == H5S_UNLIMITED);
-}
-
-/**
- * Figures out the extents of a dataset
- */
-static bob::io::base::HDF5Shape get_extents(boost::shared_ptr<hid_t>& space) {
-  int rank = H5Sget_simple_extent_ndims(*space);
-  if (rank < 0) throw status_error("H5Sget_simple_extent_ndims", rank);
-  //is at least a list of scalars, but could be a list of arrays
-  bob::io::base::HDF5Shape shape(rank);
-  herr_t status = H5Sget_simple_extent_dims(*space, shape.get(), 0);
-  if (status < 0) throw status_error("H5Sget_simple_extent_dims",status);
-  return shape;
-}
-
-/**
- * Creates the extensive list of compatible types for each of possible ways to
- * read/write this dataset.
- */
-static void reset_compatibility_list(boost::shared_ptr<hid_t>& space,
-    const bob::io::base::HDF5Type& file_base, std::vector<bob::io::base::HDF5Descriptor>& descr) {
-
-  if (!file_base.shape()) throw std::runtime_error("empty HDF5 dataset");
-
-  descr.clear();
-
-  switch (file_base.shape().n()) {
-
-    case 1: ///< file type has 1 dimension
-      descr.push_back(bob::io::base::HDF5Descriptor(file_base.type(),
-            file_base.shape()[0], is_extensible(space)));
-      break;
-
-    case 2:
-    case 3:
-    case 4:
-    case 5:
-      {
-        bob::io::base::HDF5Shape alt = file_base.shape();
-        alt <<= 1; ///< contract shape
-        descr.push_back(bob::io::base::HDF5Descriptor(bob::io::base::HDF5Type(file_base.type(), alt),
-              file_base.shape()[0], is_extensible(space)).subselect());
-      }
-      break;
-
-    default:
-      {
-        boost::format m("%d exceeds the number of supported dimensions");
-        m % file_base.shape().n();
-        throw std::runtime_error(m.str());
-      }
-  }
-
-  //can always read the data as a single, non-expandible array
-  descr.push_back(bob::io::base::HDF5Descriptor(file_base, 1, false));
-}
-
-bob::io::base::detail::hdf5::Dataset::Dataset(boost::shared_ptr<Group> parent,
-    const std::string& name) :
-  m_parent(parent),
-  m_name(name),
-  m_id(open_dataset(parent, name)),
-  m_dt(open_datatype(m_id)),
-  m_filespace(open_filespace(m_id)),
-  m_descr(),
-  m_memspace()
-{
-  bob::io::base::HDF5Type type(m_dt, get_extents(m_filespace));
-  reset_compatibility_list(m_filespace, type, m_descr);
-
-  //strings have to be treated slightly differently
-  if (H5Tget_class(*m_dt) == H5T_STRING) {
-    hsize_t strings = 1;
-    HDF5Shape shape(1, &strings);
-    m_memspace = open_memspace(shape);
-  }
-  else {
-    m_memspace = open_memspace(m_descr[0].type.shape());
-  }
-}
-
-/**
- * Creates and writes an "empty" Dataset in an existing file.
- */
-static void create_dataset (boost::shared_ptr<bob::io::base::detail::hdf5::Group> par,
- const std::string& name, const bob::io::base::HDF5Type& type, bool list,
- size_t compression) {
-
-  if (!name.size() || name == "." || name == "..") {
-    boost::format m("Cannot create dataset with illegal name `%s' at `%s:%s'");
-    m % name % par->file()->filename() % par->path();
-    throw std::runtime_error(m.str());
-  }
-
-  bob::io::base::HDF5Shape xshape(type.shape());
-
-  if (list) { ///< if it is a list, add and extra dimension as dimension 0
-    xshape = type.shape();
-    xshape >>= 1;
-    xshape[0] = 0; ///< no elements for the time being
-  }
-
-  bob::io::base::HDF5Shape maxshape(xshape);
-  if (list) maxshape[0] = H5S_UNLIMITED; ///< can expand forever
-
-  //creates the data space.
-  boost::shared_ptr<hid_t> space(new hid_t(-1),
-      std::ptr_fun(delete_h5dataspace));
-  *space = H5Screate_simple(xshape.n(), xshape.get(), maxshape.get());
-  if (*space < 0) throw status_error("H5Screate_simple", *space);
-
-  //creates the property list saying we need the data to be chunked if this is
-  //supposed to be a list -- HDF5 only supports expandability like this.
-  boost::shared_ptr<hid_t> dcpl = open_plist(H5P_DATASET_CREATE);
-
-  //according to the HDF5 manual, chunks have to have the same rank as the
-  //array shape.
-  bob::io::base::HDF5Shape chunking(xshape);
-  chunking[0] = 1;
-  if (list || compression) { ///< note: compression requires chunking
-    herr_t status = H5Pset_chunk(*dcpl, chunking.n(), chunking.get());
-    if (status < 0) throw status_error("H5Pset_chunk", status);
-  }
-
-  //if the user has decided to compress the dataset, do it with gzip.
-  if (compression) {
-    if (compression > 9) compression = 9;
-    herr_t status = H5Pset_deflate(*dcpl, compression);
-    if (status < 0) throw status_error("H5Pset_deflate", status);
-  }
-
-  //our link creation property list for HDF5
-  boost::shared_ptr<hid_t> lcpl = open_plist(H5P_LINK_CREATE);
-  herr_t status = H5Pset_create_intermediate_group(*lcpl, 1); //1 == true
-  if (status < 0)
-    throw status_error("H5Pset_create_intermediate_group", status);
-
-  //please note that we don't define the fill value as in the example, but
-  //according to the HDF5 documentation, this value is set to zero by default.
-
-  boost::shared_ptr<hid_t> cls = type.htype();
-
-  //finally create the dataset on the file.
-  boost::shared_ptr<hid_t> dataset(new hid_t(-1),
-      std::ptr_fun(delete_h5dataset));
-  *dataset = H5Dcreate2(*par->location(), name.c_str(),
-      *cls, *space, *lcpl, *dcpl, H5P_DEFAULT);
-
-  if (*dataset < 0) throw status_error("H5Dcreate2", *dataset);
-}
-
-/**
- * Creates and writes an "empty" std::string Dataset in an existing file.
- */
-static void create_string_dataset (boost::shared_ptr<bob::io::base::detail::hdf5::Group> par,
- const std::string& name, const bob::io::base::HDF5Type& type, size_t compression) {
-
-  if (!name.size() || name == "." || name == "..") {
-    boost::format m("Cannot create dataset with illegal name `%s' at `%s:%s'");
-    m % name % par->file()->filename() % par->path();
-    throw std::runtime_error(m.str());
-  }
-
-  //there can be only 1 string in a string dataset (for the time being)
-  hsize_t strings = 1;
-  bob::io::base::HDF5Shape xshape(1, &strings);
-
-  //creates the data space.
-  boost::shared_ptr<hid_t> space(new hid_t(-1),
-      std::ptr_fun(delete_h5dataspace));
-  *space = H5Screate_simple(xshape.n(), xshape.get(), xshape.get());
-  if (*space < 0) throw status_error("H5Screate_simple", *space);
-
-  //creates the property list saying we need the data to be chunked if this is
-  //supposed to be a list -- HDF5 only supports expandability like this.
-  boost::shared_ptr<hid_t> dcpl = open_plist(H5P_DATASET_CREATE);
-
-  //if the user has decided to compress the dataset, do it with gzip.
-  if (compression) {
-    if (compression > 9) compression = 9;
-    herr_t status = H5Pset_deflate(*dcpl, compression);
-    if (status < 0) throw status_error("H5Pset_deflate", status);
-  }
-
-  //our link creation property list for HDF5
-  boost::shared_ptr<hid_t> lcpl = open_plist(H5P_LINK_CREATE);
-  herr_t status = H5Pset_create_intermediate_group(*lcpl, 1); //1 == true
-  if (status < 0)
-    throw status_error("H5Pset_create_intermediate_group", status);
-
-  //please note that we don't define the fill value as in the example, but
-  //according to the HDF5 documentation, this value is set to zero by default.
-
-  boost::shared_ptr<hid_t> cls = type.htype();
-
-  //finally create the dataset on the file.
-  boost::shared_ptr<hid_t> dataset(new hid_t(-1),
-      std::ptr_fun(delete_h5dataset));
-  *dataset = H5Dcreate2(*par->location(), name.c_str(),
-      *cls, *space, *lcpl, *dcpl, H5P_DEFAULT);
-
-  if (*dataset < 0) throw status_error("H5Dcreate2", *dataset);
-}
-
-bob::io::base::detail::hdf5::Dataset::Dataset(boost::shared_ptr<Group> parent,
-    const std::string& name, const bob::io::base::HDF5Type& type,
-    bool list, size_t compression):
-  m_parent(parent),
-  m_name(name),
-  m_id(),
-  m_dt(),
-  m_filespace(),
-  m_descr(),
-  m_memspace()
-{
-  //First, we test to see if we can find the named dataset.
-  bob::io::base::DefaultHDF5ErrorStack->mute();
-  hid_t set_id = H5Dopen2(*parent->location(),m_name.c_str(),H5P_DEFAULT);
-  bob::io::base::DefaultHDF5ErrorStack->unmute();
-
-  if (set_id < 0) {
-    if (type.type() == bob::io::base::s)
-      create_string_dataset(parent, m_name, type, compression);
-    else
-      create_dataset(parent, m_name, type, list, compression);
-  }
-  else H5Dclose(set_id); //close it, will re-open it properly
-
-  m_id = open_dataset(parent, m_name);
-  m_dt = open_datatype(m_id);
-  m_filespace = open_filespace(m_id);
-  bob::io::base::HDF5Type file_type(m_dt, get_extents(m_filespace));
-  reset_compatibility_list(m_filespace, file_type, m_descr);
-
-  //strings have to be treated slightly differently
-  if (H5Tget_class(*m_dt) == H5T_STRING) {
-    hsize_t strings = 1;
-    HDF5Shape shape(1, &strings);
-    m_memspace = open_memspace(shape);
-  }
-  else {
-    m_memspace = open_memspace(m_descr[0].type.shape());
-  }
-}
-
-bob::io::base::detail::hdf5::Dataset::~Dataset() { }
-
-size_t bob::io::base::detail::hdf5::Dataset::size () const {
-  return m_descr[0].size;
-}
-
-size_t bob::io::base::detail::hdf5::Dataset::size (const bob::io::base::HDF5Type& type) const {
-  for (size_t k=0; k<m_descr.size(); ++k) {
-    if (m_descr[k].type == type) return m_descr[k].size;
-  }
-  boost::format m("trying to read or write `%s' at `%s' that only accepts `%s'");
-  m % type.str() % url() % m_descr[0].type.str();
-  throw std::runtime_error(m.str());
-}
-
-const boost::shared_ptr<bob::io::base::detail::hdf5::Group> bob::io::base::detail::hdf5::Dataset::parent() const {
-  return m_parent.lock();
-}
-
-boost::shared_ptr<bob::io::base::detail::hdf5::Group> bob::io::base::detail::hdf5::Dataset::parent() {
-  return m_parent.lock();
-}
-
-const std::string& bob::io::base::detail::hdf5::Dataset::filename() const {
-  return parent()->filename();
-}
-
-std::string bob::io::base::detail::hdf5::Dataset::url() const {
-  return filename() + ":" + path();
-}
-
-std::string bob::io::base::detail::hdf5::Dataset::path() const {
-  return parent()->path() + "/" + m_name;
-}
-
-const boost::shared_ptr<bob::io::base::detail::hdf5::File> bob::io::base::detail::hdf5::Dataset::file() const {
-  return parent()->file();
-}
-
-boost::shared_ptr<bob::io::base::detail::hdf5::File> bob::io::base::detail::hdf5::Dataset::file() {
-  return parent()->file();
-}
-
-/**
- * Locates a compatible type or returns end().
- */
-static std::vector<bob::io::base::HDF5Descriptor>::iterator
-  find_type_index(std::vector<bob::io::base::HDF5Descriptor>& descr,
-      const bob::io::base::HDF5Type& user_type) {
-  std::vector<bob::io::base::HDF5Descriptor>::iterator it = descr.begin();
-  for (; it != descr.end(); ++it) {
-    if (it->type == user_type) break;
-  }
-  return it;
-}
-
-std::vector<bob::io::base::HDF5Descriptor>::iterator
-bob::io::base::detail::hdf5::Dataset::select (size_t index, const bob::io::base::HDF5Type& dest) {
-
-  //finds compatibility type
-  std::vector<bob::io::base::HDF5Descriptor>::iterator it = find_type_index(m_descr, dest);
-
-  //if we cannot find a compatible type, we throw
-  if (it == m_descr.end()) {
-    boost::format m("trying to read or write `%s' at `%s' that only accepts `%s'");
-    m % dest.str() % url() % m_descr[0].type.str();
-    throw std::runtime_error(m.str());
-  }
-
-  //checks indexing
-  if (index >= it->size) {
-    boost::format m("trying to access element %d in Dataset '%s' that only contains %d elements");
-    m % index % url() % it->size;
-    throw std::runtime_error(m.str());
-  }
-
-  set_memspace(m_memspace, it->type.shape());
-
-  it->hyperslab_start[0] = index;
-
-  herr_t status = H5Sselect_hyperslab(*m_filespace, H5S_SELECT_SET,
-      it->hyperslab_start.get(), 0, it->hyperslab_count.get(), 0);
-  if (status < 0) throw status_error("H5Sselect_hyperslab", status);
-
-  return it;
-}
-
-void bob::io::base::detail::hdf5::Dataset::read_buffer (size_t index, const bob::io::base::HDF5Type& dest, void* buffer) {
-
-  std::vector<bob::io::base::HDF5Descriptor>::iterator it = select(index, dest);
-
-  herr_t status = H5Dread(*m_id, *it->type.htype(),
-      *m_memspace, *m_filespace, H5P_DEFAULT, buffer);
-
-  if (status < 0) throw status_error("H5Dread", status);
-}
-
-void bob::io::base::detail::hdf5::Dataset::write_buffer (size_t index, const bob::io::base::HDF5Type& dest,
-    const void* buffer) {
-
-  std::vector<bob::io::base::HDF5Descriptor>::iterator it = select(index, dest);
-
-  herr_t status = H5Dwrite(*m_id, *it->type.htype(),
-      *m_memspace, *m_filespace, H5P_DEFAULT, buffer);
-
-  if (status < 0) throw status_error("H5Dwrite", status);
-}
-
-void bob::io::base::detail::hdf5::Dataset::extend_buffer (const bob::io::base::HDF5Type& dest, const void* buffer) {
-
-  //finds compatibility type
-  std::vector<bob::io::base::HDF5Descriptor>::iterator it = find_type_index(m_descr, dest);
-
-  //if we cannot find a compatible type, we throw
-  if (it == m_descr.end()) {
-    boost::format m("trying to read or write `%s' at `%s' that only accepts `%s'");
-    m % dest.str() % url() % m_descr[0].type.str();
-    throw std::runtime_error(m.str());
-  }
-
-  if (!it->expandable) {
-    boost::format m("trying to append to '%s' that is not expandible");
-    m % url();
-    throw std::runtime_error(m.str());
-  }
-
-  //if it is expandible, try expansion
-  bob::io::base::HDF5Shape tmp(it->type.shape());
-  tmp >>= 1;
-  tmp[0] = it->size + 1;
-  herr_t status = H5Dset_extent(*m_id, tmp.get());
-  if (status < 0) throw status_error("H5Dset_extent", status);
-
-  //if expansion succeeded, update all compatible types
-  for (size_t k=0; k<m_descr.size(); ++k) {
-    if (m_descr[k].expandable) { //updated only the length
-      m_descr[k].size += 1;
-    }
-    else { //not expandable, update the shape/count for a straight read/write
-      m_descr[k].type.shape()[0] += 1;
-      m_descr[k].hyperslab_count[0] += 1;
-    }
-  }
-
-  m_filespace = open_filespace(m_id); //update filespace
-
-  write_buffer(tmp[0]-1, dest, buffer);
-}
-
-void bob::io::base::detail::hdf5::Dataset::gettype_attribute(const std::string& name,
-          bob::io::base::HDF5Type& type) const {
-  bob::io::base::detail::hdf5::gettype_attribute(m_id, name, type);
-}
-
-bool bob::io::base::detail::hdf5::Dataset::has_attribute(const std::string& name) const {
-  return bob::io::base::detail::hdf5::has_attribute(m_id, name);
-}
-
-void bob::io::base::detail::hdf5::Dataset::delete_attribute (const std::string& name) {
-  bob::io::base::detail::hdf5::delete_attribute(m_id, name);
-}
-
-void bob::io::base::detail::hdf5::Dataset::read_attribute (const std::string& name,
-    const bob::io::base::HDF5Type& dest_type, void* buffer) const {
-  bob::io::base::detail::hdf5::read_attribute(m_id, name, dest_type, buffer);
-}
-
-void bob::io::base::detail::hdf5::Dataset::write_attribute (const std::string& name,
-    const bob::io::base::HDF5Type& dest_type, const void* buffer) {
-  bob::io::base::detail::hdf5::write_attribute(m_id, name, dest_type, buffer);
-}
-
-void bob::io::base::detail::hdf5::Dataset::list_attributes(std::map<std::string, bob::io::base::HDF5Type>& attributes) const {
-  bob::io::base::detail::hdf5::list_attributes(m_id, attributes);
-}
-
-template <> void bob::io::base::detail::hdf5::Dataset::read<std::string>(size_t index, std::string& value) {
-  if (index != 0) throw std::runtime_error("Bob's HDF5 bindings do not (yet) support string vectors - reading something on position > 0 is therefore not possible");
-
-  size_t str_size = H5Tget_size(*m_dt); ///< finds out string size
-  boost::shared_array<char> storage(new char[str_size+1]);
-  storage[str_size] = 0; ///< null termination
-
-  herr_t status = H5Dread(*m_id, *m_dt, *m_memspace, *m_filespace, H5P_DEFAULT, storage.get());
-  if (status < 0) throw status_error("H5Dread", status);
-
-  value = storage.get();
-}
-
-template <> void bob::io::base::detail::hdf5::Dataset::replace<std::string>(size_t index, const std::string& value) {
-  if (index != 0) throw std::runtime_error("Bob's HDF5 bindings do not (yet) support string vectors - indexing something on position > 0 is therefore not possible");
-
-  herr_t status = H5Dwrite(*m_id, *m_dt, *m_memspace, *m_filespace, H5P_DEFAULT, value.c_str());
-  if (status < 0) throw status_error("H5Dwrite", status);
-}
-
-template <> void bob::io::base::detail::hdf5::Dataset::add<std::string>(const std::string& value) {
-  herr_t status = H5Dwrite(*m_id, *m_dt, *m_memspace, *m_filespace, H5P_DEFAULT, value.c_str());
-  if (status < 0) throw status_error("H5Dwrite", status);
-}
-
-template <> void bob::io::base::detail::hdf5::Dataset::set_attribute<std::string>(const std::string& name, const std::string& v) {
-  bob::io::base::HDF5Type dest_type(v);
-  write_attribute(name, dest_type, reinterpret_cast<const void*>(v.c_str()));
-}
-
-template <> std::string bob::io::base::detail::hdf5::Dataset::get_attribute(const std::string& name) const {
-  HDF5Type type;
-  gettype_attribute(name, type);
-  boost::shared_array<char> v(new char[type.shape()[0]+1]);
-  v[type.shape()[0]] = 0; ///< null termination
-  read_attribute(name, type, reinterpret_cast<void*>(v.get()));
-  std::string retval(v.get());
-  return retval;
-}
diff --git a/bob/io/base/cpp/HDF5File.cpp b/bob/io/base/cpp/HDF5File.cpp
deleted file mode 100644
index 549069f8ab821df603ef35727d0da07a4a757137..0000000000000000000000000000000000000000
--- a/bob/io/base/cpp/HDF5File.cpp
+++ /dev/null
@@ -1,294 +0,0 @@
-/**
- * @date Wed Jun 22 17:50:08 2011 +0200
- * @author Andre Anjos <andre.anjos@idiap.ch>
- *
- * @brief Implementation of the read/write functionality for HDF5 files
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#include <boost/format.hpp>
-
-#include <bob.io.base/HDF5File.h>
-
-static unsigned int getH5Access (bob::io::base::HDF5File::mode_t v) {
-  switch(v) {
-    case 0: return H5F_ACC_RDONLY;
-    case 1: return H5F_ACC_RDWR;
-    case 2: return H5F_ACC_TRUNC;
-    case 4: return H5F_ACC_EXCL;
-    default:
-            {
-              boost::format m("Trying to use an undefined access mode '%d'");
-              m % v;
-              throw std::runtime_error(m.str());
-            }
-  }
-}
-
-bob::io::base::HDF5File::HDF5File(const std::string& filename, mode_t mode):
-  m_file(new bob::io::base::detail::hdf5::File(filename, getH5Access(mode))),
-  m_cwd(m_file->root()) ///< we start by looking at the root directory
-{
-}
-
-bob::io::base::HDF5File::HDF5File(const std::string& filename, const char mode):
-m_file(),
-m_cwd()
-{
-  bob::io::base::HDF5File::mode_t new_mode = bob::io::base::HDF5File::inout;
-  switch (mode){
-    case 'r': new_mode = bob::io::base::HDF5File::in; break;
-    case 'a': new_mode = bob::io::base::HDF5File::inout; break;
-    case 'w': new_mode = bob::io::base::HDF5File::trunc; break;
-    case 'x': new_mode = bob::io::base::HDF5File::excl; break;
-    default:
-      throw std::runtime_error("Supported flags are 'r' (read-only), 'a' (read/write/append), 'w' (read/write/truncate) or 'x' (read/write/exclusive)");
-  }
-  m_file.reset(new bob::io::base::detail::hdf5::File(filename, getH5Access(new_mode)));
-  m_cwd = m_file->root(); ///< we start by looking at the root directory
-
-}
-
-bob::io::base::HDF5File::HDF5File(const bob::io::base::HDF5File& other_file):
-  m_file(other_file.m_file),
-  m_cwd(other_file.m_cwd)
-{
-}
-
-bob::io::base::HDF5File::~HDF5File() {
-}
-
-bob::io::base::HDF5File& bob::io::base::HDF5File::operator =(const bob::io::base::HDF5File& other_file){
-  m_file = other_file.m_file;
-  m_cwd = other_file.m_cwd;
-  return *this;
-}
-
-void bob::io::base::HDF5File::close() {
-  m_file.reset();
-  m_cwd.reset();
-}
-
-void bob::io::base::HDF5File::cd(const std::string& path) {
-  check_open();
-  m_cwd = m_cwd->cd(path);
-}
-
-bool bob::io::base::HDF5File::hasGroup(const std::string& path) {
-  check_open();
-  return m_cwd->has_group(path);
-}
-
-void bob::io::base::HDF5File::createGroup(const std::string& path) {
-  check_open();
-  if (!m_file->writable()) {
-    boost::format m("cannot create group '%s' at path '%s' of file '%s' because it is not writeable");
-    m % path % m_cwd->path() % m_file->filename();
-    throw std::runtime_error(m.str());
-  }
-  m_cwd->create_group(path);
-}
-
-std::string bob::io::base::HDF5File::cwd() const {
-  check_open();
-  return m_cwd->path();
-}
-
-bool bob::io::base::HDF5File::contains (const std::string& path) const {
-  check_open();
-  return m_cwd->has_dataset(path);
-}
-
-const std::vector<bob::io::base::HDF5Descriptor>& bob::io::base::HDF5File::describe
-(const std::string& path) const {
-  check_open();
-  return (*m_cwd)[path]->m_descr;
-}
-
-void bob::io::base::HDF5File::unlink (const std::string& path) {
-  check_open();
-  if (!m_file->writable()) {
-    boost::format m("cannot remove dataset at path '%s' of file '%s' because it is not writeable");
-    m % path % m_cwd->path() % m_file->filename();
-    throw std::runtime_error(m.str());
-  }
-  m_cwd->remove_dataset(path);
-}
-
-void bob::io::base::HDF5File::rename (const std::string& from, const std::string& to) {
-  check_open();
-  if (!m_file->writable()) {
-    boost::format m("cannot rename dataset '%s' -> '%s' at path '%s' of file '%s' because it is not writeable");
-    m % from % to % m_cwd->path() % m_file->filename();
-    throw std::runtime_error(m.str());
-  }
-  m_cwd->rename_dataset(from, to);
-  std::string current_path = m_cwd->path();
-  m_file->reset(); //re-read the whole structure
-  m_cwd = m_file->root();
-  m_cwd = m_cwd->cd(current_path); //go back to the path we were before
-}
-
-void bob::io::base::HDF5File::copy (HDF5File& other) {
-  check_open();
-  if (!m_file->writable()) {
-    boost::format m("cannot copy data of file '%s' to path '%s' of file '%s' because it is not writeable");
-    m % other.filename() % m_cwd->path() % m_file->filename();
-    throw std::runtime_error(m.str());
-  }
-
-  //groups
-  typedef std::map<std::string, boost::shared_ptr<bob::io::base::detail::hdf5::Group> > group_map_type;
-  const group_map_type& group_map = other.m_file->root()->groups();
-  for (group_map_type::const_iterator it=group_map.begin();
-      it != group_map.end(); ++it) {
-    m_cwd->copy_group(it->second, it->first);
-  }
-
-  //datasets
-  typedef std::map<std::string, boost::shared_ptr<bob::io::base::detail::hdf5::Dataset> > dataset_map_type;
-  const dataset_map_type& dataset_map = other.m_file->root()->datasets();
-  for (dataset_map_type::const_iterator it=dataset_map.begin();
-      it != dataset_map.end(); ++it) {
-    m_cwd->copy_dataset(it->second, it->first);
-  }
-}
-
-void bob::io::base::HDF5File::create (const std::string& path, const bob::io::base::HDF5Type& type,
-    bool list, size_t compression) {
-  check_open();
-  if (!m_file->writable()) {
-    boost::format m("cannot create dataset '%s' at path '%s' of file '%s' because it is not writeable");
-    m % path % m_cwd->path() % m_file->filename();
-    throw std::runtime_error(m.str());
-  }
-  if (!contains(path)) m_cwd->create_dataset(path, type, list, compression);
-  else (*m_cwd)[path]->size(type);
-}
-
-void bob::io::base::HDF5File::read_buffer (const std::string& path, size_t pos,
-    const bob::io::base::HDF5Type& type, void* buffer) const {
-  check_open();
-  (*m_cwd)[path]->read_buffer(pos, type, buffer);
-}
-
-void bob::io::base::HDF5File::write_buffer (const std::string& path,
-    size_t pos, const bob::io::base::HDF5Type& type, const void* buffer) {
-  check_open();
-  if (!m_file->writable()) {
-    boost::format m("cannot write to object '%s' at path '%s' of file '%s' because it is not writeable");
-    m % path % m_cwd->path() % m_file->filename();
-    throw std::runtime_error(m.str());
-  }
-  (*m_cwd)[path]->write_buffer(pos, type, buffer);
-}
-
-void bob::io::base::HDF5File::extend_buffer(const std::string& path,
-    const bob::io::base::HDF5Type& type, const void* buffer) {
-  check_open();
-  if (!m_file->writable()) {
-    boost::format m("cannot extend object '%s' at path '%s' of file '%s' because the file is not writeable");
-    m % path % m_cwd->path() % m_file->filename();
-    throw std::runtime_error(m.str());
-  }
-  (*m_cwd)[path]->extend_buffer(type, buffer);
-}
-
-bool bob::io::base::HDF5File::hasAttribute(const std::string& path,
-    const std::string& name) const {
-  check_open();
-  if (m_cwd->has_dataset(path)) {
-    return (*m_cwd)[path]->has_attribute(name);
-  }
-  else if (m_cwd->has_group(path)) {
-    return m_cwd->cd(path)->has_attribute(name);
-  }
-  return false;
-}
-
-void bob::io::base::HDF5File::getAttributeType(const std::string& path,
-    const std::string& name, HDF5Type& type) const {
-  check_open();
-  if (m_cwd->has_dataset(path)) {
-    (*m_cwd)[path]->gettype_attribute(name, type);
-  }
-  else if (m_cwd->has_group(path)) {
-    m_cwd->cd(path)->gettype_attribute(name, type);
-  }
-  else {
-    boost::format m("cannot read attribute '%s' type at path/dataset '%s' of file '%s' (cwd: '%s') because this path/dataset does not currently exist");
-    m % name % path % m_file->filename() % m_cwd->path();
-    throw std::runtime_error(m.str());
-  }
-}
-
-void bob::io::base::HDF5File::deleteAttribute(const std::string& path,
-    const std::string& name) {
-  check_open();
-  if (m_cwd->has_dataset(path)) {
-    (*m_cwd)[path]->delete_attribute(name);
-  }
-  else if (m_cwd->has_group(path)) {
-    m_cwd->cd(path)->delete_attribute(name);
-  }
-  else {
-    boost::format m("cannot delete attribute '%s' at path/dataset '%s' of file '%s' (cwd: '%s') because this path/dataset does not currently exist");
-    m % name % path % m_file->filename() % m_cwd->path();
-    throw std::runtime_error(m.str());
-  }
-}
-
-void bob::io::base::HDF5File::listAttributes(const std::string& path,
-    std::map<std::string, bob::io::base::HDF5Type>& attributes) const {
-  check_open();
-  if (m_cwd->has_dataset(path)) {
-    (*m_cwd)[path]->list_attributes(attributes);
-  }
-  else if (m_cwd->has_group(path)) {
-    m_cwd->cd(path)->list_attributes(attributes);
-  }
-  else {
-    boost::format m("cannot list attributes at path/dataset '%s' of file '%s' (cwd: '%s') because this path/dataset does not currently exist");
-    m % path % m_file->filename() % m_cwd->path();
-    throw std::runtime_error(m.str());
-  }
-}
-
-void bob::io::base::HDF5File::read_attribute(const std::string& path,
-    const std::string& name, const bob::io::base::HDF5Type& type, void* buffer) const {
-  check_open();
-  if (m_cwd->has_dataset(path)) {
-    (*m_cwd)[path]->read_attribute(name, type, buffer);
-  }
-  else if (m_cwd->has_group(path)) {
-    m_cwd->cd(path)->read_attribute(name, type, buffer);
-  }
-  else {
-    boost::format m("cannot get attribute '%s' at path/dataset '%s' of file '%s' (cwd: '%s') because this path/dataset does not currently exist");
-    m % name % path % m_file->filename() % m_cwd->path();
-    throw std::runtime_error(m.str());
-  }
-}
-
-void bob::io::base::HDF5File::write_attribute(const std::string& path,
-    const std::string& name, const bob::io::base::HDF5Type& type, const void* buffer) {
-  check_open();
-  if (m_cwd->has_dataset(path)) {
-    (*m_cwd)[path]->write_attribute(name, type, buffer);
-  }
-  else if (m_cwd->has_group(path)) {
-    m_cwd->cd(path)->write_attribute(name, type, buffer);
-  }
-  else {
-    boost::format m("cannot set attribute '%s' at path/dataset '%s' of file '%s' (cwd: '%s') because this path/dataset does not currently exist");
-    m % name % path % m_file->filename() % m_cwd->path();
-    throw std::runtime_error(m.str());
-  }
-}
-
-void bob::io::base::HDF5File::check_open() const{
-  if (!m_cwd || ! m_file){
-    throw std::runtime_error("The file is not opened yet / any more");
-  }
-}
diff --git a/bob/io/base/cpp/HDF5Group.cpp b/bob/io/base/cpp/HDF5Group.cpp
deleted file mode 100644
index 6c39b18b559def62a5ba6245426bd267bdd379e5..0000000000000000000000000000000000000000
--- a/bob/io/base/cpp/HDF5Group.cpp
+++ /dev/null
@@ -1,560 +0,0 @@
-/**
- * @author Andre Anjos <andre.anjos@idiap.ch>
- * @date Wed 29 Feb 17:24:10 2012
- *
- * @brief Implements HDF5 groups.
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#include <boost/make_shared.hpp>
-#include <boost/shared_array.hpp>
-#include <boost/filesystem.hpp>
-#include <boost/format.hpp>
-#include <boost/algorithm/string.hpp>
-
-#include <bob.core/logging.h>
-
-#include <bob.io.base/HDF5Group.h>
-#include <bob.io.base/HDF5Utils.h>
-
-/**
- * Creates an "auto-destructible" HDF5 Group
- */
-static void delete_h5g (hid_t* p) {
-  if (*p >= 0) {
-    herr_t err = H5Gclose(*p);
-    if (err < 0) {
-      bob::core::error << "H5Gclose() exited with an error (" << err << "). The stack trace follows:" << std::endl;
-      bob::core::error << bob::io::base::format_hdf5_error() << std::endl;
-    }
-  }
-  delete p;
-}
-
-static boost::shared_ptr<hid_t> create_new_group(boost::shared_ptr<hid_t> p,
-    const std::string& name) {
-  boost::shared_ptr<hid_t> retval(new hid_t(-1), std::ptr_fun(delete_h5g));
-  *retval = H5Gcreate2(*p, name.c_str(), H5P_DEFAULT, H5P_DEFAULT,
-      H5P_DEFAULT);
-  if (*retval < 0) {
-    boost::format m("call to HDF5 C-function H5Gcreate2() returned error %d. HDF5 error statck follows:\n%s");
-    m % *retval % bob::io::base::format_hdf5_error();
-    throw std::runtime_error(m.str());
-  }
-  return retval;
-}
-
-static boost::shared_ptr<hid_t> open_group(boost::shared_ptr<hid_t> g,
-    const char* name) {
-  boost::shared_ptr<hid_t> retval(new hid_t(-1), std::ptr_fun(delete_h5g));
-  *retval = H5Gopen2(*g, name, H5P_DEFAULT);
-  if (*retval < 0) {
-    boost::format m("call to HDF5 C-function H5Gopen2() returned error %d. HDF5 error statck follows:\n%s");
-    m % *retval % bob::io::base::format_hdf5_error();
-    throw std::runtime_error(m.str());
-  }
-  return retval;
-}
-
-bob::io::base::detail::hdf5::Group::Group(boost::shared_ptr<Group> parent, const std::string& name):
-  m_name(name),
-  m_id(create_new_group(parent->location(), name)),
-  m_parent(parent)
-{
-}
-
-/**
- * Simple wrapper to call internal bob::io::base::detail::hdf5::Group::iterate_callback, that can call
- * Group and Dataset constructors. Note that those are private or protected for
- * design reasons.
- */
-static herr_t group_iterate_callback(hid_t self, const char *name,
-    const H5L_info_t *info, void *object) {
-  return static_cast<bob::io::base::detail::hdf5::Group*>(object)->iterate_callback(self, name, info);
-}
-
-herr_t bob::io::base::detail::hdf5::Group::iterate_callback(hid_t self, const char *name,
-    const H5L_info_t *info) {
-
-  // If we are not looking at a hard link to the data, just ignore
-  if (info->type != H5L_TYPE_HARD) {
-    TDEBUG1("Ignoring soft-link `" << name << "' in HDF5 file");
-    return 0;
-  }
-
-  // Get information about the HDF5 object
-  H5O_info_t obj_info;
-  herr_t status = H5Oget_info_by_name(self, name, &obj_info, H5P_DEFAULT);
-  if (status < 0) {
-    boost::format m("call to HDF5 C-function H5Oget_info_by_name() returned error %d. HDF5 error statck follows:\n%s");
-    m % status % bob::io::base::format_hdf5_error();
-    throw std::runtime_error(m.str());
-  }
-
-  switch(obj_info.type) {
-    case H5O_TYPE_GROUP:
-      //creates with recursion
-      m_groups[name] = boost::make_shared<bob::io::base::detail::hdf5::Group>(shared_from_this(),
-          name, true);
-      m_groups[name]->open_recursively();
-      break;
-    case H5O_TYPE_DATASET:
-      m_datasets[name] = boost::make_shared<bob::io::base::detail::hdf5::Dataset>(shared_from_this(),
-          std::string(name));
-      break;
-    default:
-      break;
-  }
-
-  return 0;
-}
-
-bob::io::base::detail::hdf5::Group::Group(boost::shared_ptr<Group> parent,
-    const std::string& name, bool):
-  m_name(name),
-  m_id(open_group(parent->location(), name.c_str())),
-  m_parent(parent)
-{
-  //checks name
-  if (!m_name.size() || m_name == "." || m_name == "..") {
-    boost::format m("Cannot create group with illegal name `%s' at `%s'");
-    m % name % url();
-    throw std::runtime_error(m.str());
-  }
-}
-
-void bob::io::base::detail::hdf5::Group::open_recursively() {
-  //iterates over this group only and instantiates what needs to be instantiated
-  herr_t status = H5Literate(*m_id, H5_INDEX_NAME,
-      H5_ITER_NATIVE, 0, group_iterate_callback, static_cast<void*>(this));
-  if (status < 0) {
-    boost::format m("Call to HDF5 C-function H5Literate() returned error %d. HDF5 error statck follows:\n%s");
-    m % status % bob::io::base::format_hdf5_error();
-    throw std::runtime_error(m.str());
-  }
-}
-
-bob::io::base::detail::hdf5::Group::Group(boost::shared_ptr<File> parent):
-  m_name(""),
-  m_id(open_group(parent->location(), "/")),
-  m_parent()
-{
-}
-
-bob::io::base::detail::hdf5::Group::~Group() { }
-
-const boost::shared_ptr<bob::io::base::detail::hdf5::Group> bob::io::base::detail::hdf5::Group::parent() const {
-  return m_parent.lock();
-}
-
-boost::shared_ptr<bob::io::base::detail::hdf5::Group> bob::io::base::detail::hdf5::Group::parent() {
-  return m_parent.lock();
-}
-
-const std::string& bob::io::base::detail::hdf5::Group::filename() const {
-  return parent()->filename();
-}
-
-std::string bob::io::base::detail::hdf5::Group::path() const {
-  return (m_name.size()?parent()->path():"") + "/" + m_name;
-}
-
-std::string bob::io::base::detail::hdf5::Group::url() const {
-  return filename() + ":" + path();
-}
-
-const boost::shared_ptr<bob::io::base::detail::hdf5::File> bob::io::base::detail::hdf5::Group::file() const {
-  return parent()->file();
-}
-
-boost::shared_ptr<bob::io::base::detail::hdf5::File> bob::io::base::detail::hdf5::Group::file() {
-  return parent()->file();
-}
-
-boost::shared_ptr<bob::io::base::detail::hdf5::Group> bob::io::base::detail::hdf5::Group::cd(const std::string& dir) {
-  //empty dir == void action, return self
-  if (!dir.size()) return shared_from_this();
-
-  if (dir[0] == '/') { //absolute path given, apply to root node
-    return file()->root()->cd(dir.substr(1));
-  }
-
-  //relative path given, start from self
-  std::string::size_type pos = dir.find_first_of('/');
-  if (pos == std::string::npos) { //it should be one of my children
-    if (dir == ".") return shared_from_this();
-    if (dir == "..") {
-      if (!m_name.size()) { //this is the root group already
-        boost::format m("Cannot go beyond root directory at file `%s'");
-        m % file()->filename();
-        throw std::runtime_error(m.str());
-      }
-      //else, just return its parent
-      return parent();
-    }
-    if (!has_group(dir)) {
-      boost::format m("Cannot find group `%s' at `%s'");
-      m % dir % url();
-      throw std::runtime_error(m.str());
-    }
-    //else, just return the named group
-    return m_groups[dir];
-  }
-
-  //if you get to this point, we are just traversing
-  std::string mydir = dir.substr(0, pos);
-  if (mydir == ".") return cd(dir.substr(pos+1));
-  if (mydir == "..") return parent()->cd(dir.substr(pos+1));
-  if (!has_group(mydir)) {
-    boost::format m("Cannot find group `%s' at `%s'");
-    m % dir % url();
-    throw std::runtime_error(m.str());
-  }
-
-  //else, just recurse to the next group
-  return m_groups[mydir]->cd(dir.substr(pos+1));
-}
-
-const boost::shared_ptr<bob::io::base::detail::hdf5::Group> bob::io::base::detail::hdf5::Group::cd(const std::string& dir) const {
-  return const_cast<bob::io::base::detail::hdf5::Group*>(this)->cd(dir);
-}
-
-boost::shared_ptr<bob::io::base::detail::hdf5::Dataset> bob::io::base::detail::hdf5::Group::operator[] (const std::string& dir) {
-  std::string::size_type pos = dir.find_last_of('/');
-  if (pos == std::string::npos) { //search on the current group
-    if (!has_dataset(dir)) {
-      boost::format m("Cannot find dataset `%s' at `%s'");
-      m % dir % url();
-      throw std::runtime_error(m.str());
-    }
-    return m_datasets[dir];
-  }
-
-  //if you get to this point, the search routine needs to be performed on
-  //another group, indicated by the path. So, we first cd() there and then do
-  //the same as we do here. This will recurse through the directory structure
-  //until we find the place defined by the user or raise an exception.
-  std::string dest = dir.substr(0, pos);
-  if (!dest.size()) dest = "/";
-  boost::shared_ptr<bob::io::base::detail::hdf5::Group> g = cd(dest);
-  return g->operator[](dir.substr(pos+1));
-}
-
-const boost::shared_ptr<bob::io::base::detail::hdf5::Dataset> bob::io::base::detail::hdf5::Group::operator[] (const std::string& dir) const {
-  return const_cast<bob::io::base::detail::hdf5::Group*>(this)->operator[](dir);
-}
-
-void bob::io::base::detail::hdf5::Group::reset() {
-  typedef std::map<std::string, boost::shared_ptr<bob::io::base::detail::hdf5::Group> > group_map_type;
-  for (group_map_type::const_iterator it = m_groups.begin();
-      it != m_groups.end(); ++it) {
-    remove_group(it->first);
-  }
-
-  typedef std::map<std::string, boost::shared_ptr<bob::io::base::detail::hdf5::Dataset> >
-    dataset_map_type;
-  for (dataset_map_type::const_iterator it = m_datasets.begin();
-      it != m_datasets.end(); ++it) {
-    remove_dataset(it->first);
-  }
-}
-
-boost::shared_ptr<bob::io::base::detail::hdf5::Group> bob::io::base::detail::hdf5::Group::create_group(const std::string& dir) {
-  std::string::size_type pos = dir.find_last_of('/');
-  if (pos == std::string::npos) { //creates on the current group
-    boost::shared_ptr<bob::io::base::detail::hdf5::Group> g =
-      boost::make_shared<bob::io::base::detail::hdf5::Group>(shared_from_this(), dir);
-    m_groups[dir] = g;
-    return g;
-  }
-
-  //if you get to this point, the search routine needs to be performed on
-  //another group, indicated by the path. So, we first cd() there and then do
-  //the same as we do here. This will recurse through the directory structure
-  //until we find the place defined by the user or raise an exception.
-  std::string dest = dir.substr(0, pos);
-  if (!dest.size()) dest = "/";
-  boost::shared_ptr<bob::io::base::detail::hdf5::Group> g = cd(dest);
-  return g->create_group(dir.substr(pos+1));
-}
-
-void bob::io::base::detail::hdf5::Group::remove_group(const std::string& dir) {
-  std::string::size_type pos = dir.find_last_of('/');
-  if (pos == std::string::npos) { //copy on the current group
-    herr_t status = H5Ldelete(*m_id, dir.c_str(), H5P_DEFAULT);
-    if (status < 0) {
-      boost::format m("Call to HDF5 C-function H5Ldelete() returned error %d. HDF5 error statck follows:\n%s");
-      m % status % bob::io::base::format_hdf5_error();
-      throw std::runtime_error(m.str());
-    }
-    typedef std::map<std::string, boost::shared_ptr<bob::io::base::detail::hdf5::Group> > map_type;
-    map_type::iterator it = m_groups.find(dir);
-    m_groups.erase(it);
-    return;
-  }
-
-  //if you get to this point, the removal routine needs to be performed on
-  //another group, indicated by the path. So, we first cd() there and then do
-  //the same as we do here. This will recurse through the directory structure
-  //until we find the place defined by the user or raise an exception.
-  std::string dest = dir.substr(0, pos);
-  if (!dest.size()) dest = "/";
-  boost::shared_ptr<bob::io::base::detail::hdf5::Group> g = cd(dest);
-  return g->remove_group(dir.substr(pos+1));
-}
-
-/**
- * Opens an "auto-destructible" HDF5 property list
- */
-static void delete_h5plist (hid_t* p) {
-  if (*p >= 0) {
-    herr_t err = H5Pclose(*p);
-    if (err < 0) {
-      bob::core::error << "H5Pclose() exited with an error (" << err << "). The stack trace follows:" << std::endl;
-      bob::core::error << bob::io::base::format_hdf5_error() << std::endl;
-    }
-  }
-  delete p;
-}
-
-static boost::shared_ptr<hid_t> open_plist(hid_t classid) {
-  boost::shared_ptr<hid_t> retval(new hid_t(-1), std::ptr_fun(delete_h5plist));
-  *retval = H5Pcreate(classid);
-  if (*retval < 0) {
-    boost::format m("call to HDF5 C-function H5Pcreate() returned error %d. HDF5 error statck follows:\n%s");
-    m % *retval % bob::io::base::format_hdf5_error();
-    throw std::runtime_error(m.str());
-  }
-  return retval;
-}
-
-void bob::io::base::detail::hdf5::Group::rename_group(const std::string& from, const std::string& to) {
-  boost::shared_ptr<hid_t> create_props = open_plist(H5P_LINK_CREATE);
-  H5Pset_create_intermediate_group(*create_props, 1);
-  herr_t status = H5Lmove(*m_id, from.c_str(), H5L_SAME_LOC, to.c_str(),
-      *create_props, H5P_DEFAULT);
-  if (status < 0) {
-    boost::format m("Call to HDF5 C-function H5Lmove() returned error %d. HDF5 error statck follows:\n%s");
-    m % status % bob::io::base::format_hdf5_error();
-    throw std::runtime_error(m.str());
-  }
-}
-
-void bob::io::base::detail::hdf5::Group::copy_group(const boost::shared_ptr<Group> other,
-    const std::string& dir) {
-  std::string::size_type pos = dir.find_last_of('/');
-  if (pos == std::string::npos) { //copy on the current group
-    const char* use_name = dir.size()?dir.c_str():other->name().c_str();
-    herr_t status = H5Ocopy(*other->parent()->location(),
-        other->name().c_str(), *m_id, use_name, H5P_DEFAULT, H5P_DEFAULT);
-    if (status < 0) {
-      boost::format m("call to HDF5 C-function H5Ocopy() returned error %d. HDF5 error statck follows:\n%s");
-      m % status % bob::io::base::format_hdf5_error();
-      throw std::runtime_error(m.str());
-    }
-
-    //read new group contents
-    boost::shared_ptr<bob::io::base::detail::hdf5::Group> copied =
-      boost::make_shared<bob::io::base::detail::hdf5::Group>(shared_from_this(), use_name);
-    copied->open_recursively();
-
-    //index it
-    m_groups[use_name] = copied;
-
-    return;
-  }
-
-  //if you get to this point, the copy routine needs to be performed on
-  //another group, indicated by the path. So, we first cd() there and then do
-  //the same as we do here. This will recurse through the directory structure
-  //until we find the place defined by the user or return false.
-  std::string dest = dir.substr(0, pos);
-  if (!dest.size()) dest = "/";
-  boost::shared_ptr<bob::io::base::detail::hdf5::Group> g = cd(dest);
-  return g->copy_group(other, dir.substr(pos+1));
-}
-
-bool bob::io::base::detail::hdf5::Group::has_group(const std::string& dir) const {
-  std::string::size_type pos = dir.find_last_of('/');
-  if (pos == std::string::npos) { //search on the current group
-    if (dir == "." || dir == "..") return true; //special case
-    typedef std::map<std::string, boost::shared_ptr<bob::io::base::detail::hdf5::Group> > map_type;
-    map_type::const_iterator it = m_groups.find(dir);
-    return (it != m_groups.end());
-  }
-
-  //if you get to this point, the search routine needs to be performed on
-  //another group, indicated by the path. So, we first cd() there and then do
-  //the same as we do here. This will recurse through the directory structure
-  //until we find the place defined by the user or return false.
-  std::string dest = dir.substr(0, pos);
-  if (!dest.size()) dest = "/";
-  boost::shared_ptr<bob::io::base::detail::hdf5::Group> g = cd(dest);
-  return g->has_group(dir.substr(pos+1));
-}
-
-boost::shared_ptr<bob::io::base::detail::hdf5::Dataset> bob::io::base::detail::hdf5::Group::create_dataset
-(const std::string& dir, const bob::io::base::HDF5Type& type, bool list,
- size_t compression) {
-  std::string::size_type pos = dir.find_last_of('/');
-  if (pos == std::string::npos) { //creates on the current group
-    boost::shared_ptr<bob::io::base::detail::hdf5::Dataset> d =
-      boost::make_shared<bob::io::base::detail::hdf5::Dataset>(shared_from_this(), dir, type,
-          list, compression);
-    m_datasets[dir] = d;
-    return d;
-  }
-
-  //if you get to this point, the search routine needs to be performed on
-  //another group, indicated by the path. So, we first cd() there and then do
-  //the same as we do here. This will recurse through the directory structure
-  //until we find the place defined by the user or return false.
-  std::string dest = dir.substr(0, pos);
-  boost::shared_ptr<bob::io::base::detail::hdf5::Group> g;
-  if (!dest.size()) g = cd("/");
-  else {
-    //let's make sure the directory exists, or let's create it recursively
-    if (!has_group(dest)) g = create_group(dest);
-    else g = cd(dest);
-  }
-  return g->create_dataset(dir.substr(pos+1), type, list, compression);
-}
-
-void bob::io::base::detail::hdf5::Group::remove_dataset(const std::string& dir) {
-  std::string::size_type pos = dir.find_last_of('/');
-  if (pos == std::string::npos) { //removes on the current group
-    herr_t status = H5Ldelete(*m_id, dir.c_str(), H5P_DEFAULT);
-    if (status < 0) {
-      boost::format m("Call to HDF5 C-function H5Ldelete() returned error %d. HDF5 error statck follows:\n%s");
-      m % status % bob::io::base::format_hdf5_error();
-      throw std::runtime_error(m.str());
-    }
-    typedef std::map<std::string, boost::shared_ptr<bob::io::base::detail::hdf5::Dataset> > map_type;
-    map_type::iterator it = m_datasets.find(dir);
-    m_datasets.erase(it);
-    return;
-  }
-
-  //if you get to this point, the removal routine needs to be performed on
-  //another group, indicated by the path. So, we first cd() there and then do
-  //the same as we do here. This will recurse through the directory structure
-  //until we find the place defined by the user or raise an exception.
-  std::string dest = dir.substr(0, pos);
-  if (!dest.size()) dest = "/";
-  boost::shared_ptr<bob::io::base::detail::hdf5::Group> g = cd(dest);
-  return g->remove_dataset(dir.substr(pos+1));
-}
-
-void bob::io::base::detail::hdf5::Group::rename_dataset(const std::string& from, const std::string& to) {
-  boost::shared_ptr<hid_t> create_props = open_plist(H5P_LINK_CREATE);
-  H5Pset_create_intermediate_group(*create_props, 1);
-  herr_t status = H5Lmove(*m_id, from.c_str(), H5L_SAME_LOC, to.c_str(),
-      *create_props, H5P_DEFAULT);
-  if (status < 0) {
-    boost::format m("Call to HDF5 C-function H5Ldelete() returned error %d. HDF5 error statck follows:\n%s");
-    m % status % bob::io::base::format_hdf5_error();
-    throw std::runtime_error(m.str());
-  }
-}
-
-void bob::io::base::detail::hdf5::Group::copy_dataset(const boost::shared_ptr<Dataset> other,
-    const std::string& dir) {
-
-  std::string::size_type pos = dir.find_last_of('/');
-  if (pos == std::string::npos) { //search on the current group
-    const char* use_name = dir.size()?dir.c_str():other->name().c_str();
-    herr_t status = H5Ocopy(*other->parent()->location(),
-        other->name().c_str(), *m_id, use_name, H5P_DEFAULT, H5P_DEFAULT);
-    if (status < 0) {
-      boost::format m("Call to HDF5 C-function H5Ocopy() returned error %d. HDF5 error statck follows:\n%s");
-      m % status % bob::io::base::format_hdf5_error();
-      throw std::runtime_error(m.str());
-    }
-    //read new group contents
-    m_datasets[use_name] = boost::make_shared<bob::io::base::detail::hdf5::Dataset>(shared_from_this(), use_name);
-    return;
-  }
-
-  //if you get to this point, the copy routine needs to be performed on
-  //another group, indicated by the path. So, we first cd() there and then do
-  //the same as we do here. This will recurse through the directory structure
-  //until we find the place defined by the user.
-  std::string dest = dir.substr(0, pos);
-  if (!dest.size()) dest = "/";
-  boost::shared_ptr<bob::io::base::detail::hdf5::Group> g = cd(dest);
-  return g->copy_dataset(other, dir.substr(pos+1));
-}
-
-bool bob::io::base::detail::hdf5::Group::has_dataset(const std::string& dir) const {
-  std::string::size_type pos = dir.find_last_of('/');
-  if (pos == std::string::npos) { //search on the current group
-    typedef std::map<std::string, boost::shared_ptr<bob::io::base::detail::hdf5::Dataset> > map_type;
-    map_type::const_iterator it = m_datasets.find(dir);
-    return (it != m_datasets.end());
-  }
-
-  //if you get to this point, the search routine needs to be performed on
-  //another group, indicated by the path. So, we first cd() there and then do
-  //the same as we do here. This will recurse through the directory structure
-  //until we find the place defined by the user or return false.
-  std::string dest = dir.substr(0, pos);
-  if (!dest.size()) dest = "/";
-  boost::shared_ptr<bob::io::base::detail::hdf5::Group> g = cd(dest);
-  return g->has_dataset(dir.substr(pos+1));
-}
-
-void bob::io::base::detail::hdf5::Group::gettype_attribute(const std::string& name,
-    bob::io::base::HDF5Type& type) const {
-  bob::io::base::detail::hdf5::gettype_attribute(m_id, name, type);
-}
-
-bool bob::io::base::detail::hdf5::Group::has_attribute(const std::string& name) const {
-  return bob::io::base::detail::hdf5::has_attribute(m_id, name);
-}
-
-void bob::io::base::detail::hdf5::Group::delete_attribute (const std::string& name) {
-  bob::io::base::detail::hdf5::delete_attribute(m_id, name);
-}
-
-void bob::io::base::detail::hdf5::Group::read_attribute (const std::string& name,
-    const bob::io::base::HDF5Type& dest_type, void* buffer) const {
-  bob::io::base::detail::hdf5::read_attribute(m_id, name, dest_type, buffer);
-}
-
-void bob::io::base::detail::hdf5::Group::write_attribute (const std::string& name,
-    const bob::io::base::HDF5Type& dest_type, const void* buffer) {
-  bob::io::base::detail::hdf5::write_attribute(m_id, name, dest_type, buffer);
-}
-
-void bob::io::base::detail::hdf5::Group::list_attributes(std::map<std::string, bob::io::base::HDF5Type>& attributes) const {
-  bob::io::base::detail::hdf5::list_attributes(m_id, attributes);
-}
-
-template <> void bob::io::base::detail::hdf5::Group::set_attribute<std::string>(const std::string& name, const std::string& v) {
-  bob::io::base::HDF5Type dest_type(v);
-  write_attribute(name, dest_type, reinterpret_cast<const void*>(v.c_str()));
-}
-
-template <> std::string bob::io::base::detail::hdf5::Group::get_attribute(const std::string& name) const {
-  HDF5Type type;
-  gettype_attribute(name, type);
-  boost::shared_array<char> v(new char[type.shape()[0]+1]);
-  v[type.shape()[0]] = 0; ///< null termination
-  read_attribute(name, type, reinterpret_cast<void*>(v.get()));
-  std::string retval(v.get());
-  return retval;
-}
-
-bob::io::base::detail::hdf5::RootGroup::RootGroup(boost::shared_ptr<File> parent):
-  bob::io::base::detail::hdf5::Group(parent),
-  m_parent(parent)
-{
-}
-
-bob::io::base::detail::hdf5::RootGroup::~RootGroup() {
-}
-
-const std::string& bob::io::base::detail::hdf5::RootGroup::filename() const {
-  return m_parent.lock()->filename();
-}
diff --git a/bob/io/base/cpp/HDF5Types.cpp b/bob/io/base/cpp/HDF5Types.cpp
deleted file mode 100644
index 0f38566863e7b727b5c36d4b68232de0ca0f7b14..0000000000000000000000000000000000000000
--- a/bob/io/base/cpp/HDF5Types.cpp
+++ /dev/null
@@ -1,866 +0,0 @@
-/**
- * @date Wed Jun 22 17:50:08 2011 +0200
- * @author Andre Anjos <andre.anjos@idiap.ch>
- *
- * @brief A few helpers to handle HDF5 datasets in a more abstract way.
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#include <boost/format.hpp>
-#include <sstream>
-#include <boost/make_shared.hpp>
-
-/**
- * MT "lock" support was only introduced in Boost 1.35. Before copying this
- * very ugly hack, make sure we are still using Boost 1.34. This will no longer
- * be the case starting January 2011.
- */
-#include <boost/version.hpp>
-#include <boost/thread/mutex.hpp>
-#if ((BOOST_VERSION / 100) % 1000) > 34
-#include <boost/thread/locks.hpp>
-#else
-#warning Disabling MT locks because Boost < 1.35!
-#endif
-
-#include <bob.core/logging.h>
-
-#include <bob.io.base/HDF5Types.h>
-
-const char* bob::io::base::stringize (hdf5type t) {
-  switch (t) {
-    case bob::io::base::s:
-      return "string";
-    case bob::io::base::b:
-      return "bool";
-    case bob::io::base::i8:
-      return "int8";
-    case bob::io::base::i16:
-      return "int16";
-    case bob::io::base::i32:
-      return "int32";
-    case bob::io::base::i64:
-      return "int64";
-    case bob::io::base::u8:
-      return "uint8";
-    case bob::io::base::u16:
-      return "uint16";
-    case bob::io::base::u32:
-      return "uint32";
-    case bob::io::base::u64:
-      return "uint64";
-    case bob::io::base::f32:
-      return "float32";
-    case bob::io::base::f64:
-      return "float64";
-    case bob::io::base::f128:
-      return "float128";
-    case bob::io::base::c64:
-      return "complex64";
-    case bob::io::base::c128:
-      return "complex128";
-    case bob::io::base::c256:
-      return "complex256";
-    case bob::io::base::unsupported:
-      return "unsupported";
-  }
-  return "unsupported"; ///< just to silence gcc
-}
-
-static herr_t walker(unsigned n, const H5E_error2_t *desc, void *cookie) {
-  bob::io::base::HDF5ErrorStack& stack = *(bob::io::base::HDF5ErrorStack*)cookie;
-  std::vector<std::string>& sv = stack.get();
-  boost::format fmt("%s() @ %s+%d: %s");
-  fmt % desc->func_name % desc->file_name % desc->line % desc->desc;
-  sv.push_back(fmt.str());
-  return 0;
-}
-
-static herr_t err_callback(hid_t stack, void* cookie) {
-  bob::io::base::HDF5ErrorStack& err_stack = *(bob::io::base::HDF5ErrorStack*)cookie;
-  if (!err_stack.muted()) H5Ewalk2(stack, H5E_WALK_DOWNWARD, walker, cookie);
-  H5Eclear2(stack);
-  return 0;
-}
-
-bob::io::base::HDF5ErrorStack::HDF5ErrorStack ():
-  m_stack(H5E_DEFAULT),
-  m_muted(false),
-  m_err(),
-  m_func(0),
-  m_client_data(0)
-{
-  H5Eget_auto2(m_stack, &m_func, &m_client_data);
-  H5Eset_auto2(m_stack, err_callback, this);
-}
-
-bob::io::base::HDF5ErrorStack::HDF5ErrorStack (hid_t stack):
-  m_stack(stack),
-  m_muted(false),
-  m_err(),
-  m_func(0),
-  m_client_data(0)
-{
-  H5Eget_auto2(m_stack, &m_func, &m_client_data);
-  H5Eset_auto2(m_stack, err_callback, this);
-}
-
-bob::io::base::HDF5ErrorStack::~HDF5ErrorStack () {
-  H5Eset_auto2(m_stack, m_func, m_client_data);
-}
-
-//creates a pointer to the default HDF5 error stack that is global to the
-//application level.
-const boost::shared_ptr<bob::io::base::HDF5ErrorStack>
-  bob::io::base::DefaultHDF5ErrorStack(new HDF5ErrorStack());
-
-bob::io::base::HDF5Shape::HDF5Shape (size_t n):
-  m_n(n),
-  m_shape()
-{
-  if (n > MAX_HDF5SHAPE_SIZE) {
-    boost::format m("cannot create shape with %u dimensions, exceeding the maximum number of dimensions supported by this API (%u)");
-    m % n % MAX_HDF5SHAPE_SIZE;
-    throw std::runtime_error(m.str());
-  }
-  for (size_t i=0; i<n; ++i) m_shape[i] = 0;
-}
-
-bob::io::base::HDF5Shape::HDF5Shape ():
-  m_n(0),
-  m_shape()
-{
-}
-
-bob::io::base::HDF5Shape::HDF5Shape (const bob::io::base::HDF5Shape& other):
-  m_n(other.m_n),
-  m_shape()
-{
-  for (size_t i=0; i<m_n; ++i) m_shape[i] = other.m_shape[i];
-}
-
-bob::io::base::HDF5Shape::~HDF5Shape() {
-}
-
-bob::io::base::HDF5Shape& bob::io::base::HDF5Shape::operator= (const bob::io::base::HDF5Shape& other) {
-  m_n = other.m_n;
-  for (size_t i=0; i<m_n; ++i) m_shape[i] = other.m_shape[i];
-  return *this;
-}
-
-void bob::io::base::HDF5Shape::copy(const bob::io::base::HDF5Shape& other) {
-  if (m_n <= other.m_n) { //I'm smaller or equal
-    for (size_t i=0; i<m_n; ++i) m_shape[i] = other.m_shape[i];
-  }
-  else { //The other is smaller
-    for (size_t i=0; i<other.m_n; ++i) m_shape[i] = other.m_shape[i];
-  }
-}
-
-void bob::io::base::HDF5Shape::reset() {
-  m_n = 0;
-}
-
-bob::io::base::HDF5Shape& bob::io::base::HDF5Shape::operator <<= (size_t pos) {
-  if (!m_n || !pos) return *this;
-  for (size_t i=0; i<(m_n-pos); ++i) m_shape[i] = m_shape[i+pos];
-  m_n -= pos;
-  return *this;
-}
-
-bob::io::base::HDF5Shape& bob::io::base::HDF5Shape::operator >>= (size_t pos) {
-  if (!pos) return *this;
-  if ( (m_n + pos) > MAX_HDF5SHAPE_SIZE) {
-    boost::format m("if you shift right this shape by %u positions, you will exceed the maximum number of dimensions supported by this API (%u)");
-    m % pos % MAX_HDF5SHAPE_SIZE;
-    throw std::runtime_error(m.str());
-  }
-  for (size_t i=(m_n+pos-1); i>(pos-1); --i) m_shape[i] = m_shape[i-1];
-  for (size_t i=0; i<pos; ++i) m_shape[i] = 1;
-  m_n += pos;
-  return *this;
-}
-
-hsize_t bob::io::base::HDF5Shape::product() const {
-  hsize_t retval = 1;
-  for (size_t i=0; i<m_n; ++i) retval *= m_shape[i];
-  return retval;
-}
-
-bool bob::io::base::HDF5Shape::operator== (const HDF5Shape& other) const {
-  if (m_n != other.m_n) return false;
-  for (size_t i=0; i<m_n; ++i) if (m_shape[i] != other[i]) return false;
-  return true;
-}
-
-bool bob::io::base::HDF5Shape::operator!= (const HDF5Shape& other) const {
-  return !(*this == other);
-}
-
-std::string bob::io::base::HDF5Shape::str () const {
-  if (m_n == 0) return "";
-  std::ostringstream retval("");
-  retval << m_shape[0];
-  for (size_t i=1; i<m_n; ++i) retval << ", " << m_shape[i];
-  return retval.str();
-}
-
-/**
- * Deleter method for auto-destroyable HDF5 datatypes.
- */
-static void delete_h5datatype (hid_t* p) {
-  if (*p >= 0) {
-    herr_t err = H5Tclose(*p);
-    if (err < 0) {
-      bob::core::error << "H5Tclose() exited with an error (" << err << "). The stack trace follows:" << std::endl;
-      bob::core::error << bob::io::base::format_hdf5_error() << std::endl;
-    }
-  }
-  delete p;
-}
-
-/**
- * Given a datatype which is a compound type, returns the std::complex<T>
- * hdf5type equivalent or raises.
- */
-static bob::io::base::hdf5type equivctype(const boost::shared_ptr<hid_t>& dt) {
-  if (H5Tget_nmembers(*dt) != 2) throw std::runtime_error("the internal HDF5 type is not supported by our HDF5 interface");
-
-  //members have to:
-  // 1. have names "real" and "imag"
-  // 2. have class type H5T_FLOAT
-  // 3. have equal size
-  // 4. have a size of 4, 8 or 16 bytes
-
-  // 1.
-  int real = H5Tget_member_index(*dt, "real");
-  if (real < 0) {
-    throw std::runtime_error("the complex member index for `real' is not present on this HDF5 type");
-  }
-  int imag = H5Tget_member_index(*dt, "imag");
-  if (imag < 0) {
-    throw std::runtime_error("the complex member index for `imag' is not present on this HDF5 type");
-  }
-
-  // 2.
-  if (H5Tget_member_class(*dt, real) != H5T_FLOAT)
-    throw std::runtime_error("the raw type for member `real' on complex structure in HDF5 is not H5T_FLOAT as expected");
-  if (H5Tget_member_class(*dt, imag) != H5T_FLOAT)
-    throw std::runtime_error("the raw type for member `imag' on complex structure in HDF5 is not H5T_FLOAT as expected");
-
-  // 3.
-  boost::shared_ptr<hid_t> realid(new hid_t(-1), std::ptr_fun(delete_h5datatype));
-  *realid = H5Tget_member_type(*dt, real);
-  boost::shared_ptr<hid_t> imagid(new hid_t(-1), std::ptr_fun(delete_h5datatype));
-  *imagid = H5Tget_member_type(*dt, imag);
-  size_t realsize = H5Tget_size(*realid);
-  size_t imagsize = H5Tget_size(*imagid);
-  if (realsize != imagsize) {
-    throw std::runtime_error("the sizes of the real and imaginary parts on HDF5 complex struct are not the same");
-  }
-
-  // 4.
-  switch (realsize) {
-    case 4: //std::complex<float>
-      return bob::io::base::c64;
-    case 8: //std::complex<double>
-      return bob::io::base::c128;
-    case 16: //std::complex<double>
-      return bob::io::base::c256;
-    default:
-      break;
-  }
-
-  throw std::runtime_error("could not find the equivalent internal type for (supposedly) complex HDF5 structure");
-}
-
-/**
- * Checks if a given type can be read as boolean
- */
-static void checkbool(const boost::shared_ptr<hid_t>& dt) {
-
-  if (H5Tget_nmembers(*dt) != 2) {
-    throw std::runtime_error("the number of enumeration members for the locally installed boolean type is not 2");
-  }
-
-  int8_t value;
-  herr_t status = H5Tget_member_value(*dt, 0, &value);
-  if (status < 0) {
-    boost::format m("call to HDF5 C-function H5Tget_member_value() returned error %d. HDF5 error statck follows:\n%s");
-    m % status % bob::io::base::format_hdf5_error();
-    throw std::runtime_error(m.str());
-  }
-  bool next_is_false = false;
-  if (value != 0) next_is_false = true;
-  status = H5Tget_member_value(*dt, 1, &value);
-  if (status < 0) {
-    boost::format m("call to HDF5 C-function H5Tget_member_value() returned error %d. HDF5 error statck follows:\n%s");
-    m % status % bob::io::base::format_hdf5_error();
-    throw std::runtime_error(m.str());
-  }
-  if (next_is_false) {
-    if (value != 0) {
-      throw std::runtime_error("the attribution of false(0) or true(1) is messed up on the current data type, which is supposed to be a boolean");
-    }
-  }
-  else {
-    if (value == 0) {
-      throw std::runtime_error("the attribution of false(0) or true(1) is messed up on the current data type, which is supposed to be a boolean");
-    }
-  }
-}
-
-/**
- * Given a datatype, returns the supported type equivalent or raises
- */
-static bob::io::base::hdf5type get_datatype
-(const boost::shared_ptr<hid_t>& dt) {
-  H5T_class_t classtype = H5Tget_class(*dt);
-
-  if (classtype == H5T_STRING) return bob::io::base::s; //no need to check further
-
-  size_t typesize = H5Tget_size(*dt); ///< element size
-  H5T_sign_t signtype = H5Tget_sign(*dt);
-
-  //we only support little-endian byte-ordering
-  H5T_order_t ordertype = H5Tget_order(*dt);
-
-  //please note that checking compound types for hdf5 < 1.8.6 does not work.
-# if H5_VERSION_GE(1,8,6)
-  if (ordertype < 0) {
-    boost::format m("call to HDF5 C-function H5Tget_order returned error %d. HDF5 error statck follows:\n%s");
-    m % ordertype % bob::io::base::format_hdf5_error();
-    throw std::runtime_error(m.str());
-  }
-
-  if (ordertype != H5T_ORDER_LE) {
-    throw std::runtime_error("The endianness of datatype is not little-endian");
-  }
-# else
-  if ((ordertype >= 0) && (ordertype != H5T_ORDER_LE)) {
-    throw std::runtime_error("The endianness of datatype is not little-endian");
-  }
-# endif
-
-  switch (classtype) {
-    case H5T_ENUM:
-      checkbool(dt);
-      return bob::io::base::b;
-    case H5T_INTEGER:
-      switch (typesize) {
-        case 1: //int8 or uint8
-          switch (signtype) {
-            case H5T_SGN_NONE:
-              return bob::io::base::u8;
-            case H5T_SGN_2: //two's complement == "is signed" ;-)
-              return bob::io::base::i8;
-            default:
-              throw std::runtime_error("HDF5 1-byte integer datatype (read from file) cannot be mapped into a C++ type supported by this API");
-          }
-          break;
-        case 2: //int16 or uint16
-          switch (signtype) {
-            case H5T_SGN_NONE:
-              return bob::io::base::u16;
-            case H5T_SGN_2: //two's complement == "is signed" ;-)
-              return bob::io::base::i16;
-            default:
-              throw std::runtime_error("HDF5 2-byte integer datatype (read from file) cannot be mapped into a C++ type supported by this API");
-          }
-          break;
-        case 4: //int32 or uint32
-          switch (signtype) {
-            case H5T_SGN_NONE:
-              return bob::io::base::u32;
-            case H5T_SGN_2: //two's complement == "is signed" ;-)
-              return bob::io::base::i32;
-            default:
-              throw std::runtime_error("HDF5 4-byte integer datatype (read from file) cannot be mapped into a C++ type supported by this API");
-          }
-          break;
-        case 8: //int64 or uint64
-          switch (signtype) {
-            case H5T_SGN_NONE:
-              return bob::io::base::u64;
-            case H5T_SGN_2: //two's complement == "is signed" ;-)
-              return bob::io::base::i64;
-            default:
-              throw std::runtime_error("HDF5 8-byte integer datatype (read from file) cannot be mapped into a C++ type supported by this API");
-          }
-          break;
-        default:
-          break;
-      }
-      break;
-    case H5T_FLOAT:
-      switch (typesize) {
-        case 4: //float
-          return bob::io::base::f32;
-        case 8: //double
-          return bob::io::base::f64;
-        case 16: //long double
-          return bob::io::base::f128;
-        default:
-          break;
-      }
-      break;
-    case H5T_COMPOUND: //complex
-      return equivctype(dt);
-    default:
-      break;
-  }
-
-  throw std::runtime_error("cannot handle HDF5 datatype on file using one of the native types supported by this API");
-}
-
-bool bob::io::base::HDF5Type::compatible (const bob::io::base::array::typeinfo& value) const
-{
-  return *this == HDF5Type(value);
-}
-
-/**
- * Given a datatype, returns the supported HDF5 datatype equivalent or -1
- */
-boost::shared_ptr<hid_t> bob::io::base::HDF5Type::htype() const {
-  switch (m_type) {
-    case bob::io::base::s:
-      {
-        boost::shared_ptr<hid_t> retval(new hid_t(-1),
-            std::ptr_fun(delete_h5datatype));
-        *retval = H5Tcopy(H5T_C_S1);
-        if (*retval < 0) {
-          boost::format m("call to HDF5 C-function H5Tcopy() returned error %d. HDF5 error statck follows:\n%s");
-          m % *retval % bob::io::base::format_hdf5_error();
-          throw std::runtime_error(m.str());
-        }
-
-        //set string size
-        herr_t status = H5Tset_size(*retval, m_shape[0]);
-        if (status < 0) {
-          boost::format m("Call to HDF5 C-function H5Tset_size() returned error %d. HDF5 error statck follows:\n%s");
-          m % status % bob::io::base::format_hdf5_error();
-          throw std::runtime_error(m.str());
-        }
-
-        return retval;
-      }
-    case bob::io::base::b:
-      {
-        //why? HDF5 is a C library and in C there is no boolean type
-        //bottom-line => we have to define our own...
-
-        boost::shared_ptr<hid_t> retval(new hid_t(-1),
-            std::ptr_fun(delete_h5datatype));
-        *retval = H5Tenum_create(H5T_NATIVE_INT8);
-        if (*retval < 0) {
-          boost::format m("call to HDF5 C-function H5Tenum_create() returned error %d. HDF5 error statck follows:\n%s");
-          m % *retval % bob::io::base::format_hdf5_error();
-          throw std::runtime_error(m.str());
-        }
-        int8_t val;
-        herr_t status;
-
-        //defines false
-        val = 0;
-        status = H5Tenum_insert(*retval, "false", &val);
-        if (status < 0) {
-          boost::format m("call to HDF5 C-function H5Tenum_insert() returned error %d. HDF5 error statck follows:\n%s");
-          m % status % bob::io::base::format_hdf5_error();
-          throw std::runtime_error(m.str());
-        }
-
-        //defines true
-        val = 1;
-        status = H5Tenum_insert(*retval, "true",  &val);
-        if (*retval < 0) {
-          boost::format m("call to HDF5 C-function H5Tenum_insert() returned error %d. HDF5 error statck follows:\n%s");
-          m % *retval % bob::io::base::format_hdf5_error();
-          throw std::runtime_error(m.str());
-        }
-
-        return retval;
-      }
-    case bob::io::base::i8:
-      return boost::make_shared<hid_t>(H5T_NATIVE_INT8);
-    case bob::io::base::i16:
-      return boost::make_shared<hid_t>(H5T_NATIVE_INT16);
-    case bob::io::base::i32:
-      return boost::make_shared<hid_t>(H5T_NATIVE_INT32);
-    case bob::io::base::i64:
-      return boost::make_shared<hid_t>(H5T_NATIVE_INT64);
-    case bob::io::base::u8:
-      return boost::make_shared<hid_t>(H5T_NATIVE_UINT8);
-    case bob::io::base::u16:
-      return boost::make_shared<hid_t>(H5T_NATIVE_UINT16);
-    case bob::io::base::u32:
-      return boost::make_shared<hid_t>(H5T_NATIVE_UINT32);
-    case bob::io::base::u64:
-      return boost::make_shared<hid_t>(H5T_NATIVE_UINT64);
-    case bob::io::base::f32:
-      return boost::make_shared<hid_t>(H5T_NATIVE_FLOAT);
-    case bob::io::base::f64:
-      return boost::make_shared<hid_t>(H5T_NATIVE_DOUBLE);
-    case bob::io::base::f128:
-      return boost::make_shared<hid_t>(H5T_NATIVE_LDOUBLE);
-    case bob::io::base::c64:
-      {
-        boost::shared_ptr<hid_t> retval(new hid_t(-1),
-            std::ptr_fun(delete_h5datatype));
-        *retval = H5Tcreate(H5T_COMPOUND, 2*sizeof(float));
-        if (*retval < 0) {
-          boost::format m("call to HDF5 C-function H5Tcreate() returned error %d. HDF5 error statck follows:\n%s");
-          m % *retval % bob::io::base::format_hdf5_error();
-          throw std::runtime_error(m.str());
-        }
-        herr_t status = H5Tinsert(*retval, "real", 0, H5T_NATIVE_FLOAT);
-        if (status < 0) {
-          boost::format m("call to HDF5 C-function H5Tinsert() returned error %d. HDF5 error statck follows:\n%s");
-          m % status % bob::io::base::format_hdf5_error();
-          throw std::runtime_error(m.str());
-        }
-        status = H5Tinsert(*retval, "imag", sizeof(float), H5T_NATIVE_FLOAT);
-        if (status < 0) {
-          boost::format m("call to HDF5 C-function H5Tinsert() returned error %d. HDF5 error statck follows:\n%s");
-          m % status % bob::io::base::format_hdf5_error();
-          throw std::runtime_error(m.str());
-        }
-        return retval;
-      }
-    case bob::io::base::c128:
-      {
-        boost::shared_ptr<hid_t> retval(new hid_t(-1),
-            std::ptr_fun(delete_h5datatype));
-        *retval = H5Tcreate(H5T_COMPOUND, 2*sizeof(double));
-        if (*retval < 0) {
-          boost::format m("call to HDF5 C-function H5Tcreate() returned error %d. HDF5 error statck follows:\n%s");
-          m % *retval % bob::io::base::format_hdf5_error();
-          throw std::runtime_error(m.str());
-        }
-        herr_t status = H5Tinsert(*retval, "real", 0, H5T_NATIVE_DOUBLE);
-        if (status < 0) {
-          boost::format m("call to HDF5 C-function H5Tinsert() returned error %d. HDF5 error statck follows:\n%s");
-          m % status % bob::io::base::format_hdf5_error();
-          throw std::runtime_error(m.str());
-        }
-        status = H5Tinsert(*retval, "imag", sizeof(double), H5T_NATIVE_DOUBLE);
-        if (status < 0) {
-          boost::format m("call to HDF5 C-function H5Tinsert() returned error %d. HDF5 error statck follows:\n%s");
-          m % status % bob::io::base::format_hdf5_error();
-          throw std::runtime_error(m.str());
-        }
-        return retval;
-      }
-    case bob::io::base::c256:
-      {
-        boost::shared_ptr<hid_t> retval(new hid_t(-1),
-            std::ptr_fun(delete_h5datatype));
-        *retval = H5Tcreate(H5T_COMPOUND, 2*sizeof(long double));
-        if (*retval < 0) {
-          boost::format m("call to HDF5 C-function H5Tcreate() returned error %d. HDF5 error statck follows:\n%s");
-          m % *retval % bob::io::base::format_hdf5_error();
-          throw std::runtime_error(m.str());
-        }
-        herr_t status = H5Tinsert(*retval, "real", 0, H5T_NATIVE_LDOUBLE);
-        if (status < 0) {
-          boost::format m("call to HDF5 C-function H5Tinsert() returned error %d. HDF5 error statck follows:\n%s");
-          m % status % bob::io::base::format_hdf5_error();
-          throw std::runtime_error(m.str());
-        }
-        status = H5Tinsert(*retval, "imag", sizeof(long double), H5T_NATIVE_LDOUBLE);
-        if (status < 0) {
-          boost::format m("call to HDF5 C-function H5Tinsert() returned error %d. HDF5 error statck follows:\n%s");
-          m % status % bob::io::base::format_hdf5_error();
-          throw std::runtime_error(m.str());
-        }
-        return retval;
-      }
-    default:
-      break;
-  }
-  throw std::runtime_error("the C++ type you are trying to convert into a native HDF5 type is not supported by this API");
-}
-
-#define DEFINE_SUPPORT(T,E) bob::io::base::HDF5Type::HDF5Type(const T& value): \
-    m_type(E), m_shape(1) { m_shape[0] = 1; }
-DEFINE_SUPPORT(bool,bob::io::base::b)
-DEFINE_SUPPORT(int8_t,bob::io::base::i8)
-DEFINE_SUPPORT(int16_t,bob::io::base::i16)
-DEFINE_SUPPORT(int32_t,bob::io::base::i32)
-DEFINE_SUPPORT(int64_t,bob::io::base::i64)
-DEFINE_SUPPORT(uint8_t,bob::io::base::u8)
-DEFINE_SUPPORT(uint16_t,bob::io::base::u16)
-DEFINE_SUPPORT(uint32_t,bob::io::base::u32)
-DEFINE_SUPPORT(uint64_t,bob::io::base::u64)
-DEFINE_SUPPORT(float,bob::io::base::f32)
-DEFINE_SUPPORT(double,bob::io::base::f64)
-DEFINE_SUPPORT(long double,bob::io::base::f128)
-DEFINE_SUPPORT(std::complex<float>,bob::io::base::c64)
-DEFINE_SUPPORT(std::complex<double>,bob::io::base::c128)
-DEFINE_SUPPORT(std::complex<long double>,bob::io::base::c256)
-#undef DEFINE_SUPPORT
-
-bob::io::base::HDF5Type::HDF5Type(const char* value):
-  m_type(bob::io::base::s),
-  m_shape(1)
-{
-  m_shape[0] = std::strlen(value);
-}
-
-bob::io::base::HDF5Type::HDF5Type(const std::string& value):
-  m_type(bob::io::base::s),
-  m_shape(1)
-{
-  m_shape[0] = value.size();
-}
-
-#define DEFINE_SUPPORT(T,E,N) bob::io::base::HDF5Type::HDF5Type \
-    (const blitz::Array<T,N>& value): \
-      m_type(E), \
-      m_shape(value.shape()) { \
-        if (N > bob::io::base::array::N_MAX_DIMENSIONS_ARRAY) {\
-          boost::format m("you passed an array with %d dimensions, but this HDF5 API only supports arrays with up to %d dimensions"); \
-          m % N % bob::io::base::array::N_MAX_DIMENSIONS_ARRAY; \
-          throw std::runtime_error(m.str()); \
-        } \
-      }
-
-#define DEFINE_BZ_SUPPORT(T,E) \
-  DEFINE_SUPPORT(T,E,1) \
-  DEFINE_SUPPORT(T,E,2) \
-  DEFINE_SUPPORT(T,E,3) \
-  DEFINE_SUPPORT(T,E,4)
-
-DEFINE_BZ_SUPPORT(bool,bob::io::base::b)
-DEFINE_BZ_SUPPORT(int8_t,bob::io::base::i8)
-DEFINE_BZ_SUPPORT(int16_t,bob::io::base::i16)
-DEFINE_BZ_SUPPORT(int32_t,bob::io::base::i32)
-DEFINE_BZ_SUPPORT(int64_t,bob::io::base::i64)
-DEFINE_BZ_SUPPORT(uint8_t,bob::io::base::u8)
-DEFINE_BZ_SUPPORT(uint16_t,bob::io::base::u16)
-DEFINE_BZ_SUPPORT(uint32_t,bob::io::base::u32)
-DEFINE_BZ_SUPPORT(uint64_t,bob::io::base::u64)
-DEFINE_BZ_SUPPORT(float,bob::io::base::f32)
-DEFINE_BZ_SUPPORT(double,bob::io::base::f64)
-DEFINE_BZ_SUPPORT(long double,bob::io::base::f128)
-DEFINE_BZ_SUPPORT(std::complex<float>,bob::io::base::c64)
-DEFINE_BZ_SUPPORT(std::complex<double>,bob::io::base::c128)
-DEFINE_BZ_SUPPORT(std::complex<long double>,bob::io::base::c256)
-#undef DEFINE_BZ_SUPPORT
-#undef DEFINE_SUPPORT
-
-bob::io::base::HDF5Type::HDF5Type():
-  m_type(bob::io::base::unsupported),
-  m_shape()
-{
-}
-
-bob::io::base::HDF5Type::HDF5Type(bob::io::base::hdf5type type):
-  m_type(type),
-  m_shape(1)
-{
-  m_shape[0] = 1;
-}
-
-bob::io::base::HDF5Type::HDF5Type(bob::io::base::hdf5type type, const bob::io::base::HDF5Shape& extents):
-  m_type(type),
-  m_shape(extents)
-{
-}
-
-static bob::io::base::hdf5type array_to_hdf5 (bob::io::base::array::ElementType eltype) {
-  switch(eltype) {
-    case bob::io::base::array::t_unknown:
-      return bob::io::base::unsupported;
-    case bob::io::base::array::t_bool:
-      return bob::io::base::b;
-    case bob::io::base::array::t_int8:
-      return bob::io::base::i8;
-    case bob::io::base::array::t_int16:
-      return bob::io::base::i16;
-    case bob::io::base::array::t_int32:
-      return bob::io::base::i32;
-    case bob::io::base::array::t_int64:
-      return bob::io::base::i64;
-    case bob::io::base::array::t_uint8:
-      return bob::io::base::u8;
-    case bob::io::base::array::t_uint16:
-      return bob::io::base::u16;
-    case bob::io::base::array::t_uint32:
-      return bob::io::base::u32;
-    case bob::io::base::array::t_uint64:
-      return bob::io::base::u64;
-    case bob::io::base::array::t_float32:
-      return bob::io::base::f32;
-    case bob::io::base::array::t_float64:
-      return bob::io::base::f64;
-    case bob::io::base::array::t_float128:
-      return bob::io::base::f128;
-    case bob::io::base::array::t_complex64:
-      return bob::io::base::c64;
-    case bob::io::base::array::t_complex128:
-      return bob::io::base::c128;
-    case bob::io::base::array::t_complex256:
-      return bob::io::base::c256;
-  }
-  throw std::runtime_error("unsupported dtype <=> hdf5 type conversion -- FIXME");
-}
-
-bob::io::base::HDF5Type::HDF5Type(const bob::io::base::array::typeinfo& ti):
-  m_type(array_to_hdf5(ti.dtype)),
-  m_shape(ti.nd, ti.shape)
-{
-}
-
-bob::io::base::HDF5Type::HDF5Type(bob::io::base::array::ElementType eltype,
-    const HDF5Shape& extents):
-  m_type(array_to_hdf5(eltype)),
-  m_shape(extents)
-{
-}
-
-bob::io::base::HDF5Type::HDF5Type(const boost::shared_ptr<hid_t>& type,
-    const bob::io::base::HDF5Shape& extents):
-  m_type(get_datatype(type)),
-  m_shape(extents)
-{
-}
-
-bob::io::base::HDF5Type::HDF5Type(const boost::shared_ptr<hid_t>& type):
-  m_type(get_datatype(type)),
-  m_shape(1)
-{
-  //strings have to be treated slightly differently
-  if (H5Tget_class(*type) == H5T_STRING) m_shape[0] = H5Tget_size(*type);
-  else m_shape[0] = 1;
-}
-
-bob::io::base::HDF5Type::HDF5Type(const HDF5Type& other):
-  m_type(other.m_type),
-  m_shape(other.m_shape)
-{
-}
-
-bob::io::base::HDF5Type::~HDF5Type() { }
-
-bob::io::base::HDF5Type& bob::io::base::HDF5Type::operator= (const bob::io::base::HDF5Type& other)
-{
-  m_type = other.m_type;
-  m_shape = other.m_shape;
-  return *this;
-}
-
-bool bob::io::base::HDF5Type::operator== (const bob::io::base::HDF5Type& other) const {
-  return (m_type == other.m_type) && (m_shape == other.m_shape);
-}
-
-bool bob::io::base::HDF5Type::operator!= (const bob::io::base::HDF5Type& other) const {
-  return !(*this == other);
-}
-
-std::string bob::io::base::HDF5Type::str() const {
-  boost::format retval("%s (%s)");
-  retval % bob::io::base::stringize(m_type) % m_shape.str();
-  return retval.str();
-}
-
-bob::io::base::array::ElementType bob::io::base::HDF5Type::element_type() const {
-  switch (m_type) {
-    case b:
-      return bob::io::base::array::t_bool;
-    case i8:
-      return bob::io::base::array::t_int8;
-    case i16:
-      return bob::io::base::array::t_int16;
-    case i32:
-      return bob::io::base::array::t_int32;
-    case i64:
-      return bob::io::base::array::t_int64;
-    case u8:
-      return bob::io::base::array::t_uint8;
-    case u16:
-      return bob::io::base::array::t_uint16;
-    case u32:
-      return bob::io::base::array::t_uint32;
-    case u64:
-      return bob::io::base::array::t_uint64;
-    case f32:
-      return bob::io::base::array::t_float32;
-    case f64:
-      return bob::io::base::array::t_float64;
-    case f128:
-      return bob::io::base::array::t_float128;
-    case c64:
-      return bob::io::base::array::t_complex64;
-    case c128:
-      return bob::io::base::array::t_complex128;
-    case c256:
-      return bob::io::base::array::t_complex256;
-    case s:
-      throw std::runtime_error("Cannot convert HDF5 string type to an element type to be used in blitz::Array's - FIXME: something is wrong in the logic");
-    default:
-      break;
-  }
-  return bob::io::base::array::t_unknown;
-}
-
-void bob::io::base::HDF5Type::copy_to (bob::io::base::array::typeinfo& ti) const {
-  ti.dtype = element_type();
-  ti.nd = shape().n();
-  if (ti.nd > (BOB_MAX_DIM+1)) {
-    boost::format f("HDF5 type has more (%d) than the allowed maximum number of dimensions (%d)");
-    f % ti.nd % (BOB_MAX_DIM+1);
-    throw std::runtime_error(f.str());
-  }
-  for (size_t i=0; i<ti.nd; ++i) ti.shape[i] = shape()[i];
-  ti.update_strides();
-}
-
-bob::io::base::HDF5Descriptor::HDF5Descriptor(const HDF5Type& type, size_t size,
-          bool expand):
-  type(type),
-  size(size),
-  expandable(expand),
-  hyperslab_start(type.shape().n()),
-  hyperslab_count(type.shape())
-{
-}
-
-bob::io::base::HDF5Descriptor::HDF5Descriptor(const HDF5Descriptor& other):
-  type(other.type),
-  size(other.size),
-  expandable(other.expandable),
-  hyperslab_start(other.hyperslab_start),
-  hyperslab_count(other.hyperslab_count)
-{
-}
-
-bob::io::base::HDF5Descriptor::~HDF5Descriptor() { }
-
-bob::io::base::HDF5Descriptor& bob::io::base::HDF5Descriptor::operator=
-(const bob::io::base::HDF5Descriptor& other) {
-  type = other.type;
-  size = other.size;
-  expandable = other.expandable;
-  hyperslab_start = other.hyperslab_start;
-  hyperslab_count = other.hyperslab_count;
-  return *this;
-}
-
-bob::io::base::HDF5Descriptor& bob::io::base::HDF5Descriptor::subselect() {
-  hyperslab_start >>= 1;
-  hyperslab_count >>= 1;
-  hyperslab_count[0] = 1;
-  return *this;
-}
-
-std::string bob::io::base::format_hdf5_error() {
-  const std::vector<std::string>& stack = bob::io::base::DefaultHDF5ErrorStack->get();
-  std::ostringstream retval;
-  std::string prefix(" ");
-  if (stack.size()) retval << prefix << stack[0];
-  for (size_t i=1; i<stack.size(); ++i)
-    retval << std::endl << prefix << stack[i];
-  bob::io::base::DefaultHDF5ErrorStack->clear();
-  return retval.str();
-}
diff --git a/bob/io/base/cpp/HDF5Utils.cpp b/bob/io/base/cpp/HDF5Utils.cpp
deleted file mode 100644
index 12c13ea807ea3c44c564fbbbddb1f0b3c1bbde50..0000000000000000000000000000000000000000
--- a/bob/io/base/cpp/HDF5Utils.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-/**
- * @date Wed Jun 22 17:50:08 2011 +0200
- * @author Andre Anjos <andre.anjos@idiap.ch>
- *
- * @brief Implements a set of utilities to read HDF5 files.
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#include <boost/format.hpp>
-#include <boost/make_shared.hpp>
-
-#include <bob.core/logging.h>
-
-#include <bob.io.base/HDF5Utils.h>
-
-/**
- * Opens/Creates an "auto-destructible" HDF5 file
- */
-static void delete_h5file (hid_t* p) {
-  if (*p >= 0) {
-    herr_t err = H5Fclose(*p);
-    if (err < 0) {
-      bob::core::error << "H5Fclose(hid=" << *p << ") exited with an error (" << err << "). The stack trace follows:" << std::endl;
-      bob::core::error << bob::io::base::format_hdf5_error() << std::endl;
-    }
-  }
-  delete p;
-}
-
-/**
- * Opens/Creates and "auto-destructible" HDF5 file creation property list
- */
-static void delete_h5p (hid_t* p) {
-  if (*p >= 0) {
-    herr_t err = H5Pclose(*p);
-    if (err < 0) {
-      bob::core::error << "H5Pclose(hid=" << *p << ") exited with an error (" << err << "). The stack trace follows:" << std::endl;
-      bob::core::error << bob::io::base::format_hdf5_error() << std::endl;
-      return;
-    }
-  }
-  delete p;
-}
-
-static boost::shared_ptr<hid_t> open_file(const boost::filesystem::path& path,
-    unsigned int flags, boost::shared_ptr<hid_t>& fcpl) {
-
-  boost::shared_ptr<hid_t> retval(new hid_t(-1), std::ptr_fun(delete_h5file));
-
-  if (!boost::filesystem::exists(path) && flags == H5F_ACC_RDONLY) {
-    //file was opened for reading, but does not exist... Raise
-    boost::format m("cannot open file `%s'");
-    m % path.string();
-    throw std::runtime_error(m.str());
-  }
-
-  if (boost::filesystem::exists(path) && flags != H5F_ACC_TRUNC) { //open
-    *retval = H5Fopen(path.string().c_str(), flags, H5P_DEFAULT);
-    if (*retval < 0) {
-      boost::format m("call to HDF5 C-function H5Fopen() returned error %d on file '%s'. HDF5 error statck follows:\n%s");
-      m % *retval % path.string().c_str() % bob::io::base::format_hdf5_error();
-      throw std::runtime_error(m.str());
-    }
-    //replaces the file create list properties with the one from the file
-    fcpl = boost::shared_ptr<hid_t>(new hid_t(-1), std::ptr_fun(delete_h5p));
-    *fcpl = H5Fget_create_plist(*retval);
-    if (*fcpl < 0) {
-      boost::format m("call to HDF5 C-function H5Fget_create_list() returned error %d on file '%s'. HDF5 error statck follows:\n%s");
-      m % *fcpl % path.string().c_str() % bob::io::base::format_hdf5_error();
-      throw std::runtime_error(m.str());
-    }
-  }
-  else { //file needs to be created or truncated (can set user block)
-    *retval = H5Fcreate(path.string().c_str(), H5F_ACC_TRUNC,
-        *fcpl, H5P_DEFAULT);
-    if (*retval < 0) {
-      boost::format m("call to HDF5 C-function H5Fcreate() returned error %d on file '%s'. HDF5 error statck follows:\n%s");
-      m % *retval % path.string().c_str() % bob::io::base::format_hdf5_error();
-      throw std::runtime_error(m.str());
-    }
-  }
-  return retval;
-}
-
-static boost::shared_ptr<hid_t> create_fcpl(hsize_t userblock_size) {
-  if (!userblock_size) return boost::make_shared<hid_t>(H5P_DEFAULT);
-  //otherwise we have to go through the settings
-  boost::shared_ptr<hid_t> retval(new hid_t(-1), std::ptr_fun(delete_h5p));
-  *retval = H5Pcreate(H5P_FILE_CREATE);
-  if (*retval < 0) {
-    boost::format m("call to HDF5 C-function H5Pcreate() returned error %d. HDF5 error statck follows:\n%s");
-    m % *retval % bob::io::base::format_hdf5_error();
-    throw std::runtime_error(m.str());
-  }
-  herr_t err = H5Pset_userblock(*retval, userblock_size);
-  if (err < 0) {
-    boost::format m("call to HDF5 C-function H5Pset_userblock() returned error %d. HDF5 error statck follows:\n%s");
-    m % err % bob::io::base::format_hdf5_error();
-    throw std::runtime_error(m.str());
-  }
-  return retval;
-}
-
-bob::io::base::detail::hdf5::File::File(const boost::filesystem::path& path, unsigned int flags,
-    size_t userblock_size):
-  m_path(path),
-  m_flags(flags),
-  m_fcpl(create_fcpl(userblock_size)),
-  m_id(open_file(m_path, m_flags, m_fcpl))
-{
-}
-
-bob::io::base::detail::hdf5::File::~File() {
-}
-
-boost::shared_ptr<bob::io::base::detail::hdf5::RootGroup> bob::io::base::detail::hdf5::File::root() {
-  if (!m_root) {
-    m_root = boost::make_shared<bob::io::base::detail::hdf5::RootGroup>(shared_from_this());
-    m_root->open_recursively();
-  }
-  return m_root;
-}
-
-void bob::io::base::detail::hdf5::File::reset() {
-  m_root.reset();
-}
-
-void bob::io::base::detail::hdf5::File::flush() {
-  herr_t err = H5Fflush(*m_id, H5F_SCOPE_GLOBAL);
-  if (err < 0){
-    std::runtime_error("H5Fflush returned with an error code.");
-  }
-}
-
-bool bob::io::base::detail::hdf5::File::writable() const {
-  return (m_flags != H5F_ACC_RDONLY);
-}
-
-size_t bob::io::base::detail::hdf5::File::userblock_size() const {
-  hsize_t retval;
-  herr_t err = H5Pget_userblock(*m_fcpl, &retval);
-  if (err < 0) {
-    boost::format m("Call to HDF5 C-function H5Pget_create_plist() returned error %d. HDF5 error statck follows:\n%s");
-    m % err % bob::io::base::format_hdf5_error();
-    throw std::runtime_error(m.str());
-  }
-  return retval;
-}
-
-void bob::io::base::detail::hdf5::File::get_userblock(std::string& data) const {
-  //TODO
-}
-
-void bob::io::base::detail::hdf5::File::set_userblock(const std::string& data) {
-  //TODO
-}
diff --git a/bob/io/base/cpp/array.cpp b/bob/io/base/cpp/array.cpp
deleted file mode 100644
index 2ffc94d77a13adec893f99fa8b052a55c45554ff..0000000000000000000000000000000000000000
--- a/bob/io/base/cpp/array.cpp
+++ /dev/null
@@ -1,134 +0,0 @@
-/**
- * @date Tue Nov 8 15:34:31 2011 +0100
- * @author Andre Anjos <andre.anjos@idiap.ch>
- *
- * @brief Some buffer stuff
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#include <boost/format.hpp>
-#include <bob.io.base/array.h>
-
-bob::io::base::array::typeinfo::typeinfo():
-  dtype(bob::io::base::array::t_unknown),
-  nd(0)
-{
-}
-
-bob::io::base::array::typeinfo::typeinfo(const bob::io::base::array::typeinfo& other):
-  dtype(other.dtype)
-{
-  set_shape(other.nd, other.shape);
-}
-
-bob::io::base::array::typeinfo& bob::io::base::array::typeinfo::operator= (const bob::io::base::array::typeinfo& other) {
-  dtype = other.dtype;
-  set_shape(other.nd, other.shape);
-  return *this;
-}
-
-void bob::io::base::array::typeinfo::reset() {
-  dtype = bob::io::base::array::t_unknown;
-  nd = 0;
-}
-
-bool bob::io::base::array::typeinfo::is_valid() const {
-  return (dtype != bob::io::base::array::t_unknown) && (nd > 0) && (nd <= (BOB_MAX_DIM+1)) && has_valid_shape();
-}
-
-void bob::io::base::array::typeinfo::update_strides() {
-  switch (nd) {
-    case 0:
-      return;
-    case 1:
-      stride[0] = 1;
-      return;
-    case 2:
-      stride[1] = 1;
-      stride[0] = shape[1];
-      return;
-    case 3:
-      stride[2] = 1;
-      stride[1] = shape[2];
-      stride[0] = shape[1]*shape[2];
-      return;
-    case 4:
-      stride[3] = 1;
-      stride[2] = shape[3];
-      stride[1] = shape[2]*shape[3];
-      stride[0] = shape[1]*shape[2]*shape[3];
-      return;
-    case 5:
-      stride[4] = 1;
-      stride[3] = shape[4];
-      stride[2] = shape[3]*shape[4];
-      stride[1] = shape[2]*shape[3]*shape[4];
-      stride[0] = shape[1]*shape[2]*shape[3]*shape[4];
-      return;
-    default:
-      break;
-  }
-  throw std::runtime_error("unsupported number of dimensions");
-}
-
-size_t bob::io::base::array::typeinfo::size() const {
-  size_t retval = 1;
-  for (size_t k=0; k<nd; ++k) retval *= shape[k];
-  return retval;
-}
-
-size_t bob::io::base::array::typeinfo::buffer_size() const {
-  return size()*bob::io::base::array::getElementSize(dtype);
-}
-
-static bool same_shape(size_t nd, const size_t* s1, const size_t* s2) {
-  for (size_t k=0; k<nd; ++k) if (s1[k] != s2[k]) return false;
-  return true;
-}
-
-bool bob::io::base::array::typeinfo::is_compatible(const bob::io::base::array::typeinfo& other) const {
-  return (dtype == other.dtype) && (nd == other.nd) && same_shape(nd, shape, other.shape);
-}
-
-std::string bob::io::base::array::typeinfo::str() const {
-  boost::format s("dtype: %s (%d); shape: [%s]; size: %d bytes");
-  size_t sz = 0;
-  size_t buf_sz = 0;
-  if (dtype != bob::io::base::array::t_unknown) {
-    //otherwise it throws
-    sz = item_size();
-    buf_sz = buffer_size();
-  }
-  s % item_str() % sz;
-  switch (nd) {
-    case 0:
-      s % "";
-      break;
-    case 1:
-      s % (boost::format("%d") % shape[0]).str();
-      break;
-    case 2:
-      s % (boost::format("%d,%d") % shape[0] % shape[1]).str();
-      break;
-    case 3:
-      s % (boost::format("%d,%d,%d") % shape[0] % shape[1] % shape[2]).str();
-      break;
-    case 4:
-      s % (boost::format("%d,%d,%d,%d") % shape[0] % shape[1] % shape[2] % shape[3]).str();
-      break;
-    default:
-      s % ">4 dimensions?";
-      break;
-  }
-  s % buf_sz;
-  return s.str();
-}
-
-void bob::io::base::array::typeinfo::reset_shape() {
-  shape[0] = 0;
-}
-
-bool bob::io::base::array::typeinfo::has_valid_shape() const {
-  return shape[0] != 0;
-}
diff --git a/bob/io/base/cpp/array_type.cpp b/bob/io/base/cpp/array_type.cpp
deleted file mode 100644
index d42368e9175199572724f337ba5623d6a8a76a71..0000000000000000000000000000000000000000
--- a/bob/io/base/cpp/array_type.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/**
- * @date Sat Apr 9 18:10:10 2011 +0200
- * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch>
- *
- * @brief Some type-related array utilities
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#include <bob.io.base/array_type.h>
-#include <boost/format.hpp>
-
-static const char* t_bool_string = "bool";
-static const char* t_int8_string = "int8";
-static const char* t_int16_string = "int16";
-static const char* t_int32_string = "int32";
-static const char* t_int64_string = "int64";
-static const char* t_uint8_string = "uint8";
-static const char* t_uint16_string = "uint16";
-static const char* t_uint32_string = "uint32";
-static const char* t_uint64_string = "uint64";
-static const char* t_float32_string = "float32";
-static const char* t_float64_string = "float64";
-static const char* t_float128_string = "float128";
-static const char* t_complex64_string = "complex64";
-static const char* t_complex128_string = "complex128";
-static const char* t_complex256_string = "complex256";
-static const char* t_unknown_string = "unknown";
-
-size_t bob::io::base::array::getElementSize(ElementType t) {
-  switch(t) {
-    case bob::io::base::array::t_bool:
-      return sizeof(bool);
-    case bob::io::base::array::t_int8:
-      return sizeof(int8_t);
-    case bob::io::base::array::t_int16:
-      return sizeof(int16_t);
-    case bob::io::base::array::t_int32:
-      return sizeof(int32_t);
-    case bob::io::base::array::t_int64:
-      return sizeof(int64_t);
-    case bob::io::base::array::t_uint8:
-      return sizeof(uint8_t);
-    case bob::io::base::array::t_uint16:
-      return sizeof(uint16_t);
-    case bob::io::base::array::t_uint32:
-      return sizeof(uint32_t);
-    case bob::io::base::array::t_uint64:
-      return sizeof(uint64_t);
-    case bob::io::base::array::t_float32:
-      return sizeof(float);
-    case bob::io::base::array::t_float64:
-      return sizeof(double);
-    case bob::io::base::array::t_float128:
-      return sizeof(long double);
-    case bob::io::base::array::t_complex64:
-      return sizeof(std::complex<float>);
-    case bob::io::base::array::t_complex128:
-      return sizeof(std::complex<double>);
-    case bob::io::base::array::t_complex256:
-      return sizeof(std::complex<long double>);
-    default:
-      {
-        boost::format m("unsupported element type (%d)");
-        m % (int)t;
-        throw std::runtime_error(m.str());
-      }
-  }
-}
-
-const char* bob::io::base::array::stringize(ElementType t) {
-  switch(t) {
-    case bob::io::base::array::t_bool:
-      return t_bool_string;
-    case bob::io::base::array::t_int8:
-      return t_int8_string;
-    case bob::io::base::array::t_int16:
-      return t_int16_string;
-    case bob::io::base::array::t_int32:
-      return t_int32_string;
-    case bob::io::base::array::t_int64:
-      return t_int64_string;
-    case bob::io::base::array::t_uint8:
-      return t_uint8_string;
-    case bob::io::base::array::t_uint16:
-      return t_uint16_string;
-    case bob::io::base::array::t_uint32:
-      return t_uint32_string;
-    case bob::io::base::array::t_uint64:
-      return t_uint64_string;
-    case bob::io::base::array::t_float32:
-      return t_float32_string;
-    case bob::io::base::array::t_float64:
-      return t_float64_string;
-    case bob::io::base::array::t_float128:
-      return t_float128_string;
-    case bob::io::base::array::t_complex64:
-      return t_complex64_string;
-    case bob::io::base::array::t_complex128:
-      return t_complex128_string;
-    case bob::io::base::array::t_complex256:
-      return t_complex256_string;
-    default:
-      return t_unknown_string;
-  }
-}
-
-bob::io::base::array::ElementType bob::io::base::array::unstringize(const char* s) {
-  std::string sc(s);
-  if (sc == t_bool_string) return bob::io::base::array::t_bool;
-  if (sc == t_int8_string) return bob::io::base::array::t_int8;
-  if (sc == t_int16_string) return bob::io::base::array::t_int16;
-  if (sc == t_int32_string) return bob::io::base::array::t_int32;
-  if (sc == t_int64_string) return bob::io::base::array::t_int64;
-  if (sc == t_uint8_string) return bob::io::base::array::t_uint8;
-  if (sc == t_uint16_string) return bob::io::base::array::t_uint16;
-  if (sc == t_uint32_string) return bob::io::base::array::t_uint32;
-  if (sc == t_uint64_string) return bob::io::base::array::t_uint64;
-  if (sc == t_float32_string) return bob::io::base::array::t_float32;
-  if (sc == t_float64_string) return bob::io::base::array::t_float64;
-  if (sc == t_float128_string) return bob::io::base::array::t_float128;
-  if (sc == t_complex64_string) return bob::io::base::array::t_complex64;
-  if (sc == t_complex128_string) return bob::io::base::array::t_complex128;
-  if (sc == t_complex256_string) return bob::io::base::array::t_complex256;
-  return bob::io::base::array::t_unknown;
-}
diff --git a/bob/io/base/cpp/blitz_array.cpp b/bob/io/base/cpp/blitz_array.cpp
deleted file mode 100644
index 2bc723a71d4b2770207fb24732641e1e67a1948f..0000000000000000000000000000000000000000
--- a/bob/io/base/cpp/blitz_array.cpp
+++ /dev/null
@@ -1,166 +0,0 @@
-/**
- * @date Tue Nov 8 15:34:31 2011 +0100
- * @author Andre Anjos <andre.anjos@idiap.ch>
- *
- * @brief Implementation of non-templated methods of the blitz
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#include <stdexcept>
-
-#include <bob.io.base/blitz_array.h>
-
-bob::io::base::array::blitz_array::blitz_array(boost::shared_ptr<blitz_array> other) {
-  set(other);
-}
-
-bob::io::base::array::blitz_array::blitz_array(const blitz_array& other) {
-  set(other);
-}
-
-bob::io::base::array::blitz_array::blitz_array(boost::shared_ptr<interface> other) {
-  set(other);
-}
-
-bob::io::base::array::blitz_array::blitz_array(const interface& other) {
-  set(other);
-}
-
-bob::io::base::array::blitz_array::blitz_array(const typeinfo& info) {
-  set(info);
-}
-
-bob::io::base::array::blitz_array::blitz_array(void* data, const typeinfo& info):
-  m_type(info),
-  m_ptr(data),
-  m_is_blitz(false) {
-}
-
-bob::io::base::array::blitz_array::~blitz_array() {
-}
-
-void bob::io::base::array::blitz_array::set(boost::shared_ptr<blitz_array> other) {
-  m_type = other->m_type;
-  m_ptr = other->m_ptr;
-  m_is_blitz = other->m_is_blitz;
-  m_data = other->m_data;
-}
-
-void bob::io::base::array::blitz_array::set(const interface& other) {
-  set(other.type());
-  memcpy(m_ptr, other.ptr(), m_type.buffer_size());
-}
-
-void bob::io::base::array::blitz_array::set(boost::shared_ptr<interface> other) {
-  m_type = other->type();
-  m_ptr = other->ptr();
-  m_is_blitz = false;
-  m_data = other;
-}
-
-template <typename T>
-static boost::shared_ptr<void> make_array(size_t nd, const size_t* shape,
-    void*& ptr) {
-  switch(nd) {
-    case 1:
-      {
-        blitz::TinyVector<int,1> tv_shape;
-        for (size_t k=0; k<nd; ++k) tv_shape[k] = shape[k];
-        boost::shared_ptr<void> retval =
-          boost::make_shared<blitz::Array<T,1> >(tv_shape);
-        ptr = reinterpret_cast<void*>(boost::static_pointer_cast<blitz::Array<T,1> >(retval)->data());
-        return retval;
-      }
-    case 2:
-      {
-        blitz::TinyVector<int,2> tv_shape;
-        for (size_t k=0; k<nd; ++k) tv_shape[k] = shape[k];
-        boost::shared_ptr<void> retval =
-          boost::make_shared<blitz::Array<T,2> >(tv_shape);
-        ptr = reinterpret_cast<void*>(boost::static_pointer_cast<blitz::Array<T,2> >(retval)->data());
-        return retval;
-      }
-    case 3:
-      {
-        blitz::TinyVector<int,3> tv_shape;
-        for (size_t k=0; k<nd; ++k) tv_shape[k] = shape[k];
-        boost::shared_ptr<void> retval =
-          boost::make_shared<blitz::Array<T,3> >(tv_shape);
-        ptr = reinterpret_cast<void*>(boost::static_pointer_cast<blitz::Array<T,3> >(retval)->data());
-        return retval;
-      }
-    case 4:
-      {
-        blitz::TinyVector<int,4> tv_shape;
-        for (size_t k=0; k<nd; ++k) tv_shape[k] = shape[k];
-        boost::shared_ptr<void> retval =
-          boost::make_shared<blitz::Array<T,4> >(tv_shape);
-        ptr = reinterpret_cast<void*>(boost::static_pointer_cast<blitz::Array<T,4> >(retval)->data());
-        return retval;
-      }
-    default:
-      break;
-  }
-  throw std::runtime_error("unsupported number of dimensions -- debug me");
-}
-
-void bob::io::base::array::blitz_array::set (const bob::io::base::array::typeinfo& req) {
-  if (m_type.is_compatible(req)) return; ///< double-check requirement first!
-
-  //ok, have to go through reallocation
-  m_type = req;
-  m_is_blitz = true;
-  switch (m_type.dtype) {
-    case bob::io::base::array::t_bool:
-      m_data = make_array<bool>(req.nd, req.shape, m_ptr);
-      return;
-    case bob::io::base::array::t_int8:
-      m_data = make_array<int8_t>(req.nd, req.shape, m_ptr);
-      return;
-    case bob::io::base::array::t_int16:
-      m_data = make_array<int16_t>(req.nd, req.shape, m_ptr);
-      return;
-    case bob::io::base::array::t_int32:
-      m_data = make_array<int32_t>(req.nd, req.shape, m_ptr);
-      return;
-    case bob::io::base::array::t_int64:
-      m_data = make_array<int64_t>(req.nd, req.shape, m_ptr);
-      return;
-    case bob::io::base::array::t_uint8:
-      m_data = make_array<uint8_t>(req.nd, req.shape, m_ptr);
-      return;
-    case bob::io::base::array::t_uint16:
-      m_data = make_array<uint16_t>(req.nd, req.shape, m_ptr);
-      return;
-    case bob::io::base::array::t_uint32:
-      m_data = make_array<uint32_t>(req.nd, req.shape, m_ptr);
-      return;
-    case bob::io::base::array::t_uint64:
-      m_data = make_array<uint64_t>(req.nd, req.shape, m_ptr);
-      return;
-    case bob::io::base::array::t_float32:
-      m_data = make_array<float>(req.nd, req.shape, m_ptr);
-      return;
-    case bob::io::base::array::t_float64:
-      m_data = make_array<double>(req.nd, req.shape, m_ptr);
-      return;
-    case bob::io::base::array::t_float128:
-      m_data = make_array<long double>(req.nd, req.shape, m_ptr);
-      return;
-    case bob::io::base::array::t_complex64:
-      m_data = make_array<std::complex<float> >(req.nd, req.shape, m_ptr);
-      return;
-    case bob::io::base::array::t_complex128:
-      m_data = make_array<std::complex<double> >(req.nd, req.shape, m_ptr);
-      return;
-    case bob::io::base::array::t_complex256:
-      m_data = make_array<std::complex<long double> >(req.nd, req.shape, m_ptr);
-      return;
-    default:
-      break;
-  }
-
-  //if we get to this point, there is nothing much we can do...
-  throw std::runtime_error("invalid data type on blitz array reset -- debug me");
-}
diff --git a/bob/io/base/cpp/reorder.cpp b/bob/io/base/cpp/reorder.cpp
deleted file mode 100644
index cda5ab335a47cb9a05dcf2e14357b91f6311cdfd..0000000000000000000000000000000000000000
--- a/bob/io/base/cpp/reorder.cpp
+++ /dev/null
@@ -1,288 +0,0 @@
-/**
- * @date Tue Nov 22 11:24:44 2011 +0100
- * @author Andre Anjos <andre.anjos@idiap.ch>
- *
- * @brief Implementation of row-major/column-major reordering
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#include <boost/format.hpp>
-#include <cstring> //for memcpy
-
-#include <bob.io.base/reorder.h>
-
-void bob::io::base::rc2d(size_t& row, size_t& col, const size_t i, const size_t j,
-    const size_t* shape) {
-  row = (i * shape[1]) + j;
-  col = (j * shape[0]) + i;
-}
-
-void bob::io::base::rc3d(size_t& row, size_t& col, const size_t i, const size_t j,
-    const size_t k, const size_t* shape) {
-  row = ( (i * shape[1]) + j ) * shape[2] + k;
-  col = ( (k * shape[1]) + j ) * shape[0] + i;
-}
-
-void bob::io::base::rc4d(size_t& row, size_t& col, const size_t i, const size_t j,
-    const size_t k, const size_t l, const size_t* shape) {
-  row = ( ( i * shape[1] + j ) * shape[2] + k ) * shape[3] + l;
-  col = ( ( l * shape[2] + k ) * shape[1] + j ) * shape[0] + i;
-}
-
-void bob::io::base::row_to_col_order(const void* src_, void* dst_,
-    const bob::io::base::array::typeinfo& info) {
-
-  size_t dsize = info.item_size();
-
-  //cast to byte type so we can manipulate the pointers...
-  const uint8_t* src = static_cast<const uint8_t*>(src_);
-  uint8_t* dst = static_cast<uint8_t*>(dst_);
-
-  switch(info.nd) {
-
-    case 1:
-      std::memcpy(dst, src, info.buffer_size());
-      break;
-
-    case 2:
-      for (size_t i=0; i<info.shape[0]; ++i)
-        for (size_t j=0; j<info.shape[1]; ++j) {
-          size_t row_major, col_major;
-          bob::io::base::rc2d(row_major, col_major, i, j, info.shape);
-          row_major *= dsize;
-          col_major *= dsize;
-          std::memcpy(&dst[col_major], &src[row_major], dsize);
-        }
-      break;
-
-    case 3:
-      for (size_t i=0; i<info.shape[0]; ++i)
-        for (size_t j=0; j<info.shape[1]; ++j)
-          for (size_t k=0; k<info.shape[2]; ++k) {
-            size_t row_major, col_major;
-            bob::io::base::rc3d(row_major, col_major, i, j, k, info.shape);
-            row_major *= dsize;
-            col_major *= dsize;
-            std::memcpy(&dst[col_major], &src[row_major], dsize);
-          }
-      break;
-
-    case 4:
-      for (size_t i=0; i<info.shape[0]; ++i)
-        for (size_t j=0; j<info.shape[1]; ++j)
-          for (size_t k=0; k<info.shape[2]; ++k)
-            for (size_t l=0; l<info.shape[3]; ++l) {
-              size_t row_major, col_major;
-              bob::io::base::rc4d(row_major, col_major, i, j, k, l, info.shape);
-              row_major *= dsize;
-              col_major *= dsize;
-              std::memcpy(&dst[col_major], &src[row_major], dsize);
-            }
-      break;
-
-    default:
-      {
-        boost::format m("row_to_col_order() can only flip arrays with up to %u dimensions - you passed one with %u dimensions");
-        m % BOB_MAX_DIM % info.nd;
-        throw std::runtime_error(m.str());
-      }
-  }
-}
-
-void bob::io::base::col_to_row_order(const void* src_, void* dst_,
-    const bob::io::base::array::typeinfo& info) {
-
-  size_t dsize = info.item_size();
-
-  //cast to byte type so we can manipulate the pointers...
-  const uint8_t* src = static_cast<const uint8_t*>(src_);
-  uint8_t* dst = static_cast<uint8_t*>(dst_);
-
-  switch(info.nd) {
-
-    case 1:
-      std::memcpy(dst, src, info.buffer_size());
-      break;
-
-    case 2:
-      for (size_t i=0; i<info.shape[0]; ++i)
-        for (size_t j=0; j<info.shape[1]; ++j) {
-          size_t row_major, col_major;
-          bob::io::base::rc2d(row_major, col_major, i, j, info.shape);
-          row_major *= dsize;
-          col_major *= dsize;
-          std::memcpy(&dst[row_major], &src[col_major], dsize);
-        }
-      break;
-
-    case 3:
-      for (size_t i=0; i<info.shape[0]; ++i)
-        for (size_t j=0; j<info.shape[1]; ++j)
-          for (size_t k=0; k<info.shape[2]; ++k) {
-            size_t row_major, col_major;
-            bob::io::base::rc3d(row_major, col_major, i, j, k, info.shape);
-            row_major *= dsize;
-            col_major *= dsize;
-            std::memcpy(&dst[row_major], &src[col_major], dsize);
-          }
-      break;
-
-    case 4:
-      for (size_t i=0; i<info.shape[0]; ++i)
-        for (size_t j=0; j<info.shape[1]; ++j)
-          for (size_t k=0; k<info.shape[2]; ++k)
-            for (size_t l=0; l<info.shape[3]; ++l) {
-              size_t row_major, col_major;
-              bob::io::base::rc4d(row_major, col_major, i, j, k, l, info.shape);
-              row_major *= dsize;
-              col_major *= dsize;
-              std::memcpy(&dst[row_major], &src[col_major], dsize);
-            }
-      break;
-
-    default:
-      {
-        boost::format m("col_to_row_order() can only flip arrays with up to %u dimensions - you passed one with %u dimensions");
-        m % BOB_MAX_DIM % info.nd;
-        throw std::runtime_error(m.str());
-      }
-  }
-}
-
-void bob::io::base::row_to_col_order_complex(const void* src_, void* dst_re_,
-    void* dst_im_, const bob::io::base::array::typeinfo& info) {
-
-  size_t dsize = info.item_size();
-  size_t dsize2 = dsize/2; ///< size of each complex component (real, imaginary)
-
-  //cast to byte type so we can manipulate the pointers...
-  const uint8_t* src = static_cast<const uint8_t*>(src_);
-  uint8_t* dst_re = static_cast<uint8_t*>(dst_re_);
-  uint8_t* dst_im = static_cast<uint8_t*>(dst_im_);
-
-  switch(info.nd) {
-
-    case 1:
-      for (size_t i=0; i<info.shape[0]; ++i) {
-        std::memcpy(&dst_re[dsize2*i], &src[dsize*i]       , dsize2);
-        std::memcpy(&dst_im[dsize2*i], &src[dsize*i]+dsize2, dsize2);
-      }
-      break;
-
-    case 2:
-      for (size_t i=0; i<info.shape[0]; ++i)
-        for (size_t j=0; j<info.shape[1]; ++j) {
-          size_t row_major, col_major;
-          bob::io::base::rc2d(row_major, col_major, i, j, info.shape);
-          row_major *= dsize;
-          col_major *= dsize2;
-          std::memcpy(&dst_re[col_major], &src[row_major]       , dsize2);
-          std::memcpy(&dst_im[col_major], &src[row_major]+dsize2, dsize2);
-        }
-      break;
-
-    case 3:
-      for (size_t i=0; i<info.shape[0]; ++i)
-        for (size_t j=0; j<info.shape[1]; ++j)
-          for (size_t k=0; k<info.shape[2]; ++k) {
-            size_t row_major, col_major;
-            bob::io::base::rc3d(row_major, col_major, i, j, k, info.shape);
-            row_major *= dsize;
-            col_major *= dsize2;
-            std::memcpy(&dst_re[col_major], &src[row_major]       , dsize2);
-            std::memcpy(&dst_im[col_major], &src[row_major]+dsize2, dsize2);
-          }
-      break;
-
-    case 4:
-      for (size_t i=0; i<info.shape[0]; ++i)
-        for (size_t j=0; j<info.shape[1]; ++j)
-          for (size_t k=0; k<info.shape[2]; ++k)
-            for (size_t l=0; l<info.shape[3]; ++l) {
-              size_t row_major, col_major;
-              bob::io::base::rc4d(row_major, col_major, i, j, k, l, info.shape);
-              row_major *= dsize;
-              col_major *= dsize2;
-              std::memcpy(&dst_re[col_major], &src[row_major]       , dsize2);
-              std::memcpy(&dst_im[col_major], &src[row_major]+dsize2, dsize2);
-            }
-      break;
-
-    default:
-      {
-        boost::format m("row_to_col_order_complex() can only flip arrays with up to %u dimensions - you passed one with %u dimensions");
-        m % BOB_MAX_DIM % info.nd;
-        throw std::runtime_error(m.str());
-      }
-  }
-}
-
-void bob::io::base::col_to_row_order_complex(const void* src_re_, const void* src_im_,
-    void* dst_, const bob::io::base::array::typeinfo& info) {
-
-  size_t dsize = info.item_size();
-  size_t dsize2 = dsize/2; ///< size of each complex component (real, imaginary)
-
-  //cast to byte type so we can manipulate the pointers...
-  const uint8_t* src_re = static_cast<const uint8_t*>(src_re_);
-  const uint8_t* src_im = static_cast<const uint8_t*>(src_im_);
-  uint8_t* dst = static_cast<uint8_t*>(dst_);
-
-  switch(info.nd) {
-
-    case 1:
-      for (size_t i=0; i<info.shape[0]; ++i) {
-        std::memcpy(&dst[dsize*i]       , &src_re[dsize2*i], dsize2);
-        std::memcpy(&dst[dsize*i]+dsize2, &src_im[dsize2*i], dsize2);
-      }
-      break;
-
-    case 2:
-      for (size_t i=0; i<info.shape[0]; ++i)
-        for (size_t j=0; j<info.shape[1]; ++j) {
-          size_t row_major, col_major;
-          bob::io::base::rc2d(row_major, col_major, i, j, info.shape);
-          row_major *= dsize;
-          col_major *= dsize2;
-          std::memcpy(&dst[row_major],        &src_re[col_major], dsize2);
-          std::memcpy(&dst[row_major]+dsize2, &src_im[col_major], dsize2);
-        }
-      break;
-
-    case 3:
-      for (size_t i=0; i<info.shape[0]; ++i)
-        for (size_t j=0; j<info.shape[1]; ++j)
-          for (size_t k=0; k<info.shape[2]; ++k) {
-            size_t row_major, col_major;
-            bob::io::base::rc3d(row_major, col_major, i, j, k, info.shape);
-            row_major *= dsize;
-            col_major *= dsize2;
-            std::memcpy(&dst[row_major]       , &src_re[col_major], dsize2);
-            std::memcpy(&dst[row_major]+dsize2, &src_im[col_major], dsize2);
-          }
-      break;
-
-    case 4:
-      for (size_t i=0; i<info.shape[0]; ++i)
-        for (size_t j=0; j<info.shape[1]; ++j)
-          for (size_t k=0; k<info.shape[2]; ++k)
-            for (size_t l=0; l<info.shape[3]; ++l) {
-              size_t row_major, col_major;
-              bob::io::base::rc4d(row_major, col_major, i, j, k, l, info.shape);
-              row_major *= dsize;
-              col_major *= dsize2;
-              std::memcpy(&dst[row_major]       , &src_re[col_major], dsize2);
-              std::memcpy(&dst[row_major]+dsize2, &src_im[col_major], dsize2);
-            }
-      break;
-
-    default:
-      {
-        boost::format m("col_to_row_order_complex() can only flip arrays with up to %u dimensions - you passed one with %u dimensions");
-        m % BOB_MAX_DIM % info.nd;
-        throw std::runtime_error(m.str());
-      }
-  }
-}
-
diff --git a/bob/io/base/cpp/utils.cpp b/bob/io/base/cpp/utils.cpp
deleted file mode 100644
index 3467b997726137f619d1fb4911d5df8b28caaadc..0000000000000000000000000000000000000000
--- a/bob/io/base/cpp/utils.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-/**
- * @author Andre Anjos <andre.anjos@idiap.ch>
- * @date Wed  3 Oct 08:36:48 2012
- *
- * @brief Implementation of some compile-time I/O utitlites
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#include <bob.io.base/CodecRegistry.h>
-#include <bob.io.base/utils.h>
-
-boost::shared_ptr<bob::io::base::File> bob::io::base::open (const char* filename,
-    char mode, const char* pretend_extension) {
-  boost::shared_ptr<bob::io::base::CodecRegistry> instance = bob::io::base::CodecRegistry::instance();
-  return instance->findByExtension(pretend_extension)(filename, mode);
-}
-
-boost::shared_ptr<bob::io::base::File> bob::io::base::open (const char* filename, char mode) {
-  boost::shared_ptr<bob::io::base::CodecRegistry> instance = bob::io::base::CodecRegistry::instance();
-  return instance->findByFilenameExtension(filename)(filename, mode);
-}
-
-bob::io::base::array::typeinfo bob::io::base::peek (const char* filename) {
-  return open(filename, 'r')->type();
-}
-
-bob::io::base::array::typeinfo bob::io::base::peek_all (const char* filename) {
-  return open(filename, 'r')->type_all();
-}
diff --git a/bob/io/base/file.cpp b/bob/io/base/file.cpp
deleted file mode 100644
index fc2622a7efb5f595b8f0fdf33094b4e4b285fe36..0000000000000000000000000000000000000000
--- a/bob/io/base/file.cpp
+++ /dev/null
@@ -1,603 +0,0 @@
-/**
- * @author Andre Anjos <andre.anjos@idiap.ch>
- * @date Tue  5 Nov 11:16:09 2013
- *
- * @brief Bindings to bob::io::base::File
- */
-
-#define BOB_IO_BASE_MODULE
-#include "bobskin.h"
-#include <bob.io.base/api.h>
-#include <numpy/arrayobject.h>
-#include <bob.blitz/capi.h>
-#include <bob.blitz/cleanup.h>
-#include <bob.extension/documentation.h>
-#include <stdexcept>
-
-#include <bob.io.base/CodecRegistry.h>
-#include <bob.io.base/utils.h>
-
-/* Creates an exception message including the name of the given file, if possible */
-inline const std::string exception_message(PyBobIoFileObject* self, const std::string& name){
-  std::ostringstream str;
-  str << name << " (";
-  try{
-    str << "'" << self->f->filename() << "'";
-  } catch (...){
-    str << "<unkown>";
-  }
-  str << ")";
-  return  str.str();
-}
-
-static auto s_file = bob::extension::ClassDoc(
-  "File",
-  "Use this object to read and write data into files"
-)
-.add_constructor(
-  bob::extension::FunctionDoc(
-    "File",
-    "Opens a file for reading or writing",
-    "Normally, we read the file matching the extension to one of the available codecs installed with the present release of Bob. "
-    "If you set the ``pretend_extension`` parameter though, we will read the file as it had a given extension. "
-    "The value should start with a ``'.'``. "
-    "For example ``'.hdf5'``, to make the file be treated like an HDF5 file.",
-    true
-  )
-  .add_prototype("filename, [mode], [pretend_extension]", "")
-  .add_parameter("filename", "str", "The file path to the file you want to open")
-  .add_parameter("mode", "one of ('r', 'w', 'a')", "[Default: ``'r'``] A single character indicating if you'd like to ``'r'``\\ ead, ``'w'``\\ rite or ``'a'``\\ ppend into the file; if you choose ``'w'`` and the file already exists, it will be truncated")
-  .add_parameter("pretend_extension", "str", "[optional] An extension to use; see :py:func:`bob.io.base.extensions` for a list of (currently) supported extensions")
-);
-/* How to create a new PyBobIoFileObject */
-static PyObject* PyBobIoFile_New(PyTypeObject* type, PyObject*, PyObject*) {
-
-  /* Allocates the python object itself */
-  PyBobIoFileObject* self = (PyBobIoFileObject*)type->tp_alloc(type, 0);
-
-  self->f.reset();
-
-  return reinterpret_cast<PyObject*>(self);
-}
-
-static void PyBobIoFile_Delete (PyBobIoFileObject* o) {
-
-  o->f.reset();
-  Py_TYPE(o)->tp_free((PyObject*)o);
-
-}
-
-int PyBobIo_FilenameConverter (PyObject* o, const char** b) {
-#if PY_VERSION_HEX >= 0x03000000
-  if (PyUnicode_Check(o)) {
-    *b = PyUnicode_AsUTF8(o);
-  } else {
-    PyObject* temp = PyObject_Bytes(o);
-    if (!temp) return 0;
-    auto temp_ = make_safe(temp);
-    *b = PyBytes_AsString(temp);
-  }
-#else
-  if (PyUnicode_Check(o)) {
-    PyObject* temp = PyUnicode_AsEncodedString(o, Py_FileSystemDefaultEncoding, "strict");
-    if (!temp) return 0;
-    auto temp_ = make_safe(temp);
-    *b = PyString_AsString(temp);
-  } else {
-    *b = PyString_AsString(o);
-  }
-#endif
-  return b != 0;
-}
-
-/* The __init__(self) method */
-static int PyBobIoFile_init(PyBobIoFileObject* self, PyObject *args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static char** kwlist = s_file.kwlist();
-
-  const char* filename;
-  const char* pretend_extension = 0;
-
-#if PY_VERSION_HEX >= 0x03000000
-#  define MODE_CHAR "C"
-  int mode = 'r';
-#else
-#  define MODE_CHAR "c"
-  char mode = 'r';
-#endif
-
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|" MODE_CHAR "s", kwlist,
-        &PyBobIo_FilenameConverter, &filename, &mode, &pretend_extension)) return -1;
-
-#undef MODE_CHAR
-
-  if (mode != 'r' && mode != 'w' && mode != 'a') {
-    PyErr_Format(PyExc_ValueError, "file open mode string should have 1 element and be either 'r' (read), 'w' (write) or 'a' (append)");
-    return -1;
-  }
-
-  if (pretend_extension) {
-    self->f = bob::io::base::open(filename, mode, pretend_extension);
-  }
-  else {
-    self->f = bob::io::base::open(filename, mode);
-  }
-
-  return 0; ///< SUCCESS
-BOB_CATCH_MEMBER("constructor", -1);
-}
-
-static PyObject* PyBobIoFile_repr(PyBobIoFileObject* self) {
-  return PyString_FromFormat("%s(filename='%s', codec='%s')", Py_TYPE(self)->tp_name, self->f->filename(), self->f->name());
-}
-
-static auto s_filename = bob::extension::VariableDoc(
-  "filename",
-  "str",
-  "The path to the file being read/written"
-);
-static PyObject* PyBobIoFile_Filename(PyBobIoFileObject* self) {
-  return Py_BuildValue("s", self->f->filename());
-}
-
-static auto s_codec_name = bob::extension::VariableDoc(
-  "codec_name",
-  "str",
-  "Name of the File class implementation",
-  "This variable is available for compatibility reasons with the previous versions of this library."
-);
-static PyObject* PyBobIoFile_CodecName(PyBobIoFileObject* self) {
-  return Py_BuildValue("s", self->f->name());
-}
-
-
-static PyGetSetDef PyBobIoFile_getseters[] = {
-    {
-      s_filename.name(),
-      (getter)PyBobIoFile_Filename,
-      0,
-      s_filename.doc(),
-      0,
-    },
-    {
-      s_codec_name.name(),
-      (getter)PyBobIoFile_CodecName,
-      0,
-      s_codec_name.doc(),
-      0,
-    },
-    {0}  /* Sentinel */
-};
-
-static Py_ssize_t PyBobIoFile_len (PyBobIoFileObject* self) {
-  Py_ssize_t retval = self->f->size();
-  return retval;
-}
-
-int PyBobIo_AsTypenum (bob::io::base::array::ElementType type) {
-
-  switch(type) {
-    case bob::io::base::array::t_bool:
-      return NPY_BOOL;
-    case bob::io::base::array::t_int8:
-      return NPY_INT8;
-    case bob::io::base::array::t_int16:
-      return NPY_INT16;
-    case bob::io::base::array::t_int32:
-      return NPY_INT32;
-    case bob::io::base::array::t_int64:
-      return NPY_INT64;
-    case bob::io::base::array::t_uint8:
-      return NPY_UINT8;
-    case bob::io::base::array::t_uint16:
-      return NPY_UINT16;
-    case bob::io::base::array::t_uint32:
-      return NPY_UINT32;
-    case bob::io::base::array::t_uint64:
-      return NPY_UINT64;
-    case bob::io::base::array::t_float32:
-      return NPY_FLOAT32;
-    case bob::io::base::array::t_float64:
-      return NPY_FLOAT64;
-#ifdef NPY_FLOAT128
-    case bob::io::base::array::t_float128:
-      return NPY_FLOAT128;
-#endif
-    case bob::io::base::array::t_complex64:
-      return NPY_COMPLEX64;
-    case bob::io::base::array::t_complex128:
-      return NPY_COMPLEX128;
-#ifdef NPY_COMPLEX256
-    case bob::io::base::array::t_complex256:
-      return NPY_COMPLEX256;
-#endif
-    default:
-      PyErr_Format(PyExc_TypeError, "unsupported Bob/C++ element type (%s)", bob::io::base::array::stringize(type));
-  }
-
-  return NPY_NOTYPE;
-
-}
-
-static PyObject* PyBobIoFile_getIndex (PyBobIoFileObject* self, Py_ssize_t i) {
-  if (i < 0) i += self->f->size(); ///< adjust for negative indexing
-
-  if (i < 0 || (size_t)i >= self->f->size()) {
-    PyErr_Format(PyExc_IndexError, "file index out of range - `%s' only contains %" PY_FORMAT_SIZE_T "d object(s)", self->f->filename(), self->f->size());
-    return 0;
-  }
-
-  const bob::io::base::array::typeinfo& info = self->f->type();
-
-  npy_intp shape[NPY_MAXDIMS];
-  for (size_t k=0; k<info.nd; ++k) shape[k] = info.shape[k];
-
-  int type_num = PyBobIo_AsTypenum(info.dtype);
-  if (type_num == NPY_NOTYPE) return 0; ///< failure
-
-  PyObject* retval = PyArray_SimpleNew(info.nd, shape, type_num);
-  if (!retval) return 0;
-  auto retval_ = make_safe(retval);
-
-  bobskin skin((PyArrayObject*)retval, info.dtype);
-  self->f->read(skin, i);
-  return Py_BuildValue("O", retval);
-}
-
-static PyObject* PyBobIoFile_getSlice (PyBobIoFileObject* self, PySliceObject* slice) {
-
-  Py_ssize_t start, stop, step, slicelength;
-#if PY_VERSION_HEX < 0x03000000
-  if (PySlice_GetIndicesEx(slice,
-#else
-  if (PySlice_GetIndicesEx(reinterpret_cast<PyObject*>(slice),
-#endif
-        self->f->size(), &start, &stop, &step, &slicelength) < 0) return 0;
-
-  //creates the return array
-  const bob::io::base::array::typeinfo& info = self->f->type();
-
-  int type_num = PyBobIo_AsTypenum(info.dtype);
-  if (type_num == NPY_NOTYPE) return 0; ///< failure
-
-  if (slicelength <= 0) return PyArray_SimpleNew(0, 0, type_num);
-
-  npy_intp shape[NPY_MAXDIMS];
-  shape[0] = slicelength;
-  for (size_t k=0; k<info.nd; ++k) shape[k+1] = info.shape[k];
-
-  PyObject* retval = PyArray_SimpleNew(info.nd+1, shape, type_num);
-  if (!retval) return 0;
-  auto retval_ = make_safe(retval);
-
-  Py_ssize_t counter = 0;
-  for (auto i = start; (start<=stop)?i<stop:i>stop; i+=step) {
-
-    //get slice to fill
-    PyObject* islice = Py_BuildValue("n", counter++);
-    if (!islice) return 0;
-    auto islice_ = make_safe(islice);
-
-    PyObject* item = PyObject_GetItem(retval, islice);
-    if (!item) return 0;
-    auto item_ = make_safe(item);
-
-    bobskin skin((PyArrayObject*)item, info.dtype);
-    self->f->read(skin, i);
-  }
-
-  return Py_BuildValue("O", retval);
-}
-
-static PyObject* PyBobIoFile_getItem (PyBobIoFileObject* self, PyObject* item) {
-  if (PyIndex_Check(item)) {
-   Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
-   if (i == -1 && PyErr_Occurred()) return 0;
-   return PyBobIoFile_getIndex(self, i);
-  }
-  if (PySlice_Check(item)) {
-   return PyBobIoFile_getSlice(self, (PySliceObject*)item);
-  }
-  else {
-   PyErr_Format(PyExc_TypeError, "File indices must be integers, not %s", Py_TYPE(item)->tp_name);
-   return 0;
-  }
-}
-
-static PyMappingMethods PyBobIoFile_Mapping = {
-    (lenfunc)PyBobIoFile_len, //mp_length
-    (binaryfunc)PyBobIoFile_getItem, //mp_subscript
-    0 /* (objobjargproc)PyBobIoFile_SetItem //mp_ass_subscript */
-};
-
-
-static auto s_read = bob::extension::FunctionDoc(
-  "read",
-  "Reads a specific object in the file, or the whole file",
-  "This method reads data from the file. "
-  "If you specified an ``index``, it reads just the object indicated by the index, as you would do using the ``[]`` operator. "
-  "If the ``index`` is not specified, reads the whole contents of the file into a :py:class:`numpy.ndarray`.",
-  true
-)
-.add_prototype("[index]", "data")
-.add_parameter("index", "int", "[optional] The index to the object one wishes to retrieve from the file; negative indexing is supported; if not given, implies retrieval of the whole file contents.")
-.add_return("data", ":py:class:`numpy.ndarray`", "The contents of the file, as array")
-;
-static PyObject* PyBobIoFile_read(PyBobIoFileObject* self, PyObject *args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static char** kwlist = s_read.kwlist();
-
-  Py_ssize_t i = PY_SSIZE_T_MIN;
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|n", kwlist, &i)) return 0;
-
-  if (i != PY_SSIZE_T_MIN) {
-
-    // reads a specific object inside the file
-
-    if (i < 0) i += self->f->size();
-
-    if (i < 0 || (size_t)i >= self->f->size()) {
-      PyErr_Format(PyExc_IndexError, "file index out of range - `%s' only contains %" PY_FORMAT_SIZE_T "d object(s)", self->f->filename(), self->f->size());
-      return 0;
-    }
-
-    return PyBobIoFile_getIndex(self, i);
-
-  }
-
-  // reads the whole file in a single shot
-
-  const bob::io::base::array::typeinfo& info = self->f->type_all();
-
-  npy_intp shape[NPY_MAXDIMS];
-  for (size_t k=0; k<info.nd; ++k) shape[k] = info.shape[k];
-
-  int type_num = PyBobIo_AsTypenum(info.dtype);
-  if (type_num == NPY_NOTYPE) return 0; ///< failure
-
-  PyObject* retval = PyArray_SimpleNew(info.nd, shape, type_num);
-  if (!retval) return 0;
-  auto retval_ = make_safe(retval);
-
-  bobskin skin((PyArrayObject*)retval, info.dtype);
-  self->f->read_all(skin);
-
-  return Py_BuildValue("O", retval);
-BOB_CATCH_MEMBER(exception_message(self, s_read.name()).c_str(), 0)
-}
-
-
-static auto s_write = bob::extension::FunctionDoc(
-  "write",
-  "Writes the contents of an object to the file",
-  "This method writes data to the file. "
-  "It acts like the given array is the only piece of data that will ever be written to such a file. "
-  "No more data appending may happen after a call to this method.",
-  true
-)
-.add_prototype("data")
-.add_parameter("data", "array_like", "The array to be written into the file; it can be a :py:class:`numpy.ndarray`, a :py:class:`bob.blitz.array` or any other object which can be converted to either of them")
-;
-static PyObject* PyBobIoFile_write(PyBobIoFileObject* self, PyObject *args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static char** kwlist = s_write.kwlist();
-
-  PyBlitzArrayObject* bz = 0;
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&", kwlist, &PyBlitzArray_Converter, &bz)) return 0;
-
-  auto bz_ = make_safe(bz);
-
-  bobskin skin(bz);
-  self->f->write(skin);
-
-  Py_RETURN_NONE;
-BOB_CATCH_MEMBER(exception_message(self, s_write.name()).c_str(), 0)
-}
-
-
-static auto s_append = bob::extension::FunctionDoc(
-  "append",
-  "Adds the contents of an object to the file",
-  "This method appends data to the file. "
-  "If the file does not exist, creates a new file, else, makes sure that the inserted array respects the previously set file structure.",
-  true
-)
-.add_prototype("data", "position")
-.add_parameter("data", "array_like", "The array to be written into the file; it can be a :py:class:`numpy.ndarray`, a :py:class:`bob.blitz.array` or any other object which can be converted to either of them")
-.add_return("position", "int", "The current position of the newly written data")
-;
-static PyObject* PyBobIoFile_append(PyBobIoFileObject* self, PyObject *args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static char** kwlist = s_append.kwlist();
-
-  PyBlitzArrayObject* bz = 0;
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&", kwlist, &PyBlitzArray_Converter, &bz)) return 0;
-  auto bz_ = make_safe(bz);
-  Py_ssize_t pos = -1;
-
-  bobskin skin(bz);
-  pos = self->f->append(skin);
-
-  return Py_BuildValue("n", pos);
-BOB_CATCH_MEMBER(exception_message(self, s_append.name()).c_str(), 0)
-}
-
-
-PyObject* PyBobIo_TypeInfoAsTuple (const bob::io::base::array::typeinfo& ti) {
-
-  int type_num = PyBobIo_AsTypenum(ti.dtype);
-  if (type_num == NPY_NOTYPE) return 0;
-
-  PyObject* retval = Py_BuildValue("NNN",
-      reinterpret_cast<PyObject*>(PyArray_DescrFromType(type_num)),
-      PyTuple_New(ti.nd), //shape
-      PyTuple_New(ti.nd)  //strides
-      );
-  if (!retval) return 0;
-
-  PyObject* shape = PyTuple_GET_ITEM(retval, 1);
-  PyObject* stride = PyTuple_GET_ITEM(retval, 2);
-  for (Py_ssize_t i=0; (size_t)i<ti.nd; ++i) {
-    PyTuple_SET_ITEM(shape, i, Py_BuildValue("n", ti.shape[i]));
-    PyTuple_SET_ITEM(stride, i, Py_BuildValue("n", ti.stride[i]));
-  }
-
-  return retval;
-}
-
-static auto s_describe = bob::extension::FunctionDoc(
-  "describe",
-  "Returns a description (dtype, shape, stride) of data at the file",
-  0,
-  true
-)
-.add_prototype("[all]", "dtype, shape, stride")
-.add_parameter("all", "bool", "[Default: ``False``]  If set to ``True``, returns the shape and strides for reading the whole file contents in one shot.")
-.add_return("dtype", ":py:class:`numpy.dtype`", "The data type of the object")
-.add_return("shape", "tuple", "The shape of the object")
-.add_return("stride", "tuple", "The stride of the object")
-;
-static PyObject* PyBobIoFile_describe(PyBobIoFileObject* self, PyObject *args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static const char* const_kwlist[] = {"all", 0};
-  static char** kwlist = const_cast<char**>(const_kwlist);
-
-  PyObject* all = 0;
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &all)) return 0;
-
-  const bob::io::base::array::typeinfo* info = 0;
-  if (all && PyObject_IsTrue(all)) info = &self->f->type_all();
-  else info = &self->f->type();
-
-  /* Now return type description and tuples with shape and strides */
-  return PyBobIo_TypeInfoAsTuple(*info);
-BOB_CATCH_MEMBER(exception_message(self, s_describe.name()).c_str(), 0)
-}
-
-
-static PyMethodDef PyBobIoFile_methods[] = {
-    {
-      s_read.name(),
-      (PyCFunction)PyBobIoFile_read,
-      METH_VARARGS|METH_KEYWORDS,
-      s_read.doc(),
-    },
-    {
-      s_write.name(),
-      (PyCFunction)PyBobIoFile_write,
-      METH_VARARGS|METH_KEYWORDS,
-      s_write.doc(),
-    },
-    {
-      s_append.name(),
-      (PyCFunction)PyBobIoFile_append,
-      METH_VARARGS|METH_KEYWORDS,
-      s_append.doc(),
-    },
-    {
-      s_describe.name(),
-      (PyCFunction)PyBobIoFile_describe,
-      METH_VARARGS|METH_KEYWORDS,
-      s_describe.doc(),
-    },
-    {0}  /* Sentinel */
-};
-
-/**********************************
- * Definition of Iterator to File *
- **********************************/
-
-PyDoc_STRVAR(s_fileiterator_str, BOB_EXT_MODULE_PREFIX ".File.iter");
-
-/* How to create a new PyBobIoFileIteratorObject */
-static PyObject* PyBobIoFileIterator_New(PyTypeObject* type, PyObject*, PyObject*) {
-
-  /* Allocates the python object itself */
-  PyBobIoFileIteratorObject* self = (PyBobIoFileIteratorObject*)type->tp_alloc(type, 0);
-
-  return reinterpret_cast<PyObject*>(self);
-}
-
-static PyObject* PyBobIoFileIterator_iter (PyBobIoFileIteratorObject* self) {
-  return reinterpret_cast<PyObject*>(self);
-}
-
-static PyObject* PyBobIoFileIterator_next (PyBobIoFileIteratorObject* self) {
-  if ((size_t)self->curpos >= self->pyfile->f->size()) {
-    Py_XDECREF((PyObject*)self->pyfile);
-    self->pyfile = 0;
-    return 0;
-  }
-  return PyBobIoFile_getIndex(self->pyfile, self->curpos++);
-}
-
-static PyObject* PyBobIoFile_iter (PyBobIoFileObject* self) {
-  PyBobIoFileIteratorObject* retval = (PyBobIoFileIteratorObject*)PyBobIoFileIterator_New(&PyBobIoFileIterator_Type, 0, 0);
-  if (!retval) return 0;
-  retval->pyfile = self;
-  retval->curpos = 0;
-  return Py_BuildValue("N", retval);
-}
-
-#if PY_VERSION_HEX >= 0x03000000
-#  define Py_TPFLAGS_HAVE_ITER 0
-#endif
-
-PyTypeObject PyBobIoFileIterator_Type = {
-  PyVarObject_HEAD_INIT(0, 0)
-  0
-};
-
-
-PyTypeObject PyBobIoFile_Type = {
-  PyVarObject_HEAD_INIT(0, 0)
-  0
-};
-
-bool init_File(PyObject* module){
-
-  // initialize the iterator
-  PyBobIoFileIterator_Type.tp_name = s_fileiterator_str;
-  PyBobIoFileIterator_Type.tp_basicsize = sizeof(PyBobIoFileIteratorObject);
-  PyBobIoFileIterator_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER;
-  PyBobIoFileIterator_Type.tp_iter = (getiterfunc)PyBobIoFileIterator_iter;
-  PyBobIoFileIterator_Type.tp_iternext = (iternextfunc)PyBobIoFileIterator_next;
-
-  // initialize the File
-  PyBobIoFile_Type.tp_name = s_file.name();
-  PyBobIoFile_Type.tp_basicsize = sizeof(PyBobIoFileObject);
-  PyBobIoFile_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
-  PyBobIoFile_Type.tp_doc = s_file.doc();
-
-  // set the functions
-  PyBobIoFile_Type.tp_new = PyBobIoFile_New;
-  PyBobIoFile_Type.tp_init = reinterpret_cast<initproc>(PyBobIoFile_init);
-  PyBobIoFile_Type.tp_dealloc = reinterpret_cast<destructor>(PyBobIoFile_Delete);
-  PyBobIoFile_Type.tp_methods = PyBobIoFile_methods;
-  PyBobIoFile_Type.tp_getset = PyBobIoFile_getseters;
-  PyBobIoFile_Type.tp_iter = (getiterfunc)PyBobIoFile_iter;
-
-  PyBobIoFile_Type.tp_str = reinterpret_cast<reprfunc>(PyBobIoFile_repr);
-  PyBobIoFile_Type.tp_repr = reinterpret_cast<reprfunc>(PyBobIoFile_repr);
-  PyBobIoFile_Type.tp_as_mapping = &PyBobIoFile_Mapping;
-
-
-  // check that everything is fine
-  if (PyType_Ready(&PyBobIoFile_Type) < 0)
-    return false;
-  if (PyType_Ready(&PyBobIoFileIterator_Type) < 0)
-    return false;
-
-  // add the type to the module
-  Py_INCREF(&PyBobIoFile_Type);
-  bool success = PyModule_AddObject(module, s_file.name(), (PyObject*)&PyBobIoFile_Type) >= 0;
-  if (!success) return false;
-  Py_INCREF(&PyBobIoFileIterator_Type);
-  success = PyModule_AddObject(module, s_fileiterator_str, (PyObject*)&PyBobIoFileIterator_Type) >= 0;
-  return success;
-}
diff --git a/bob/io/base/hdf5.cpp b/bob/io/base/hdf5.cpp
deleted file mode 100644
index 42347bda96f5b47a0fb80c89cfba70e63627d30e..0000000000000000000000000000000000000000
--- a/bob/io/base/hdf5.cpp
+++ /dev/null
@@ -1,2137 +0,0 @@
-/**
- * @author Andre Anjos <andre.anjos@idiap.ch>
- * @date Tue 12 Nov 18:19:22 2013
- *
- * @brief Bindings to bob::io::base::HDF5File
- */
-
-#define BOB_IO_BASE_MODULE
-#include <bob.io.base/api.h>
-
-#include <boost/make_shared.hpp>
-#include <numpy/arrayobject.h>
-#include <bob.blitz/cppapi.h>
-#include <bob.blitz/cleanup.h>
-#include <bob.extension/documentation.h>
-#include <stdexcept>
-#include <cstring>
-
-/* Creates an exception message including the name of the given file, if possible */
-inline const std::string exception_message(PyBobIoHDF5FileObject* self, const std::string& name){
-  std::ostringstream str;
-  str << name << " (";
-  try{
-    str << "'" << self->f->filename() << "'";
-  } catch (...){
-    str << "<unkown>";
-  }
-  str << ")";
-  return  str.str();
-}
-
-static auto s_hdf5file = bob::extension::ClassDoc(
-  "HDF5File",
-  "Reads and writes data to HDF5 files.",
-  "HDF5 stands for Hierarchical Data Format version 5. "
-  "It is a flexible, binary file format that allows one to store and read data efficiently into or from files. "
-  "It is a cross-platform, cross-architecture format.\n\n"
-  "Objects of this class allows users to read and write data from and to files in HDF5 format. "
-  "For an introduction to HDF5, visit the `HDF5 Website <http://www.hdfgroup.org/HDF5>`_."
-)
-.add_constructor(
-  bob::extension::FunctionDoc(
-    "HDF5File",
-    "Opens an HFF5 file for reading, writing or appending.",
-    "For the ``open`` mode, use ``'r'`` for read-only ``'a'`` for read/write/append, ``'w'`` for read/write/truncate or ``'x'`` for (read/write/exclusive). "
-    "When another :py:class:`HDF5File` object is given, a shallow copy is created, pointing to the same file."
-  )
-  .add_prototype("filename, [mode]","")
-  .add_prototype("hdf5", "")
-  .add_parameter("filename", "str", "The file path to the file you want to open for reading or writing")
-  .add_parameter("mode", "one of ('r', 'w', 'a', 'x')", "[Default: ``'r'``]  The opening mode")
-  .add_parameter("hdf5", ":py:class:`HDF5File`", "An HDF5 file to copy-construct")
-);
-
-
-int PyBobIoHDF5File_Check(PyObject* o) {
-  if (!o) return 0;
-  return PyObject_IsInstance(o, reinterpret_cast<PyObject*>(&PyBobIoHDF5File_Type));
-}
-
-int PyBobIoHDF5File_Converter(PyObject* o, PyBobIoHDF5FileObject** a) {
-  if (!PyBobIoHDF5File_Check(o)) return 0;
-  Py_INCREF(o);
-  (*a) = reinterpret_cast<PyBobIoHDF5FileObject*>(o);
-  return 1;
-}
-
-/* How to create a new PyBobIoHDF5FileObject */
-static PyObject* PyBobIoHDF5File_New(PyTypeObject* type, PyObject*, PyObject*) {
-
-  /* Allocates the python object itself */
-  PyBobIoHDF5FileObject* self = (PyBobIoHDF5FileObject*)type->tp_alloc(type, 0);
-
-  self->f.reset();
-
-  return reinterpret_cast<PyObject*>(self);
-}
-
-static void PyBobIoHDF5File_Delete (PyBobIoHDF5FileObject* o) {
-
-  o->f.reset();
-  Py_TYPE(o)->tp_free((PyObject*)o);
-}
-
-static bob::io::base::HDF5File::mode_t mode_from_char (char mode) {
-
-  bob::io::base::HDF5File::mode_t new_mode = bob::io::base::HDF5File::inout;
-
-  switch (mode) {
-    case 'r': new_mode = bob::io::base::HDF5File::in; break;
-    case 'a': new_mode = bob::io::base::HDF5File::inout; break;
-    case 'w': new_mode = bob::io::base::HDF5File::trunc; break;
-    case 'x': new_mode = bob::io::base::HDF5File::excl; break;
-    default:
-      PyErr_SetString(PyExc_RuntimeError, "Supported flags are 'r' (read-only), 'a' (read/write/append), 'w' (read/write/truncate) or 'x' (read/write/exclusive)");
-  }
-
-  return new_mode;
-
-}
-
-/* The __init__(self) method */
-static int PyBobIoHDF5File_init(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static char** kwlist1 = s_hdf5file.kwlist(0);
-  static char** kwlist2 = s_hdf5file.kwlist(1);
-
-  // get the number of command line arguments
-  Py_ssize_t nargs = (args?PyTuple_Size(args):0) + (kwds?PyDict_Size(kwds):0);
-
-  if (!nargs){
-    // at least one argument is required
-    PyErr_Format(PyExc_TypeError, "`%s' constructor requires at least one parameter", Py_TYPE(self)->tp_name);
-    return -1;
-  } // nargs == 0
-
-  PyObject* k = Py_BuildValue("s", kwlist2[0]);
-  auto k_ = make_safe(k);
-  if (
-    (kwds && PyDict_Contains(kwds, k)) ||
-    (args && PyBobIoHDF5File_Check(PyTuple_GET_ITEM(args, 0)))
-  ){
-    PyBobIoHDF5FileObject* other;
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&", kwlist2, &PyBobIoHDF5File_Converter, &other))
-      return -1;
-    auto other_ = make_safe(other);
-    self->f = other->f;
-    return 0;
-  }
-
-#if PY_VERSION_HEX >= 0x03000000
-#  define MODE_CHAR "C"
-  int mode = 'r';
-#else
-#  define MODE_CHAR "c"
-  char mode = 'r';
-#endif
-
-  const char* filename;
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|" MODE_CHAR, kwlist1,
-        &PyBobIo_FilenameConverter, &filename, &mode))
-    return -1;
-
-#undef MODE_CHAR
-
-  if (mode != 'r' && mode != 'w' && mode != 'a' && mode != 'x') {
-    PyErr_Format(PyExc_ValueError, "file open mode string should have 1 element and be either 'r' (read), 'w' (write), 'a' (append), 'x' (exclusive)");
-    return -1;
-  }
-  bob::io::base::HDF5File::mode_t mode_mode = mode_from_char(mode);
-  if (PyErr_Occurred()) return -1;
-
-  self->f.reset(new bob::io::base::HDF5File(filename, mode_mode));
-  return 0; ///< SUCCESS
-BOB_CATCH_MEMBER("hdf5 constructor", -1)
-}
-
-
-static PyObject* PyBobIoHDF5File_repr(PyBobIoHDF5FileObject* self) {
-BOB_TRY
-  return PyString_FromFormat("%s(filename='%s')", Py_TYPE(self)->tp_name, self->f->filename().c_str());
-BOB_CATCH_MEMBER("__repr__", 0)
-}
-
-
-static auto s_flush = bob::extension::FunctionDoc(
-  "flush",
-  "Flushes the content of the HDF5 file to disk",
-  "When the HDF5File is open for writing, this function synchronizes the contents on the disk with the one from the file. "
-  "When the file is open for reading, nothing happens.",
-  true
-)
-  .add_prototype("")
-;
-static PyObject* PyBobIoHDF5File_flush(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static char** kwlist = s_flush.kwlist();
-
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) return 0;
-
-  self->f->flush();
-  Py_RETURN_NONE;
-BOB_CATCH_MEMBER(exception_message(self, s_flush.name()).c_str(), 0)
-}
-
-
-static auto s_close = bob::extension::FunctionDoc(
-  "close",
-  "Closes this file",
-  "This function closes the HDF5File after flushing all its contents to disk. "
-  "After the HDF5File is closed, any operation on it will result in an exception.",
-  true
-)
-.add_prototype("")
-;
-static PyObject* PyBobIoHDF5File_close(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static char** kwlist = s_close.kwlist();
-
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) return 0;
-
-  self->f->close();
-
-  Py_RETURN_NONE;
-BOB_CATCH_MEMBER(exception_message(self, s_close.name()).c_str(), 0);
-}
-
-
-static auto s_cd = bob::extension::FunctionDoc(
-  "cd",
-  "Changes the current prefix path",
-  "When this object is created the prefix path is empty, which means all following paths to data objects should be given using the full path. "
-  "If you set the ``path`` to a different value, it will be used as a prefix to any subsequent operation until you reset it. "
-  "If ``path`` starts with ``'/'``, it is treated as an absolute path. "
-  "If the value is relative, it is added to the current path; ``'..'`` and ``'.'`` are supported. "
-  "If it is absolute, it causes the prefix to be reset.\n\n"
-  "..note:: All operations taking a relative path, following a :py:func:`cd`, will be considered relative to the value defined by the :py:attr:`cwd` property of this object.",
-  true
-)
-.add_prototype("path")
-.add_parameter("path", "str", "The path to change directories to")
-;
-
-static PyObject* PyBobIoHDF5File_changeDirectory(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static char** kwlist = s_cd.kwlist();
-
-  const char* path = 0;
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &path)) return 0;
-
-  self->f->cd(path);
-
-  Py_RETURN_NONE;
-BOB_CATCH_MEMBER(exception_message(self, s_cd.name()).c_str(), 0)
-}
-
-
-static auto s_has_group = bob::extension::FunctionDoc(
-  "has_group",
-  "Checks if a path (group) exists inside a file",
-  "This method does not work for datasets, only for directories. "
-  "If the given path is relative, it is take w.r.t. to the current working directory.",
-  true
-)
-.add_prototype("path")
-.add_parameter("path", "str", "The path to check")
-;
-static PyObject* PyBobIoHDF5File_hasGroup(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static char** kwlist = s_has_group.kwlist();
-
-  const char* path = 0;
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &path)) return 0;
-
-  if (self->f->hasGroup(path)) Py_RETURN_TRUE;
-  Py_RETURN_FALSE;
-BOB_CATCH_MEMBER(exception_message(self, s_has_group.name()).c_str(), 0)
-}
-
-
-static auto s_create_group = bob::extension::FunctionDoc(
-  "create_group",
-  "Creates a new path (group) inside the file",
-  "A relative path is taken w.r.t. to the current directory. "
-  "If the directory already exists (check it with :py:meth:`has_group`), an exception will be raised.",
-  true
-)
-.add_prototype("path")
-.add_parameter("path", "str", "The path to create.")
-;
-static PyObject* PyBobIoHDF5File_createGroup(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static char** kwlist = s_create_group.kwlist();
-
-  const char* path = 0;
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &path)) return 0;
-
-  self->f->createGroup(path);
-
-  Py_RETURN_NONE;
-BOB_CATCH_MEMBER(exception_message(self, s_create_group.name()).c_str(), 0)
-}
-
-
-static auto s_has_dataset = bob::extension::FunctionDoc(
-  "has_dataset",
-  "Checks if a dataset exists inside a file",
-  "Checks if a dataset exists inside a file, on the specified path. "
-  "If the given path is relative, it is take w.r.t. to the current working directory.\n\n"
-  ".. note:: The functions :py:meth:`has_dataset` and :py:meth:`has_key` are synonyms. "
-  "You can also use the Python's ``in`` operator instead of :py:meth:`has_key`: ``key in hdf5file``.",
-  true
-)
-.add_prototype("key")
-.add_parameter("key", "str", "The dataset path to check")
-;
-auto s_has_key = s_has_dataset.clone("has_key");
-static PyObject* PyBobIoHDF5File_hasDataset(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static char** kwlist = s_has_dataset.kwlist();
-
-  const char* key = 0;
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &key)) return 0;
-
-  if (self->f->contains(key)) Py_RETURN_TRUE;
-
-  Py_RETURN_FALSE;
-BOB_CATCH_MEMBER(exception_message(self, s_has_dataset.name()).c_str(), 0)
-}
-
-static bob::io::base::hdf5type PyBobIo_H5FromTypenum (int type_num) {
-
-  switch(type_num) {
-    case NPY_STRING:     return bob::io::base::s;
-    case NPY_BOOL:       return bob::io::base::b;
-    case NPY_INT8:       return bob::io::base::i8;
-    case NPY_INT16:      return bob::io::base::i16;
-    case NPY_INT32:      return bob::io::base::i32;
-    case NPY_INT64:      return bob::io::base::i64;
-    case NPY_UINT8:      return bob::io::base::u8;
-    case NPY_UINT16:     return bob::io::base::u16;
-    case NPY_UINT32:     return bob::io::base::u32;
-    case NPY_UINT64:     return bob::io::base::u64;
-    case NPY_FLOAT32:    return bob::io::base::f32;
-    case NPY_FLOAT64:    return bob::io::base::f64;
-#ifdef NPY_FLOAT128
-    case NPY_FLOAT128:   return bob::io::base::f128;
-#endif
-    case NPY_COMPLEX64:  return bob::io::base::c64;
-    case NPY_COMPLEX128: return bob::io::base::c128;
-#ifdef NPY_COMPLEX256
-    case NPY_COMPLEX256: return bob::io::base::c256;
-#endif
-#if defined(__LP64__) || defined(__APPLE__)
-    case NPY_LONGLONG:
-                         switch (NPY_BITSOF_LONGLONG) {
-                           case 8: return bob::io::base::i8;
-                           case 16: return bob::io::base::i16;
-                           case 32: return bob::io::base::i32;
-                           case 64: return bob::io::base::i64;
-                           default: return bob::io::base::unsupported;
-                         }
-                         break;
-    case NPY_ULONGLONG:
-                         switch (NPY_BITSOF_LONGLONG) {
-                           case 8: return bob::io::base::u8;
-                           case 16: return bob::io::base::u16;
-                           case 32: return bob::io::base::u32;
-                           case 64: return bob::io::base::u64;
-                           default: return bob::io::base::unsupported;
-                         }
-                         break;
-#endif
-    default:             return bob::io::base::unsupported;
-  }
-
-}
-
-static int PyBobIo_H5AsTypenum (bob::io::base::hdf5type type) {
-
-  switch(type) {
-    case bob::io::base::s:    return NPY_STRING;
-    case bob::io::base::b:    return NPY_BOOL;
-    case bob::io::base::i8:   return NPY_INT8;
-    case bob::io::base::i16:  return NPY_INT16;
-    case bob::io::base::i32:  return NPY_INT32;
-    case bob::io::base::i64:  return NPY_INT64;
-    case bob::io::base::u8:   return NPY_UINT8;
-    case bob::io::base::u16:  return NPY_UINT16;
-    case bob::io::base::u32:  return NPY_UINT32;
-    case bob::io::base::u64:  return NPY_UINT64;
-    case bob::io::base::f32:  return NPY_FLOAT32;
-    case bob::io::base::f64:  return NPY_FLOAT64;
-#ifdef NPY_FLOAT128
-    case bob::io::base::f128: return NPY_FLOAT128;
-#endif
-    case bob::io::base::c64:  return NPY_COMPLEX64;
-    case bob::io::base::c128: return NPY_COMPLEX128;
-#ifdef NPY_COMPLEX256
-    case bob::io::base::c256: return NPY_COMPLEX256;
-#endif
-    default:            return NPY_NOTYPE;
-  }
-
-}
-
-static PyObject* PyBobIo_HDF5TypeAsTuple (const bob::io::base::HDF5Type& t) {
-
-  const bob::io::base::HDF5Shape& sh = t.shape();
-  size_t ndim = sh.n();
-  const hsize_t* shptr = sh.get();
-
-  int type_num = PyBobIo_H5AsTypenum(t.type());
-  if (type_num == NPY_NOTYPE) {
-    PyErr_Format(PyExc_TypeError, "unsupported HDF5 element type (%d) found during conversion to numpy type number", (int)t.type());
-    return 0;
-  }
-
-  PyObject* dtype = reinterpret_cast<PyObject*>(PyArray_DescrFromType(type_num));
-  if (!dtype) return 0;
-  auto dtype_ = make_safe(dtype);
-
-  PyObject* shape = PyTuple_New(ndim);
-  if (!shape) return 0;
-  auto shape_ = make_safe(shape);
-
-  PyObject* retval = Py_BuildValue("OO", dtype, shape);
-  if (!retval) return 0;
-  auto retval_ = make_safe(retval);
-
-  for (Py_ssize_t i=0; i<(Py_ssize_t)ndim; ++i) {
-    PyObject* value = Py_BuildValue("n", shptr[i]);
-    if (!value) return 0;
-    PyTuple_SET_ITEM(shape, i, value);
-  }
-
-  return Py_BuildValue("O", retval);
-
-}
-
-static PyObject* PyBobIo_HDF5DescriptorAsTuple (const bob::io::base::HDF5Descriptor& d) {
-  return Py_BuildValue("NnO",
-    PyBobIo_HDF5TypeAsTuple(d.type),
-    d.size,
-    d.expandable? Py_True : Py_False
-  ); //steals references, except for True/False
-}
-
-
-static auto s_describe = bob::extension::FunctionDoc(
-  "describe",
-  "Describes a dataset type/shape, if it exists inside a file",
-  "If a given ``key`` to an HDF5 dataset exists inside the file, returns a type description of objects recorded in such a dataset, otherwise, raises an exception. "
-  "The returned value type is a list of tuples (HDF5Type, number-of-objects, expandable) describing the capabilities if the file is read using these formats. \n\n",
-  true
-)
-.add_prototype("key", "[(hdf5type, size, expandable)]")
-.add_parameter("key", "str", "The dataset path to describe")
-.add_return("hdf5type", "tuple", "The HDF5Type of the returned array")
-.add_return("size", "int", "The number of objects in the dataset")
-.add_return("expandable", "bool", "Defines if this object can be resized.")
-;
-static PyObject* PyBobIoHDF5File_describe(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static char** kwlist = s_describe.kwlist();
-
-  const char* key = 0;
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &key)) return 0;
-
-  const std::vector<bob::io::base::HDF5Descriptor>& dv = self->f->describe(key);
-  PyObject* retval = PyList_New(dv.size());
-  if (!retval) return 0;
-  auto retval_ = make_safe(retval);
-
-  for (size_t k=0; k<dv.size(); ++k) {
-    PyObject* entry = PyBobIo_HDF5DescriptorAsTuple(dv[k]);
-    if (!entry) return 0;
-    PyList_SET_ITEM(retval, k, entry);
-  }
-
-  return Py_BuildValue("O", retval);
-BOB_CATCH_MEMBER(exception_message(self, s_describe.name()).c_str(), 0)
-}
-
-
-static auto s_unlink = bob::extension::FunctionDoc(
-  "unlink",
-  "Unlinks datasets inside the file making them invisible",
-  "If a given path to an HDF5 dataset exists inside the file, unlinks it."
-  "Please note this will note remove the data from the file, just make it inaccessible. "
-  "If you wish to cleanup, save the reacheable objects from this file to another :py:class:`HDF5File` object using :py:meth:`copy`, for example.",
-  true
-)
-.add_prototype("key")
-.add_parameter("key", "str", "The dataset path to unlink")
-;
-static PyObject* PyBobIoHDF5File_unlink(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static char** kwlist = s_unlink.kwlist();
-
-  const char* key = 0;
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &key)) return 0;
-
-  self->f->unlink(key);
-
-  Py_RETURN_NONE;
-BOB_CATCH_MEMBER(exception_message(self, s_unlink.name()).c_str(), 0)
-}
-
-
-static auto s_rename = bob::extension::FunctionDoc(
-  "rename",
-  "Renames datasets in a file",
-  0,
-  true
-)
-.add_prototype("from, to")
-.add_parameter("from", "str", "The path to the data to be renamed")
-.add_parameter("to", "str", "The new name of the dataset")
-;
-static PyObject* PyBobIoHDF5File_rename(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static char** kwlist = s_rename.kwlist();
-
-  const char* from = 0;
-  const char* to = 0;
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss", kwlist, &from, &to)) return 0;
-
-  self->f->rename(from, to);
-
-  Py_RETURN_NONE;
-BOB_CATCH_MEMBER(exception_message(self, s_rename.name()).c_str(), 0)
-}
-
-
-static auto s_paths = bob::extension::FunctionDoc(
-  "paths",
-  "Lists datasets available inside this file",
-  "Returns all paths to datasets available inside this file, stored under the current working directory. "
-  "If ``relative`` is set to ``True``, the returned paths are relative to the current working directory, otherwise they are absolute.\n\n"
-  ".. note:: The functions :py:meth:`keys` and :py:meth:`paths` are synonyms.",
-  true
-)
-.add_prototype("[relative]", "paths")
-.add_parameter("relative", "bool", "[Default: ``False``] If set to ``True``, the returned paths are relative to the current working directory, otherwise they are absolute")
-.add_return("paths", "[str]", "A list of paths inside this file")
-;
-auto s_keys = s_paths.clone("keys");
-static PyObject* PyBobIoHDF5File_paths(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static char** kwlist = s_paths.kwlist();
-
-  PyObject* pyrel = 0;
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &pyrel)) return 0;
-
-  bool relative = false;
-  if (pyrel && PyObject_IsTrue(pyrel)) relative = true;
-
-  std::vector<std::string> values;
-  self->f->paths(values, relative);
-  PyObject* retval = PyList_New(values.size());
-  if (!retval) return 0;
-  auto retval_ = make_safe(retval);
-  for (size_t i=0; i<values.size(); ++i) {
-    PyList_SET_ITEM(retval, i, Py_BuildValue("s", values[i].c_str()));
-  }
-
-  return Py_BuildValue("O", retval);
-BOB_CATCH_MEMBER(exception_message(self, s_paths.name()).c_str(), 0)
-}
-
-
-static auto s_sub_groups = bob::extension::FunctionDoc(
-  "sub_groups",
-  "Lists groups (directories) in the current file",
-  0,
-  true
-)
-.add_prototype("[relative], [recursive]", "groups")
-.add_parameter("relative", "bool", "[Default: ``False``] If set to ``True``, the returned sub-groups are relative to the current working directory, otherwise they are absolute")
-.add_parameter("recursive", "bool", "[Default: ``True``] If set to ``False``, the returned sub-groups   are only the ones in the current directory, otherwise recurses down the directory structure")
-.add_return("groups", "[str]", "The list of directories (groups) inside this file")
-;
-static PyObject* PyBobIoHDF5File_subGroups(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static char** kwlist = s_sub_groups.kwlist();
-
-  PyObject* pyrel = 0;
-  PyObject* pyrec = 0;
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwlist, &pyrel, &pyrec)) return 0;
-
-  bool relative = (pyrel && PyObject_IsTrue(pyrel));
-  bool recursive = (!pyrec || PyObject_IsTrue(pyrec));
-
-  std::vector<std::string> values;
-  self->f->sub_groups(values, relative, recursive);
-  PyObject* retval = PyList_New(values.size());
-  if (!retval) return 0;
-  auto retval_ = make_safe(retval);
-  for (size_t i=0; i<values.size(); ++i) {
-    PyList_SET_ITEM(retval, i, Py_BuildValue("s", values[i].c_str()));
-  }
-
-  return Py_BuildValue("O", retval);
-BOB_CATCH_MEMBER(exception_message(self, s_sub_groups.name()).c_str(), 0)
-}
-
-
-static PyObject* PyBobIoHDF5File_Xread(PyBobIoHDF5FileObject* self, const char* p, int descriptor, int pos) {
-
-  const std::vector<bob::io::base::HDF5Descriptor> D = self->f->describe(p);
-
-  //last descriptor always contains the full readout.
-  const bob::io::base::HDF5Type& type = D[descriptor].type;
-  const bob::io::base::HDF5Shape& shape = type.shape();
-
-  if (shape.n() == 1 && shape[0] == 1) { //read as scalar
-    switch(type.type()) {
-      case bob::io::base::s:
-        return Py_BuildValue("s", self->f->read<std::string>(p, pos).c_str());
-      case bob::io::base::b:
-        return PyBlitzArrayCxx_FromCScalar(self->f->read<bool>(p, pos));
-      case bob::io::base::i8:
-        return PyBlitzArrayCxx_FromCScalar(self->f->read<int8_t>(p, pos));
-      case bob::io::base::i16:
-        return PyBlitzArrayCxx_FromCScalar(self->f->read<int16_t>(p, pos));
-      case bob::io::base::i32:
-        return PyBlitzArrayCxx_FromCScalar(self->f->read<int32_t>(p, pos));
-      case bob::io::base::i64:
-        return PyBlitzArrayCxx_FromCScalar(self->f->read<int64_t>(p, pos));
-      case bob::io::base::u8:
-        return PyBlitzArrayCxx_FromCScalar(self->f->read<uint8_t>(p, pos));
-      case bob::io::base::u16:
-        return PyBlitzArrayCxx_FromCScalar(self->f->read<uint16_t>(p, pos));
-      case bob::io::base::u32:
-        return PyBlitzArrayCxx_FromCScalar(self->f->read<uint32_t>(p, pos));
-      case bob::io::base::u64:
-        return PyBlitzArrayCxx_FromCScalar(self->f->read<uint64_t>(p, pos));
-      case bob::io::base::f32:
-        return PyBlitzArrayCxx_FromCScalar(self->f->read<float>(p, pos));
-      case bob::io::base::f64:
-        return PyBlitzArrayCxx_FromCScalar(self->f->read<double>(p, pos));
-      case bob::io::base::f128:
-        return PyBlitzArrayCxx_FromCScalar(self->f->read<long double>(p, pos));
-      case bob::io::base::c64:
-        return PyBlitzArrayCxx_FromCScalar(self->f->read<std::complex<float> >(p, pos));
-      case bob::io::base::c128:
-        return PyBlitzArrayCxx_FromCScalar(self->f->read<std::complex<double> >(p, pos));
-      case bob::io::base::c256:
-        return PyBlitzArrayCxx_FromCScalar(self->f->read<std::complex<long double> >(p, pos));
-      default:
-        PyErr_Format(PyExc_TypeError, "unsupported HDF5 type: %s", type.str().c_str());
-        return 0;
-    }
-  }
-
-  //read as an numpy array
-  int type_num = PyBobIo_H5AsTypenum(type.type());
-  if (type_num == NPY_NOTYPE) return 0; ///< failure
-
-  npy_intp pyshape[NPY_MAXDIMS];
-  for (size_t k=0; k<shape.n(); ++k) pyshape[k] = shape.get()[k];
-
-  PyObject* retval = PyArray_SimpleNew(shape.n(), pyshape, type_num);
-  if (!retval) return 0;
-  auto retval_ = make_safe(retval);
-
-  self->f->read_buffer(p, pos, type, PyArray_DATA((PyArrayObject*)retval));
-
-  return Py_BuildValue("O", retval);
-}
-
-
-static auto s_read = bob::extension::FunctionDoc(
-  "read",
-  "Reads whole datasets from the file",
-  "This function reads full data sets from this file. "
-  "The data type is dependent on the stored data, but is generally a :py:class:`numpy.ndarray`.\n\n"
-  ".. note:: The functions :py:func:`read` and :py:func:`get` are synonyms."
-)
-.add_prototype("key", "data")
-.add_parameter("key", "str", "The path to the dataset to read data from; can be an absolute value (starting with a leading ``'/'``) or relative to the current working directory :py:attr:`cwd`")
-.add_return("data", ":py:class:`numpy.ndarray` or other", "The data read from this file at the given key")
-;
-auto s_get = s_read.clone("get");
-static PyObject* PyBobIoHDF5File_read(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) {
-BOB_TRY
-
-  /* Parses input arguments in a single shot */
-  static char** kwlist = s_read.kwlist();
-
-  const char* key = 0;
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &key)) return 0;
-
-  return PyBobIoHDF5File_Xread(self, key, 1, 0);
-BOB_CATCH_MEMBER(exception_message(self, s_read.name()).c_str(), 0)
-}
-
-
-static auto s_lread = bob::extension::FunctionDoc(
-  "lread",
-  "Reads some contents of the dataset",
-  "This method reads contents from a dataset, treating the N-dimensional dataset like a container for multiple objects with N-1 dimensions. "
-  "It returns a single :py:class:`numpy.ndarray` in case ``pos`` is set to a value >= 0, or a list of arrays otherwise."
-)
-.add_prototype("key, [pos]", "data")
-.add_parameter("key", "str", "The path to the dataset to read data from, can be an absolute value (starting with a leading ``'/'``) or relative to the current working directory :py:attr:`cwd`")
-.add_parameter("pos", "int", "If given and >= 0 returns the data object with the given index, otherwise returns a list by reading all objects in sequence")
-.add_return("data", ":py:class:`numpy.ndarray` or [:py:class:`numpy.ndarray`]", "The data read from this file")
-;
-static PyObject* PyBobIoHDF5File_listRead(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static char** kwlist = s_lread.kwlist();
-
-  const char* key = 0;
-  Py_ssize_t pos = -1;
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|n", kwlist, &key, &pos)) return 0;
-
-  if (pos >= 0) return PyBobIoHDF5File_Xread(self, key, 0, pos);
-
-  //otherwise returns as a list
-  const std::vector<bob::io::base::HDF5Descriptor>& D = self->f->describe(key);
-
-  PyObject* retval = PyList_New(D[0].size);
-  if (!retval) return 0;
-  auto retval_ = make_safe(retval);
-
-  for (uint64_t k=0; k<D[0].size; ++k) {
-    PyObject* item = PyBobIoHDF5File_Xread(self, key, 0, k);
-    if (!item) return 0;
-    PyList_SET_ITEM(retval, k, item);
-  }
-
-  return Py_BuildValue("O", retval);
-BOB_CATCH_MEMBER(exception_message(self, s_lread.name()).c_str(), 0)
-}
-
-
-/**
- * Sets at 't', the type of the object 'o' according to our support types.
- * Raise in case of problems. Furthermore, returns 'true' if the object is as
- * simple scalar.
- */
-
-static void null_char_array_deleter(char*) {}
-
-#if PY_VERSION_HEX >= 0x03000000
-static void char_array_deleter(char* o) { delete[] o; }
-#endif
-
-static boost::shared_ptr<char> PyBobIo_GetString(PyObject* o) {
-
-#if PY_VERSION_HEX < 0x03000000
-
-  return boost::shared_ptr<char>(PyString_AsString(o), null_char_array_deleter);
-
-#else
-
-  if (PyBytes_Check(o)) {
-    //fast way out
-    return boost::shared_ptr<char>(PyBytes_AsString(o), null_char_array_deleter);
-  }
-
-  PyObject* bytes = 0;
-
-  if (PyUnicode_Check(o)) {
-    //re-encode using utf-8
-    bytes = PyUnicode_AsEncodedString(o, "utf-8", "strict");
-  }
-  else {
-    //tries coercion
-    bytes = PyObject_Bytes(o);
-  }
-  auto bytes_ = make_safe(bytes); ///< protects acquired resource
-
-  Py_ssize_t length = PyBytes_GET_SIZE(bytes)+1;
-  char* copy = new char[length];
-  std::strncpy(copy, PyBytes_AsString(bytes), length);
-
-  return boost::shared_ptr<char>(copy, char_array_deleter);
-
-#endif
-
-}
-
-static int PyBobIoHDF5File_setStringType(bob::io::base::HDF5Type& t, PyObject* o) {
-  auto value = PyBobIo_GetString(o);
-  if (!value) return -1;
-  t = bob::io::base::HDF5Type(value.get());
-  return 0;
-}
-
-template <typename T> int PyBobIoHDF5File_setType(bob::io::base::HDF5Type& t) {
-  T v;
-  t = bob::io::base::HDF5Type(v);
-  return 0;
-}
-
-/**
- * A function to check for python scalars that works with numpy-1.6.x
- */
-static bool PyBobIoHDF5File_isPythonScalar(PyObject* obj) {
-  return (
-    PyBool_Check(obj) ||
-#if PY_VERSION_HEX < 0x03000000
-    PyString_Check(obj) ||
-#else
-    PyBytes_Check(obj) ||
-#endif
-    PyUnicode_Check(obj) ||
-#if PY_VERSION_HEX < 0x03000000
-    PyInt_Check(obj) ||
-#endif
-    PyLong_Check(obj) ||
-    PyFloat_Check(obj) ||
-    PyComplex_Check(obj)
-    );
-}
-
-/**
- * Returns the type of object `op' is - a scalar (return value = 0), a
- * bob.blitz.array (return value = 1), a numpy.ndarray (return value = 2), an
- * object which is convertible to a numpy.ndarray (return value = 3) or returns
- * -1 if the object cannot be converted. No error is set on the python stack.
- *
- * If the object is convertible into a numpy.ndarray, then it is converted into
- * a numpy ndarray and the resulting object is placed in `converted'. If
- * `*converted' is set to 0 (NULL), then we don't try a conversion, returning
- * -1.
- */
-static int PyBobIoHDF5File_getObjectType(PyObject* o, bob::io::base::HDF5Type& t,
-    PyObject** converted=0) {
-
-  if (PyArray_IsScalar(o, Generic) || PyBobIoHDF5File_isPythonScalar(o)) {
-
-    if (PyArray_IsScalar(o, String))
-      return PyBobIoHDF5File_setStringType(t, o);
-
-    else if (PyBool_Check(o))
-      return PyBobIoHDF5File_setType<bool>(t);
-
-#if PY_VERSION_HEX < 0x03000000
-    else if (PyString_Check(o))
-      return PyBobIoHDF5File_setStringType(t, o);
-
-#else
-    else if (PyBytes_Check(o))
-      return PyBobIoHDF5File_setStringType(t, o);
-
-#endif
-    else if (PyUnicode_Check(o))
-      return PyBobIoHDF5File_setStringType(t, o);
-
-#if PY_VERSION_HEX < 0x03000000
-    else if (PyInt_Check(o))
-      return PyBobIoHDF5File_setType<int32_t>(t);
-
-#endif
-    else if (PyLong_Check(o))
-      return PyBobIoHDF5File_setType<int64_t>(t);
-
-    else if (PyFloat_Check(o))
-      return PyBobIoHDF5File_setType<double>(t);
-
-    else if (PyComplex_Check(o))
-      return PyBobIoHDF5File_setType<std::complex<double> >(t);
-
-    else if (PyArray_IsScalar(o, Bool))
-      return PyBobIoHDF5File_setType<bool>(t);
-
-    else if (PyArray_IsScalar(o, Int8))
-      return PyBobIoHDF5File_setType<int8_t>(t);
-
-    else if (PyArray_IsScalar(o, UInt8))
-      return PyBobIoHDF5File_setType<uint8_t>(t);
-
-    else if (PyArray_IsScalar(o, Int16))
-      return PyBobIoHDF5File_setType<int16_t>(t);
-
-    else if (PyArray_IsScalar(o, UInt16))
-      return PyBobIoHDF5File_setType<uint16_t>(t);
-
-    else if (PyArray_IsScalar(o, Int32))
-      return PyBobIoHDF5File_setType<int32_t>(t);
-
-    else if (PyArray_IsScalar(o, UInt32))
-      return PyBobIoHDF5File_setType<uint32_t>(t);
-
-    else if (PyArray_IsScalar(o, Int64))
-      return PyBobIoHDF5File_setType<int64_t>(t);
-
-    else if (PyArray_IsScalar(o, UInt64))
-      return PyBobIoHDF5File_setType<uint64_t>(t);
-
-    else if (PyArray_IsScalar(o, Float))
-      return PyBobIoHDF5File_setType<float>(t);
-
-    else if (PyArray_IsScalar(o, Double))
-      return PyBobIoHDF5File_setType<double>(t);
-
-    else if (PyArray_IsScalar(o, LongDouble))
-      return PyBobIoHDF5File_setType<long double>(t);
-
-    else if (PyArray_IsScalar(o, CFloat))
-      return PyBobIoHDF5File_setType<std::complex<float> >(t);
-
-    else if (PyArray_IsScalar(o, CDouble))
-      return PyBobIoHDF5File_setType<std::complex<double> >(t);
-
-    else if (PyArray_IsScalar(o, CLongDouble))
-      return PyBobIoHDF5File_setType<std::complex<long double> >(t);
-
-    //if you get to this, point, it is an unsupported scalar
-    return -1;
-
-  }
-
-  else if (PyBlitzArray_Check(o)) {
-
-    PyBlitzArrayObject* bz = reinterpret_cast<PyBlitzArrayObject*>(o);
-    bob::io::base::hdf5type h5type = PyBobIo_H5FromTypenum(bz->type_num);
-    if (h5type == bob::io::base::unsupported) return -1;
-    bob::io::base::HDF5Shape h5shape(bz->ndim, bz->shape);
-    t = bob::io::base::HDF5Type(h5type, h5shape);
-    return 1;
-
-  }
-
-  else if (PyArray_CheckExact(o) && PyArray_ISCARRAY_RO((PyArrayObject*)o)) {
-
-    PyArrayObject* np = reinterpret_cast<PyArrayObject*>(o);
-    bob::io::base::hdf5type h5type = PyBobIo_H5FromTypenum(PyArray_DESCR(np)->type_num);
-    if (h5type == bob::io::base::unsupported) return -1;
-    bob::io::base::HDF5Shape h5shape(PyArray_NDIM(np), PyArray_DIMS(np));
-    t = bob::io::base::HDF5Type(h5type, h5shape);
-    return 2;
-
-  }
-
-  else if (converted) {
-
-    *converted = PyArray_FromAny(o, 0, 1, 0,
-#if     NPY_FEATURE_VERSION >= NUMPY17_API /* NumPy C-API version >= 1.7 */
-        NPY_ARRAY_CARRAY_RO,
-#       else
-        NPY_CARRAY_RO,
-#       endif
-        0);
-    if (!*converted) return -1; ///< error condition
-
-    PyArrayObject* np = reinterpret_cast<PyArrayObject*>(*converted);
-    bob::io::base::hdf5type h5type = PyBobIo_H5FromTypenum(PyArray_DESCR(np)->type_num);
-    if (h5type == bob::io::base::unsupported) {
-      Py_CLEAR(*converted);
-      return -1;
-    }
-    bob::io::base::HDF5Shape h5shape(PyArray_NDIM(np), PyArray_DIMS(np));
-    t = bob::io::base::HDF5Type(h5type, h5shape);
-    return 3;
-
-  }
-
-  //if you get to this, point, it is an unsupported type
-  return -1;
-
-}
-
-template <typename T>
-static PyObject* PyBobIoHDF5File_replaceScalar(PyBobIoHDF5FileObject* self,
-    const char* path, Py_ssize_t pos, PyObject* o) {
-
-  T value = PyBlitzArrayCxx_AsCScalar<T>(o);
-  if (PyErr_Occurred()) return 0;
-  self->f->replace(path, pos, value);
-
-  Py_RETURN_NONE;
-
-}
-
-
-static auto s_replace = bob::extension::FunctionDoc(
-  "replace",
-  "Modifies the value of a scalar/array in a dataset.",
-  0,
-  true
-)
-.add_prototype("path, pos, data")
-.add_parameter("path", "str", "The path to the dataset to read data from; can be an absolute value (starting with a leading ``'/'``) or relative to the current working directory :py:attr:`cwd`")
-.add_parameter("pos", "int", "Position, within the dataset, of the object to be replaced; the object position on the dataset must exist, or an exception is raised")
-.add_parameter("data", ":py:class:`numpy.ndarray` or scalar", "Object to replace the value with; this value must be compatible with the typing information on the dataset, or an exception will be raised")
-;
-static PyObject* PyBobIoHDF5File_replace(PyBobIoHDF5FileObject* self, PyObject* args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static char** kwlist = s_replace.kwlist();
-
-  const char* path = 0;
-  Py_ssize_t pos = -1;
-  PyObject* data = 0;
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "snO", kwlist, &path, &pos, &data)) return 0;
-
-  bob::io::base::HDF5Type type;
-  PyObject* converted = 0;
-  int is_array = PyBobIoHDF5File_getObjectType(data, type, &converted);
-  auto converted_ = make_xsafe(converted);
-
-  if (is_array < 0) { ///< error condition, signal
-    const char* filename = "<unknown>";
-    try{ filename = self->f->filename().c_str(); } catch(...){}
-    PyErr_Format(PyExc_TypeError, "error replacing position %" PY_FORMAT_SIZE_T "d of dataset `%s' at HDF5 file `%s': no support for storing objects of type `%s' on HDF5 files", pos, path, filename, Py_TYPE(data)->tp_name);
-    return 0;
-  }
-
-  if (!is_array) { //write as a scalar
-
-    switch(type.type()) {
-      case bob::io::base::s:
-        {
-          auto value = PyBobIo_GetString(data);
-          if (!value) return 0;
-          self->f->replace<std::string>(path, pos, value.get());
-          Py_RETURN_NONE;
-        }
-      case bob::io::base::b:
-        return PyBobIoHDF5File_replaceScalar<bool>(self, path, pos, data);
-      case bob::io::base::i8:
-        return PyBobIoHDF5File_replaceScalar<int8_t>(self, path, pos, data);
-      case bob::io::base::i16:
-        return PyBobIoHDF5File_replaceScalar<int16_t>(self, path, pos, data);
-      case bob::io::base::i32:
-        return PyBobIoHDF5File_replaceScalar<int32_t>(self, path, pos, data);
-      case bob::io::base::i64:
-        return PyBobIoHDF5File_replaceScalar<int64_t>(self, path, pos, data);
-      case bob::io::base::u8:
-        return PyBobIoHDF5File_replaceScalar<uint8_t>(self, path, pos, data);
-      case bob::io::base::u16:
-        return PyBobIoHDF5File_replaceScalar<uint16_t>(self, path, pos, data);
-      case bob::io::base::u32:
-        return PyBobIoHDF5File_replaceScalar<uint32_t>(self, path, pos, data);
-      case bob::io::base::u64:
-        return PyBobIoHDF5File_replaceScalar<uint64_t>(self, path, pos, data);
-      case bob::io::base::f32:
-        return PyBobIoHDF5File_replaceScalar<float>(self, path, pos, data);
-      case bob::io::base::f64:
-        return PyBobIoHDF5File_replaceScalar<double>(self, path, pos, data);
-      case bob::io::base::f128:
-        return PyBobIoHDF5File_replaceScalar<long double>(self, path, pos, data);
-      case bob::io::base::c64:
-        return PyBobIoHDF5File_replaceScalar<std::complex<float> >(self, path, pos, data);
-      case bob::io::base::c128:
-        return PyBobIoHDF5File_replaceScalar<std::complex<double> >(self, path, pos, data);
-      case bob::io::base::c256:
-        return PyBobIoHDF5File_replaceScalar<std::complex<long double> >(self, path, pos, data);
-      default:
-        break;
-    }
-
-  }
-
-  else { //write as array
-
-    switch (is_array) {
-      case 1: //bob.blitz.array
-        self->f->write_buffer(path, pos, type, ((PyBlitzArrayObject*)data)->data);
-        break;
-
-      case 2: //numpy.ndarray
-        self->f->write_buffer(path, pos, type, PyArray_DATA((PyArrayObject*)data));
-        break;
-
-      case 3: //converted numpy.ndarray
-        self->f->write_buffer(path, pos, type, PyArray_DATA((PyArrayObject*)converted));
-        break;
-
-      default:
-        const char* filename = "<unknown>";
-        try{ filename = self->f->filename().c_str(); } catch(...){}
-        PyErr_Format(PyExc_NotImplementedError, "error replacing position %" PY_FORMAT_SIZE_T "d of dataset `%s' at HDF5 file `%s': HDF5 replace function is uncovered for array type %d (DEBUG ME)", pos, path, filename, is_array);
-        return 0;
-    }
-
-  }
-
-  Py_RETURN_NONE;
-BOB_CATCH_MEMBER(exception_message(self, s_replace.name()).c_str(), 0)
-}
-
-
-template <typename T>
-static int PyBobIoHDF5File_appendScalar(PyBobIoHDF5FileObject* self,
-    const char* path, PyObject* o) {
-
-  T value = PyBlitzArrayCxx_AsCScalar<T>(o);
-  if (PyErr_Occurred()) return 0;
-  self->f->append(path, value);
-
-  return 1;
-
-}
-
-static int PyBobIoHDF5File_innerAppend(PyBobIoHDF5FileObject* self, const char* path, PyObject* data, Py_ssize_t compression) {
-
-  bob::io::base::HDF5Type type;
-  PyObject* converted = 0;
-  int is_array = PyBobIoHDF5File_getObjectType(data, type, &converted);
-  auto converted_ = make_xsafe(converted);
-
-  if (is_array < 0) { ///< error condition, signal
-    const char* filename = "<unknown>";
-    try{ filename = self->f->filename().c_str(); } catch(...){}
-    PyErr_Format(PyExc_TypeError, "error appending to object `%s' of HDF5 file `%s': no support for storing objects of type `%s' on HDF5 files", path, filename, Py_TYPE(data)->tp_name);
-    return 0;
-  }
-
-  try {
-
-    if (!is_array) { //write as a scalar
-
-      switch(type.type()) {
-        case bob::io::base::s:
-          {
-            auto value = PyBobIo_GetString(data);
-            if (!value) return 0;
-            self->f->append<std::string>(path, value.get());
-            return 1;
-          }
-        case bob::io::base::b:
-          return PyBobIoHDF5File_appendScalar<bool>(self, path, data);
-        case bob::io::base::i8:
-          return PyBobIoHDF5File_appendScalar<int8_t>(self, path, data);
-        case bob::io::base::i16:
-          return PyBobIoHDF5File_appendScalar<int16_t>(self, path, data);
-        case bob::io::base::i32:
-          return PyBobIoHDF5File_appendScalar<int32_t>(self, path, data);
-        case bob::io::base::i64:
-          return PyBobIoHDF5File_appendScalar<int64_t>(self, path, data);
-        case bob::io::base::u8:
-          return PyBobIoHDF5File_appendScalar<uint8_t>(self, path, data);
-        case bob::io::base::u16:
-          return PyBobIoHDF5File_appendScalar<uint16_t>(self, path, data);
-        case bob::io::base::u32:
-          return PyBobIoHDF5File_appendScalar<uint32_t>(self, path, data);
-        case bob::io::base::u64:
-          return PyBobIoHDF5File_appendScalar<uint64_t>(self, path, data);
-        case bob::io::base::f32:
-          return PyBobIoHDF5File_appendScalar<float>(self, path, data);
-        case bob::io::base::f64:
-          return PyBobIoHDF5File_appendScalar<double>(self, path, data);
-        case bob::io::base::f128:
-          return PyBobIoHDF5File_appendScalar<long double>(self, path, data);
-        case bob::io::base::c64:
-          return PyBobIoHDF5File_appendScalar<std::complex<float> >(self, path, data);
-        case bob::io::base::c128:
-          return PyBobIoHDF5File_appendScalar<std::complex<double> >(self, path, data);
-        case bob::io::base::c256:
-          return PyBobIoHDF5File_appendScalar<std::complex<long double> >(self, path, data);
-        default:
-          break;
-      }
-
-    }
-
-    else { //write as array
-
-      switch (is_array) {
-        case 1: //bob.blitz.array
-          if (!self->f->contains(path)) self->f->create(path, type, true, compression);
-          self->f->extend_buffer(path, type, ((PyBlitzArrayObject*)data)->data);
-          break;
-
-        case 2: //numpy.ndarray
-          if (!self->f->contains(path)) self->f->create(path, type, true, compression);
-          self->f->extend_buffer(path, type, PyArray_DATA((PyArrayObject*)data));
-          break;
-
-        case 3: //converted numpy.ndarray
-          if (!self->f->contains(path)) self->f->create(path, type, true, compression);
-          self->f->extend_buffer(path, type, PyArray_DATA((PyArrayObject*)converted));
-          break;
-
-        default:{
-          const char* filename = "<unknown>";
-          try{ filename = self->f->filename().c_str(); } catch(...){}
-          PyErr_Format(PyExc_NotImplementedError, "error appending to object `%s' at HDF5 file `%s': HDF5 replace function is uncovered for array type %d (DEBUG ME)", path, filename, is_array);
-          return 0;
-        }
-      }
-
-    }
-
-  }
-  catch (std::exception& e) {
-    PyErr_SetString(PyExc_RuntimeError, e.what());
-    return 0;
-  }
-  catch (...) {
-    const char* filename = "<unknown>";
-    try{ filename = self->f->filename().c_str(); } catch(...){}
-    PyErr_Format(PyExc_RuntimeError, "cannot append to object `%s' at HDF5 file `%s': unknown exception caught", path, filename);
-    return 0;
-  }
-
-  return 1;
-
-}
-
-
-static auto s_append = bob::extension::FunctionDoc(
-  "append",
-  "Appends a scalar or an array to a dataset",
-  "The object must be compatible with the typing information on the dataset, or an exception will be raised. "
-  "You can also, optionally, set this to an iterable of scalars or arrays. "
-  "This will cause this method to iterate over the elements and add each individually.\n\n"
-  "The ``compression`` parameter is effective when appending arrays. "
-  "Set this to a number betwen 0 (default) and 9 (maximum) to compress the contents of this dataset. "
-  "This setting is only effective if the dataset does not yet exist, otherwise, the previous setting is respected.",
-  true
-)
-.add_prototype("path, data, [compression]")
-.add_parameter("path", "str", "The path to the dataset to append data at; can be an absolute value (starting with a leading ``'/'``) or relative to the current working directory :py:attr:`cwd`")
-.add_parameter("data", ":py:class:`numpy.ndarray` or scalar", "Object to append to the dataset")
-.add_parameter("compression", "int", "A compression value between 0 and 9")
-;
-static PyObject* PyBobIoHDF5File_append(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static char** kwlist = s_append.kwlist();
-
-  char* path = 0;
-  PyObject* data = 0;
-  Py_ssize_t compression = 0;
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "sO|n", kwlist, &path, &data, &compression)) return 0;
-
-  if (compression < 0 || compression > 9) {
-    PyErr_SetString(PyExc_ValueError, "compression should be set to an integer value between and including 0 and 9");
-    return 0;
-  }
-
-  // special case: user passes a tuple or list of arrays or scalars to append
-  if (PyTuple_Check(data) || PyList_Check(data)) {
-    PyObject* iter = PyObject_GetIter(data);
-    if (!iter) return 0;
-    auto iter_ = make_safe(iter);
-    while (PyObject* item = PyIter_Next(iter)) {
-      auto item_ = make_safe(item);
-      int ok = PyBobIoHDF5File_innerAppend(self, path, item, compression);
-      if (!ok) return 0;
-    }
-    Py_RETURN_NONE;
-  }
-
-  int ok = PyBobIoHDF5File_innerAppend(self, path, data, compression);
-  if (!ok) return 0;
-  Py_RETURN_NONE;
-BOB_CATCH_MEMBER(exception_message(self, s_append.name()).c_str(), 0)
-}
-
-
-template <typename T>
-static PyObject* PyBobIoHDF5File_setScalar(PyBobIoHDF5FileObject* self,
-    const char* path, PyObject* o) {
-
-  T value = PyBlitzArrayCxx_AsCScalar<T>(o);
-  if (PyErr_Occurred()) return 0;
-  self->f->set(path, value);
-
-  Py_RETURN_NONE;
-
-}
-
-
-static auto s_set = bob::extension::FunctionDoc(
-  "set",
-  "Sets the scalar or array at position 0 to the given value",
-  "This method is equivalent to checking if the scalar or array at position 0 exists and then replacing it. "
-  "If the path does not exist, we append the new scalar or array.\n\n"
-  "The ``data`` must be compatible with the typing information on the dataset, or an exception will be raised. "
-  "You can also, optionally, set this to an iterable of scalars or arrays. "
-  "This will cause this method to iterate over the elements and add each individually.\n\n"
-  "The ``compression`` parameter is effective when writing arrays. "
-  "Set this to a number betwen 0 (default) and 9 (maximum) to compress the contents of this dataset. "
-  "This setting is only effective if the dataset does not yet exist, otherwise, the previous setting is respected.\n\n"
-  ".. note:: The functions :py:meth:`set` and :py:meth:`write` are synonyms.",
-  true
-)
-.add_prototype("path, data, [compression]")
-.add_parameter("path", "str", "The path to the dataset to write data to; can be an absolute value (starting with a leading ``'/'``) or relative to the current working directory :py:attr:`cwd`")
-.add_parameter("data", ":py:class:`numpy.ndarray` or scalar", "Object to write to the dataset")
-.add_parameter("compression", "int", "A compression value between 0 and 9")
-;
-auto s_write = s_set.clone("write");
-static PyObject* PyBobIoHDF5File_set(PyBobIoHDF5FileObject* self, PyObject* args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static const char* const_kwlist[] = {"path", "data", "compression", 0};
-  static char** kwlist = const_cast<char**>(const_kwlist);
-
-  char* path = 0;
-  PyObject* data = 0;
-  Py_ssize_t compression = 0;
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "sO|n", kwlist, &path, &data, &compression)) return 0;
-
-  if (compression < 0 || compression > 9) {
-    PyErr_SetString(PyExc_ValueError, "compression should be set to an integer value between and including 0 and 9");
-    return 0;
-  }
-
-  bob::io::base::HDF5Type type;
-  PyObject* converted = 0;
-  int is_array = PyBobIoHDF5File_getObjectType(data, type, &converted);
-  auto converted_ = make_xsafe(converted);
-
-  if (is_array < 0) { ///< error condition, signal
-    const char* filename = "<unknown>";
-    try{ filename = self->f->filename().c_str(); } catch(...){}
-    PyErr_Format(PyExc_TypeError, "error setting object `%s' of HDF5 file `%s': no support for storing objects of type `%s' on HDF5 files", path, filename, Py_TYPE(data)->tp_name);
-    return 0;
-  }
-
-  if (!is_array) { //write as a scalar
-
-    switch(type.type()) {
-      case bob::io::base::s:
-        {
-          auto value = PyBobIo_GetString(data);
-          if (!value) return 0;
-          self->f->set<std::string>(path, value.get());
-          Py_RETURN_NONE;
-        }
-        break;
-      case bob::io::base::b:
-        return PyBobIoHDF5File_setScalar<bool>(self, path, data);
-      case bob::io::base::i8:
-        return PyBobIoHDF5File_setScalar<int8_t>(self, path, data);
-      case bob::io::base::i16:
-        return PyBobIoHDF5File_setScalar<int16_t>(self, path, data);
-      case bob::io::base::i32:
-        return PyBobIoHDF5File_setScalar<int32_t>(self, path, data);
-      case bob::io::base::i64:
-        return PyBobIoHDF5File_setScalar<int64_t>(self, path, data);
-      case bob::io::base::u8:
-        return PyBobIoHDF5File_setScalar<uint8_t>(self, path, data);
-      case bob::io::base::u16:
-        return PyBobIoHDF5File_setScalar<uint16_t>(self, path, data);
-      case bob::io::base::u32:
-        return PyBobIoHDF5File_setScalar<uint32_t>(self, path, data);
-      case bob::io::base::u64:
-        return PyBobIoHDF5File_setScalar<uint64_t>(self, path, data);
-      case bob::io::base::f32:
-        return PyBobIoHDF5File_setScalar<float>(self, path, data);
-      case bob::io::base::f64:
-        return PyBobIoHDF5File_setScalar<double>(self, path, data);
-      case bob::io::base::f128:
-        return PyBobIoHDF5File_setScalar<long double>(self, path, data);
-      case bob::io::base::c64:
-        return PyBobIoHDF5File_setScalar<std::complex<float> >(self, path, data);
-      case bob::io::base::c128:
-        return PyBobIoHDF5File_setScalar<std::complex<double> >(self, path, data);
-      case bob::io::base::c256:
-        return PyBobIoHDF5File_setScalar<std::complex<long double> >(self, path, data);
-      default:
-        break;
-    }
-
-  }
-
-  else { //write as array
-
-    switch (is_array) {
-      case 1: //bob.blitz.array
-        if (!self->f->contains(path)) self->f->create(path, type, false, compression);
-        self->f->write_buffer(path, 0, type, ((PyBlitzArrayObject*)data)->data);
-        break;
-
-      case 2: //numpy.ndarray
-        if (!self->f->contains(path)) self->f->create(path, type, false, compression);
-        self->f->write_buffer(path, 0, type, PyArray_DATA((PyArrayObject*)data));
-        break;
-
-      case 3: //converted numpy.ndarray
-        if (!self->f->contains(path)) self->f->create(path, type, false, compression);
-        self->f->write_buffer(path, 0, type, PyArray_DATA((PyArrayObject*)converted));
-        break;
-
-      default:
-        const char* filename = "<unknown>";
-        try{ filename = self->f->filename().c_str(); } catch(...){}
-        PyErr_Format(PyExc_NotImplementedError, "error setting object `%s' at HDF5 file `%s': HDF5 replace function is uncovered for array type %d (DEBUG ME)", path, filename, is_array);
-        return 0;
-    }
-
-  }
-
-  Py_RETURN_NONE;
-BOB_CATCH_MEMBER(exception_message(self, s_set.name()).c_str(), 0)
-}
-
-
-static auto s_copy = bob::extension::FunctionDoc(
-  "copy",
-  "Copies all accessible content to another HDF5 file",
-  "Unlinked contents of this file will not be copied. "
-  "This can be used as a method to trim unwanted content in a file.",
-  true
-)
-.add_prototype("hdf5")
-.add_parameter("hdf5", ":py:class:`HDF5File`", "The HDF5 file (already opened for writing), to copy the contents to")
-;
-static PyObject* PyBobIoHDF5File_copy(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static char** kwlist = s_copy.kwlist();
-
-  PyBobIoHDF5FileObject* other = 0;
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&", kwlist, &PyBobIoHDF5File_Converter, &other)) return 0;
-
-  self->f->copy(*other->f);
-
-  Py_RETURN_NONE;
-BOB_CATCH_MEMBER(exception_message(self, s_copy.name()).c_str(), 0)
-}
-
-
-template <typename T> static PyObject* PyBobIoHDF5File_readScalarAttribute
-(PyBobIoHDF5FileObject* self, const char* path, const char* name,
- const bob::io::base::HDF5Type& type) {
-  T value;
-  self->f->read_attribute(path, name, type, static_cast<void*>(&value));
-  return PyBlitzArrayCxx_FromCScalar(value);
-}
-
-template <> PyObject* PyBobIoHDF5File_readScalarAttribute<const char*>
-(PyBobIoHDF5FileObject* self, const char* path, const char* name,
- const bob::io::base::HDF5Type& type) {
-  std::string retval;
-  self->f->getAttribute(path, name, retval);
-  return Py_BuildValue("s", retval.c_str());
-}
-
-static PyObject* PyBobIoHDF5File_readAttribute(PyBobIoHDF5FileObject* self,
-    const char* path, const char* name, const bob::io::base::HDF5Type& type) {
-
-  //no error detection: this should be done before reaching this method
-
-  const bob::io::base::HDF5Shape& shape = type.shape();
-
-  if (type.type() == bob::io::base::s || (shape.n() == 1 && shape[0] == 1)) {
-    //read as scalar
-    switch(type.type()) {
-      case bob::io::base::s:
-        return PyBobIoHDF5File_readScalarAttribute<const char*>(self, path, name, type);
-      case bob::io::base::b:
-        return PyBobIoHDF5File_readScalarAttribute<bool>(self, path, name, type);
-      case bob::io::base::i8:
-        return PyBobIoHDF5File_readScalarAttribute<int8_t>(self, path, name, type);
-      case bob::io::base::i16:
-        return PyBobIoHDF5File_readScalarAttribute<int16_t>(self, path, name, type);
-      case bob::io::base::i32:
-        return PyBobIoHDF5File_readScalarAttribute<int32_t>(self, path, name, type);
-      case bob::io::base::i64:
-        return PyBobIoHDF5File_readScalarAttribute<int64_t>(self, path, name, type);
-      case bob::io::base::u8:
-        return PyBobIoHDF5File_readScalarAttribute<uint8_t>(self, path, name, type);
-      case bob::io::base::u16:
-        return PyBobIoHDF5File_readScalarAttribute<uint16_t>(self, path, name, type);
-      case bob::io::base::u32:
-        return PyBobIoHDF5File_readScalarAttribute<uint32_t>(self, path, name, type);
-      case bob::io::base::u64:
-        return PyBobIoHDF5File_readScalarAttribute<uint64_t>(self, path, name, type);
-      case bob::io::base::f32:
-        return PyBobIoHDF5File_readScalarAttribute<float>(self, path, name, type);
-      case bob::io::base::f64:
-        return PyBobIoHDF5File_readScalarAttribute<double>(self, path, name, type);
-      case bob::io::base::f128:
-        return PyBobIoHDF5File_readScalarAttribute<long double>(self, path, name, type);
-      case bob::io::base::c64:
-        return PyBobIoHDF5File_readScalarAttribute<std::complex<float> >(self, path, name, type);
-      case bob::io::base::c128:
-        return PyBobIoHDF5File_readScalarAttribute<std::complex<double> >(self, path, name, type);
-      case bob::io::base::c256:
-        return PyBobIoHDF5File_readScalarAttribute<std::complex<long double> >(self, path, name, type);
-      default:
-        break;
-    }
-  }
-
-  //read as an numpy array
-  int type_num = PyBobIo_H5AsTypenum(type.type());
-  if (type_num == NPY_NOTYPE) return 0; ///< failure
-
-  npy_intp pyshape[NPY_MAXDIMS];
-  for (size_t k=0; k<shape.n(); ++k) pyshape[k] = shape.get()[k];
-
-  PyObject* retval = PyArray_SimpleNew(shape.n(), pyshape, type_num);
-  if (!retval) return 0;
-  auto retval_ = make_safe(retval);
-
-  self->f->read_attribute(path, name, type, PyArray_DATA((PyArrayObject*)retval));
-
-  return Py_BuildValue("O", retval);
-}
-
-
-static auto s_get_attribute = bob::extension::FunctionDoc(
-  "get_attribute",
-  "Retrieve a given attribute from the named resource",
-  "This method returns a single value corresponding to what is stored inside the attribute container for the given resource. "
-  "If you would like to retrieve all attributes at once, use :py:meth:`get_attributes` instead.",
-  true
-)
-.add_prototype("name, [path]", "attribute")
-.add_parameter("name", "str", "The name of the attribute to retrieve; if the attribute is not available, a ``RuntimeError`` is raised")
-.add_parameter("path", "str", "[Default: ``'.'``] The path leading to the resource (dataset or group|directory) you would like to get an attribute from; if the path does not exist, a ``RuntimeError`` is raised")
-.add_return("attribute", ":py:class:`numpy.ndarray` or scalar", "The read attribute")
-;
-static PyObject* PyBobIoHDF5File_getAttribute(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static char** kwlist = s_get_attribute.kwlist();
-
-  const char* name = 0;
-  const char* path = ".";
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|s", kwlist, &name, &path)) return 0;
-
-  bob::io::base::HDF5Type type;
-
-  self->f->getAttributeType(path, name, type);
-
-  if (type.type() == bob::io::base::unsupported) {
-    const char* filename = "<unknown>";
-    try{ filename = self->f->filename().c_str(); } catch(...){}
-    boost::format m("unsupported HDF5 data type detected for attribute `%s' at path `%s' of file `%s' - returning None");
-    m % name % path % filename;
-    PyErr_Warn(PyExc_UserWarning, m.str().c_str());
-    Py_RETURN_NONE;
-  }
-
-  return PyBobIoHDF5File_readAttribute(self, path, name, type);
-BOB_CATCH_MEMBER(exception_message(self, s_get_attribute.name()).c_str(), 0)
-}
-
-
-static auto s_get_attributes = bob::extension::FunctionDoc(
-  "get_attributes",
-  "Reads all attributes of the given path",
-  "Attributes are returned in a dictionary in which each key corresponds to the attribute name and each value corresponds to the value stored inside the HDF5 file. "
-  "To retrieve only a specific attribute, use :py:meth:`get_attribute`.",
-  true
-)
-.add_prototype("[path]", "attributes")
-.add_parameter("path", "str", "[Default: ``'.'``] The path leading to the resource (dataset or group|directory) you would like to get all attributes from; if the path does not exist, a ``RuntimeError`` is raised.")
-.add_return("attributes", "{str:value}", "The attributes organized in dictionary, where ``value`` might be a :py:class:`numpy.ndarray` or a scalar")
-;
-static PyObject* PyBobIoHDF5File_getAttributes(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static char** kwlist = s_get_attributes.kwlist();
-
-  const char* path = ".";
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s", kwlist, &path)) return 0;
-
-  std::map<std::string, bob::io::base::HDF5Type> attributes;
-  self->f->listAttributes(path, attributes);
-  PyObject* retval = PyDict_New();
-  if (!retval) return 0;
-  auto retval_ = make_safe(retval);
-
-  for (auto k=attributes.begin(); k!=attributes.end(); ++k) {
-    PyObject* item = 0;
-    if (k->second.type() == bob::io::base::unsupported) {
-      const char* filename = "<unknown>";
-      try{ filename = self->f->filename().c_str(); } catch(...){}
-      boost::format m("unsupported HDF5 data type detected for attribute `%s' at path `%s' of file `%s' - returning None");
-      m % k->first % k->second.str() % filename;
-      PyErr_Warn(PyExc_UserWarning, m.str().c_str());
-      item = Py_BuildValue("");
-    }
-    else item = PyBobIoHDF5File_readAttribute(self, path, k->first.c_str(), k->second);
-
-    if (!item) return 0;
-    auto item_ = make_safe(item);
-
-    if (PyDict_SetItemString(retval, k->first.c_str(), item) != 0) return 0;
-  }
-
-  return Py_BuildValue("O", retval);
-BOB_CATCH_MEMBER(exception_message(self, s_get_attributes.name()).c_str(), 0)
-}
-
-
-template <typename T> PyObject* PyBobIoHDF5File_writeScalarAttribute(PyBobIoHDF5FileObject* self, const char* path, const char* name, const bob::io::base::HDF5Type& type, PyObject* o) {
-  T value = PyBlitzArrayCxx_AsCScalar<T>(o);
-  if (PyErr_Occurred()) return 0;
-
-  self->f->write_attribute(path, name, type, static_cast<void*>(&value));
-
-  Py_RETURN_NONE;
-}
-
-template <> PyObject* PyBobIoHDF5File_writeScalarAttribute<const char*>(PyBobIoHDF5FileObject* self, const char* path, const char* name, const bob::io::base::HDF5Type& type, PyObject* o) {
-  auto value = PyBobIo_GetString(o);
-  if (!value) return 0;
-  self->f->write_attribute(path, name, type, static_cast<const void*>(value.get()));
-  Py_RETURN_NONE;
-}
-
-static PyObject* PyBobIoHDF5File_writeAttribute(PyBobIoHDF5FileObject* self,
-    const char* path, const char* name, const bob::io::base::HDF5Type& type,
-    PyObject* o, int is_array, PyObject* converted) {
-
-  //no error detection: this should be done before reaching this method
-
-  if (!is_array) { //write as a scalar
-    switch(type.type()) {
-      case bob::io::base::s:
-        return PyBobIoHDF5File_writeScalarAttribute<const char*>(self, path, name, type, o);
-      case bob::io::base::b:
-        return PyBobIoHDF5File_writeScalarAttribute<bool>(self, path, name, type, o);
-      case bob::io::base::i8:
-        return PyBobIoHDF5File_writeScalarAttribute<int8_t>(self, path, name, type, o);
-      case bob::io::base::i16:
-        return PyBobIoHDF5File_writeScalarAttribute<int16_t>(self, path, name, type, o);
-      case bob::io::base::i32:
-        return PyBobIoHDF5File_writeScalarAttribute<int32_t>(self, path, name, type, o);
-      case bob::io::base::i64:
-        return PyBobIoHDF5File_writeScalarAttribute<int64_t>(self, path, name, type, o);
-      case bob::io::base::u8:
-        return PyBobIoHDF5File_writeScalarAttribute<uint8_t>(self, path, name, type, o);
-      case bob::io::base::u16:
-        return PyBobIoHDF5File_writeScalarAttribute<uint16_t>(self, path, name, type, o);
-      case bob::io::base::u32:
-        return PyBobIoHDF5File_writeScalarAttribute<uint32_t>(self, path, name, type, o);
-      case bob::io::base::u64:
-        return PyBobIoHDF5File_writeScalarAttribute<uint64_t>(self, path, name, type, o);
-      case bob::io::base::f32:
-        return PyBobIoHDF5File_writeScalarAttribute<float>(self, path, name, type, o);
-      case bob::io::base::f64:
-        return PyBobIoHDF5File_writeScalarAttribute<double>(self, path, name, type, o);
-      case bob::io::base::f128:
-        return PyBobIoHDF5File_writeScalarAttribute<long double>(self, path, name, type, o);
-      case bob::io::base::c64:
-        return PyBobIoHDF5File_writeScalarAttribute<std::complex<float> >(self, path, name, type, o);
-      case bob::io::base::c128:
-        return PyBobIoHDF5File_writeScalarAttribute<std::complex<double> >(self, path, name, type, o);
-      case bob::io::base::c256:
-        return PyBobIoHDF5File_writeScalarAttribute<std::complex<long double> >(self, path, name, type, o);
-      default:
-        break;
-    }
-  }
-
-  else { //write as an numpy array
-
-    switch (is_array) {
-
-      case 1: //bob.blitz.array
-        self->f->write_attribute(path, name, type, ((PyBlitzArrayObject*)o)->data);
-        break;
-
-      case 2: //numpy.ndarray
-        self->f->write_attribute(path, name, type, PyArray_DATA((PyArrayObject*)o));
-        break;
-
-      case 3: //converted numpy.ndarray
-        self->f->write_attribute(path, name, type, PyArray_DATA((PyArrayObject*)converted));
-        break;
-
-      default:{
-        const char* filename = "<unknown>";
-        try{ filename = self->f->filename().c_str(); } catch(...){}
-        PyErr_Format(PyExc_NotImplementedError, "error setting attribute `%s' at resource `%s' of HDF5 file `%s': HDF5 attribute setting function is uncovered for array type %d (DEBUG ME)", name, path, filename, is_array);
-        return 0;
-      }
-    }
-  }
-  Py_RETURN_NONE;
-}
-
-static auto s_set_attribute = bob::extension::FunctionDoc(
-  "set_attribute",
-  "Sets a given attribute at the named resource",
-  "Only simple  scalars (booleans, integers, floats and complex numbers) and arrays of those are supported at the time being. "
-  "You can use :py:mod:`numpy` scalars to set values with arbitrary precision (e.g. :py:class:`numpy.uint8`).\n\n"
-  ".. warning:: Attributes in HDF5 files are supposed to be small containers or simple scalars that provide extra information about the data stored on the main resource (dataset or group|directory). "
-  "Attributes cannot be retrieved in chunks, contrary to data in datasets. "
-  "Currently, **no limitations** for the size of values stored on attributes is imposed.",
-  true
-)
-.add_prototype("name, value, [path]")
-.add_parameter("name", "str", "The name of the attribute to set")
-.add_parameter("value", ":py:class:`numpy.ndarray` or scalar", "A simple scalar to set for the given attribute on the named resources ``path``")
-.add_parameter("path", "str", "[Default: ``'.'``] The path leading to the resource (dataset or group|directory) you would like to set an attribute at")
-;
-static PyObject* PyBobIoHDF5File_setAttribute(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static char** kwlist = s_set_attribute.kwlist();
-
-  const char* name = 0;
-  PyObject* value = 0;
-  const char* path = ".";
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "sO|s", kwlist, &name, &value, &path)) return 0;
-
-  bob::io::base::HDF5Type type;
-  PyObject* converted = 0;
-  int is_array = PyBobIoHDF5File_getObjectType(value, type, &converted);
-  auto converted_ = make_xsafe(converted);
-
-  if (is_array < 0) { ///< error condition, signal
-    const char* filename = "<unknown>";
-    try{ filename = self->f->filename().c_str(); } catch(...){}
-    PyErr_Format(PyExc_TypeError, "error setting attribute `%s' of resource `%s' at HDF5 file `%s': no support for storing objects of type `%s' on HDF5 files", name, path, filename, Py_TYPE(value)->tp_name);
-    return 0;
-  }
-
-  return PyBobIoHDF5File_writeAttribute(self, path, name, type, value, is_array, converted);
-BOB_CATCH_MEMBER(exception_message(self, s_set_attribute.name()).c_str(), 0)
-}
-
-
-static auto s_set_attributes = bob::extension::FunctionDoc(
-  "set_attributes",
-  "Sets several attribute at the named resource using a dictionary",
-  "Each value in the dictionary should be simple scalars (booleans, integers, floats and complex numbers) or arrays of those are supported at the time being. "
-  "You can use :py:mod:`numpy` scalars to set values with arbitrary precision (e.g. :py:class:`numpy.uint8`).\n\n"
-  ".. warning:: Attributes in HDF5 files are supposed to be small containers or simple scalars that provide extra information about the data stored on the main resource (dataset or group|directory). "
-  "Attributes cannot be retrieved in chunks, contrary to data in datasets. "
-  "Currently, **no limitations** for the size of values stored on attributes is imposed.",
-  true
-)
-.add_prototype("attributes, [path]")
-.add_parameter("attributes", "{str: value}", "A python dictionary containing pairs of strings and values, which can be a py:class:`numpy.ndarray` or a scalar")
-.add_parameter("path", "str", "[Default: ``'.'``] The path leading to the resource (dataset or group|directory) you would like to set attributes at")
-;
-static PyObject* PyBobIoHDF5File_setAttributes(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static char** kwlist = s_set_attributes.kwlist();
-
-  PyObject* attrs = 0;
-  const char* path = ".";
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|s", kwlist, &attrs, &path)) return 0;
-
-  if (!PyDict_Check(attrs)) {
-    PyErr_Format(PyExc_TypeError, "parameter `%s' should be a dictionary where keys are strings and values are the attribute values", kwlist[0]);
-    return 0;
-  }
-
-  PyObject *key, *value;
-  Py_ssize_t pos = 0;
-  while (PyDict_Next(attrs, &pos, &key, &value)) {
-    bob::io::base::HDF5Type type;
-    PyObject* converted = 0;
-
-    auto name = PyBobIo_GetString(key);
-    if (!name) return 0;
-
-    int is_array = PyBobIoHDF5File_getObjectType(value, type, &converted);
-    auto converted_ = make_xsafe(converted);
-
-    if (is_array < 0) { ///< error condition, signal
-      const char* filename = "<unknown>";
-      try{ filename = self->f->filename().c_str(); } catch(...){}
-      PyErr_Format(PyExc_TypeError, "error setting attribute `%s' of resource `%s' at HDF5 file `%s': no support for storing objects of type `%s' on HDF5 files", name.get(), path, filename, Py_TYPE(value)->tp_name);
-      return 0;
-    }
-
-    PyObject* retval = PyBobIoHDF5File_writeAttribute(self, path, name.get(), type, value, is_array, converted);
-    if (!retval) return 0;
-    Py_DECREF(retval);
-
-  }
-
-  Py_RETURN_NONE;
-BOB_CATCH_MEMBER(exception_message(self, s_set_attributes.name()).c_str(), 0)
-}
-
-
-static auto s_del_attribute = bob::extension::FunctionDoc(
-  "del_attribute",
-  "Removes a given attribute at the named resource",
-  0,
-  true
-)
-.add_prototype("name, [path]")
-.add_parameter("name", "str", "The name of the attribute to delete; if the attribute is not available, a ``RuntimeError`` is raised")
-.add_parameter("path", "str", "[Default: ``'.'``] The path leading to the resource (dataset or group|directory) you would like to delete an attribute from; if the path does not exist, a ``RuntimeError`` is raised")
-;
-static PyObject* PyBobIoHDF5File_delAttribute(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static char** kwlist = s_del_attribute.kwlist();
-
-  const char* name = 0;
-  const char* path = ".";
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|s", kwlist, &name, &path)) return 0;
-
-  self->f->deleteAttribute(path, name);
-
-  Py_RETURN_NONE;
-BOB_CATCH_MEMBER(exception_message(self, s_del_attribute.name()).c_str(), 0)
-}
-
-
-static auto s_del_attributes = bob::extension::FunctionDoc(
-  "del_attributes",
-  "Removes attributes in a given (existing) path",
-  "If the ``attributes`` are not given or set to ``None``, then remove all attributes at the named resource.",
-  true
-)
-.add_prototype("[attributes], [path]")
-.add_parameter("attributes", "[str] or None", "[Default: ``None``] An iterable containing the names of the attributes to be removed, or ``None``")
-.add_parameter("path", "str", "[Default: ``'.'``] The path leading to the resource (dataset or group|directory) you would like to delete attributes from; if the path does not exist, a ``RuntimeError`` is raised")
-;
-static PyObject* PyBobIoHDF5File_delAttributes(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static char** kwlist = s_del_attributes.kwlist();
-
-  PyObject* attrs = 0;
-  const char* path = ".";
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Os", kwlist, &attrs, &path)) return 0;
-
-  if (attrs && !PyIter_Check(attrs)) {
-    PyErr_Format(PyExc_TypeError, "parameter `%s', if set, must be an iterable of strings", kwlist[0]);
-    return 0;
-  }
-
-  if (attrs) {
-    PyObject* iter = PyObject_GetIter(attrs);
-    if (!iter) return 0;
-    auto iter_ = make_safe(iter);
-    while (PyObject* item = PyIter_Next(iter)) {
-      auto item_ = make_safe(item);
-      auto name = PyBobIo_GetString(item);
-      if (!name) return 0;
-      self->f->deleteAttribute(path, name.get());
-    }
-    Py_RETURN_NONE;
-  }
-
-  //else, find the attributes and remove all of them
-  std::map<std::string, bob::io::base::HDF5Type> attributes;
-  self->f->listAttributes(path, attributes);
-  for (auto k=attributes.begin(); k!=attributes.end(); ++k) {
-    self->f->deleteAttribute(path, k->first);
-  }
-
-  Py_RETURN_NONE;
-BOB_CATCH_MEMBER(exception_message(self, s_del_attributes.name()).c_str(), 0)
-}
-
-
-static auto s_has_attribute = bob::extension::FunctionDoc(
-  "has_attribute",
-  "Checks existence of a given attribute at the named resource",
-  0,
-  true
-)
-.add_prototype("name, [path]", "existence")
-.add_parameter("name", "str", "The name of the attribute to check")
-.add_parameter("path", "str", "[Default: ``'.'``] The path leading to the resource (dataset or group|directory) you would like to delete attributes from; if the path does not exist, a ``RuntimeError`` is raised")
-.add_return("existence", "bool", "``True``, if the attribute ``name`` exists, otherwise ``False``")
-;
-static PyObject* PyBobIoHDF5File_hasAttribute(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) {
-BOB_TRY
-  /* Parses input arguments in a single shot */
-  static char** kwlist = s_has_attribute.kwlist();
-
-  const char* name = 0;
-  const char* path = ".";
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|s", kwlist, &name, &path)) return 0;
-
-  if (self->f->hasAttribute(path, name))
-    Py_RETURN_TRUE;
-  Py_RETURN_FALSE;
-
-BOB_CATCH_MEMBER(exception_message(self, s_has_attribute.name()).c_str(), 0)
-}
-
-
-static PyMethodDef PyBobIoHDF5File_methods[] = {
-  {
-    s_close.name(),
-    (PyCFunction)PyBobIoHDF5File_close,
-    METH_VARARGS|METH_KEYWORDS,
-    s_close.doc()
-  },
-  {
-    s_flush.name(),
-    (PyCFunction)PyBobIoHDF5File_flush,
-    METH_VARARGS|METH_KEYWORDS,
-    s_flush.doc()
-  },
-  {
-    s_cd.name(),
-    (PyCFunction)PyBobIoHDF5File_changeDirectory,
-    METH_VARARGS|METH_KEYWORDS,
-    s_cd.doc(),
-  },
-  {
-    s_has_group.name(),
-    (PyCFunction)PyBobIoHDF5File_hasGroup,
-    METH_VARARGS|METH_KEYWORDS,
-    s_has_group.doc(),
-  },
-  {
-    s_create_group.name(),
-    (PyCFunction)PyBobIoHDF5File_createGroup,
-    METH_VARARGS|METH_KEYWORDS,
-    s_create_group.doc(),
-  },
-  {
-    s_has_dataset.name(),
-    (PyCFunction)PyBobIoHDF5File_hasDataset,
-    METH_VARARGS|METH_KEYWORDS,
-    s_has_dataset.doc(),
-  },
-  {
-    s_has_key.name(),
-    (PyCFunction)PyBobIoHDF5File_hasDataset,
-    METH_VARARGS|METH_KEYWORDS,
-    s_has_key.doc(),
-  },
-  {
-    s_describe.name(),
-    (PyCFunction)PyBobIoHDF5File_describe,
-    METH_VARARGS|METH_KEYWORDS,
-    s_describe.doc(),
-  },
-  {
-    s_unlink.name(),
-    (PyCFunction)PyBobIoHDF5File_unlink,
-    METH_VARARGS|METH_KEYWORDS,
-    s_unlink.doc(),
-  },
-  {
-    s_rename.name(),
-    (PyCFunction)PyBobIoHDF5File_rename,
-    METH_VARARGS|METH_KEYWORDS,
-    s_rename.doc(),
-  },
-  {
-    s_paths.name(),
-    (PyCFunction)PyBobIoHDF5File_paths,
-    METH_VARARGS|METH_KEYWORDS,
-    s_paths.doc(),
-  },
-  {
-    s_keys.name(),
-    (PyCFunction)PyBobIoHDF5File_paths,
-    METH_VARARGS|METH_KEYWORDS,
-    s_keys.doc(),
-  },
-  {
-    s_sub_groups.name(),
-    (PyCFunction)PyBobIoHDF5File_subGroups,
-    METH_VARARGS|METH_KEYWORDS,
-    s_sub_groups.doc(),
-  },
-  {
-    s_read.name(),
-    (PyCFunction)PyBobIoHDF5File_read,
-    METH_VARARGS|METH_KEYWORDS,
-    s_read.doc(),
-  },
-  {
-    s_get.name(),
-    (PyCFunction)PyBobIoHDF5File_read,
-    METH_VARARGS|METH_KEYWORDS,
-    s_get.doc(),
-  },
-  {
-    s_lread.name(),
-    (PyCFunction)PyBobIoHDF5File_listRead,
-    METH_VARARGS|METH_KEYWORDS,
-    s_lread.doc(),
-  },
-  {
-    s_replace.name(),
-    (PyCFunction)PyBobIoHDF5File_replace,
-    METH_VARARGS|METH_KEYWORDS,
-    s_replace.doc(),
-  },
-  {
-    s_append.name(),
-    (PyCFunction)PyBobIoHDF5File_append,
-    METH_VARARGS|METH_KEYWORDS,
-    s_append.doc(),
-  },
-  {
-    s_set.name(),
-    (PyCFunction)PyBobIoHDF5File_set,
-    METH_VARARGS|METH_KEYWORDS,
-    s_set.doc(),
-  },
-  {
-    s_write.name(),
-    (PyCFunction)PyBobIoHDF5File_set,
-    METH_VARARGS|METH_KEYWORDS,
-    s_write.doc(),
-  },
-  {
-    s_copy.name(),
-    (PyCFunction)PyBobIoHDF5File_copy,
-    METH_VARARGS|METH_KEYWORDS,
-    s_copy.doc(),
-  },
-  {
-    s_get_attribute.name(),
-    (PyCFunction)PyBobIoHDF5File_getAttribute,
-    METH_VARARGS|METH_KEYWORDS,
-    s_get_attribute.doc(),
-  },
-  {
-    s_get_attributes.name(),
-    (PyCFunction)PyBobIoHDF5File_getAttributes,
-    METH_VARARGS|METH_KEYWORDS,
-    s_get_attributes.doc(),
-  },
-  {
-    s_set_attribute.name(),
-    (PyCFunction)PyBobIoHDF5File_setAttribute,
-    METH_VARARGS|METH_KEYWORDS,
-    s_set_attribute.doc(),
-  },
-  {
-    s_set_attributes.name(),
-    (PyCFunction)PyBobIoHDF5File_setAttributes,
-    METH_VARARGS|METH_KEYWORDS,
-    s_set_attributes.doc(),
-  },
-  {
-    s_del_attribute.name(),
-    (PyCFunction)PyBobIoHDF5File_delAttribute,
-    METH_VARARGS|METH_KEYWORDS,
-    s_del_attribute.doc(),
-  },
-  {
-    s_del_attributes.name(),
-    (PyCFunction)PyBobIoHDF5File_delAttributes,
-    METH_VARARGS|METH_KEYWORDS,
-    s_del_attributes.doc(),
-  },
-  {
-    s_has_attribute.name(),
-    (PyCFunction)PyBobIoHDF5File_hasAttribute,
-    METH_VARARGS|METH_KEYWORDS,
-    s_has_attribute.doc(),
-  },
-  {0}  /* Sentinel */
-};
-
-static auto s_cwd = bob::extension::VariableDoc(
-  "cwd",
-  "str",
-  "The current working directory set on the file"
-);
-static PyObject* PyBobIoHDF5File_cwd(PyBobIoHDF5FileObject* self) {
-BOB_TRY
-  return Py_BuildValue("s", self->f->cwd().c_str());
-BOB_CATCH_MEMBER(exception_message(self, s_cwd.name()).c_str(), 0)
-}
-
-static auto s_filename = bob::extension::VariableDoc(
-  "filename",
-  "str",
-  "The name (and path) of the underlying file on hard disk"
-);
-static PyObject* PyBobIoHDF5File_filename(PyBobIoHDF5FileObject* self) {
-BOB_TRY
-  return Py_BuildValue("s", self->f->filename().c_str());
-BOB_CATCH_MEMBER(exception_message(self, s_filename.name()).c_str(), 0)
-}
-
-
-static auto s_writable = bob::extension::VariableDoc(
-  "writable",
-  "bool",
-  "Has this file been opened in writable mode?"
-);
-static PyObject* PyBobIoHDF5File_writable(PyBobIoHDF5FileObject* self) {
-BOB_TRY
-  return Py_BuildValue("b", self->f->writable());
-BOB_CATCH_MEMBER(exception_message(self, s_writable.name()).c_str(), 0)
-}
-
-static PyGetSetDef PyBobIoHDF5File_getseters[] = {
-    {
-      s_cwd.name(),
-      (getter)PyBobIoHDF5File_cwd,
-      0,
-      s_cwd.doc(),
-      0,
-    },
-    {
-      s_filename.name(),
-      (getter)PyBobIoHDF5File_filename,
-      0,
-      s_filename.doc(),
-      0,
-    },
-    {
-      s_writable.name(),
-      (getter)PyBobIoHDF5File_writable,
-      0,
-      s_writable.doc(),
-      0,
-    },
-    {0}  /* Sentinel */
-};
-
-PyTypeObject PyBobIoHDF5File_Type = {
-    PyVarObject_HEAD_INIT(0, 0)
-    0
-};
-
-bool init_HDF5File(PyObject* module){
-
-  // initialize the HDF5 file
-  PyBobIoHDF5File_Type.tp_name = s_hdf5file.name();
-  PyBobIoHDF5File_Type.tp_basicsize = sizeof(PyBobIoHDF5FileObject);
-  PyBobIoHDF5File_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
-  PyBobIoHDF5File_Type.tp_doc = s_hdf5file.doc();
-
-  // set the functions
-  PyBobIoHDF5File_Type.tp_new = PyBobIoHDF5File_New;
-  PyBobIoHDF5File_Type.tp_init = reinterpret_cast<initproc>(PyBobIoHDF5File_init);
-  PyBobIoHDF5File_Type.tp_dealloc = reinterpret_cast<destructor>(PyBobIoHDF5File_Delete);
-  PyBobIoHDF5File_Type.tp_methods = PyBobIoHDF5File_methods;
-  PyBobIoHDF5File_Type.tp_getset = PyBobIoHDF5File_getseters;
-
-  PyBobIoHDF5File_Type.tp_str = reinterpret_cast<reprfunc>(PyBobIoHDF5File_repr);
-  PyBobIoHDF5File_Type.tp_repr = reinterpret_cast<reprfunc>(PyBobIoHDF5File_repr);
-
-
-  // check that everyting is fine
-  if (PyType_Ready(&PyBobIoHDF5File_Type) < 0)
-    return false;
-
-  // add the type to the module
-  Py_INCREF(&PyBobIoHDF5File_Type);
-  return PyModule_AddObject(module, s_hdf5file.name(), (PyObject*)&PyBobIoHDF5File_Type) >= 0;
-}
diff --git a/bob/io/base/include/bob.io.base/CodecRegistry.h b/bob/io/base/include/bob.io.base/CodecRegistry.h
deleted file mode 100644
index 019bb5770959199f2a27c6df1594770c65dcf1f6..0000000000000000000000000000000000000000
--- a/bob/io/base/include/bob.io.base/CodecRegistry.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/**
- * @date Tue Oct 25 23:25:46 2011 +0200
- * @author Andre Anjos <andre.anjos@idiap.ch>
- *
- * @brief
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#ifndef BOB_IO_BASE_CODECREGISTRY_H
-#define BOB_IO_BASE_CODECREGISTRY_H
-
-#include <map>
-#include <string>
-#include <boost/shared_ptr.hpp>
-
-#include <bob.io.base/File.h>
-
-namespace bob { namespace io { namespace base {
-
-  /**
-   * The CodecRegistry holds registered converters for different types of
-   * input files. It manages registration and helps the user in picking the
-   * best codecs for their data. This class is a singleton (single global
-   * variable).
-   */
-  class CodecRegistry {
-
-    public: //static access
-
-      /**
-       * Returns the singleton
-       */
-      static boost::shared_ptr<CodecRegistry> instance();
-
-      static const std::map<std::string, std::string>& getExtensions () {
-        boost::shared_ptr<CodecRegistry> ptr = instance();
-        return ptr->s_extension2description;
-      }
-
-      /**
-       * Sets and unsets double-registration ignore flag
-       */
-      static bool ignoreDoubleRegistration() { return instance()->s_ignore; }
-      static void ignoreDoubleRegistration(bool v) { instance()->s_ignore = v; }
-
-    public: //object access
-
-      void registerExtension(const char* extension, const char* description,
-          file_factory_t factory);
-
-      void deregisterFactory(file_factory_t factory);
-      void deregisterExtension(const char* ext);
-
-      /**
-       * Returns the codec description, if an extension was registered with the
-       * matching input string. Otherwise, returns 0.
-       */
-      const char* getDescription(const char* ext);
-
-      file_factory_t findByExtension(const char* ext);
-      file_factory_t findByFilenameExtension(const char* fn);
-
-      bool isRegistered(const char* ext);
-
-    private:
-
-      CodecRegistry(): s_extension2codec(), s_ignore(false) {}
-
-      // Not implemented
-      CodecRegistry( const CodecRegistry&);
-
-      std::map<std::string, file_factory_t> s_extension2codec;
-      std::map<std::string, std::string> s_extension2description;
-      bool s_ignore; ///< shall I ignore double-registrations?
-
-  };
-
-}}}
-
-#endif /* BOB_IO_BASE_CODECREGISTRY_H */
diff --git a/bob/io/base/include/bob.io.base/File.h b/bob/io/base/include/bob.io.base/File.h
deleted file mode 100644
index e41bccdd9c4983f2be3526b3d1a24cacab150b87..0000000000000000000000000000000000000000
--- a/bob/io/base/include/bob.io.base/File.h
+++ /dev/null
@@ -1,184 +0,0 @@
-/**
- * @date Tue Oct 25 23:25:46 2011 +0200
- * @author Andre Anjos <andre.anjos@idiap.ch>
- *
- * @brief Describes a generic API for reading and writing data to external
- * files.
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#ifndef BOB_IO_BASE_FILE_H
-#define BOB_IO_BASE_FILE_H
-
-#include <boost/shared_ptr.hpp>
-#include <bob.io.base/array.h>
-#include <bob.io.base/blitz_array.h>
-
-namespace bob { namespace io { namespace base {
-
-  /**
-   * @brief Files deal with reading and writing multiple (homogeneous) array
-   * data to and from files.
-   */
-  class File {
-
-    public: //abstract API
-
-      virtual ~File();
-
-      /**
-       * The filename this array codec current points to
-       */
-      virtual const char* filename() const =0;
-
-      /**
-       * The typeinfo of data within this file, if it is supposed to be read as
-       * as a sequence of arrays
-       */
-      virtual const bob::io::base::array::typeinfo& type() const =0;
-
-      /**
-       * The typeinfo of data within this file, if it is supposed to be read as
-       * a single array.
-       */
-      virtual const bob::io::base::array::typeinfo& type_all() const =0;
-
-      /**
-       * The number of arrays available in this file, if it is supposed to be
-       * read as a sequence of arrays.
-       */
-      virtual size_t size() const =0;
-
-      /**
-       * Returns the name of the codec, for compatibility reasons.
-       */
-      virtual const char* name() const =0;
-
-      /**
-       * Loads the data of the array into memory. If an index is specified
-       * loads the specific array data from the file, otherwise, loads the data
-       * at position 0.
-       *
-       * This method will check to see if the given array has enough space. If
-       * that is not the case, it will allocate enough space internally by
-       * reseting the input array and putting the data read from the file
-       * inside.
-       */
-      virtual void read(bob::io::base::array::interface& buffer, size_t index) =0;
-
-      /**
-       * Loads all the data available at the file into a single in-memory
-       * array.
-       *
-       * This method will check to see if the given array has enough space. If
-       * that is not the case, it will allocate enough space internally by
-       * reseting the input array and putting the data read from the file
-       * inside.
-       */
-      virtual void read_all(bob::io::base::array::interface& buffer) =0;
-
-      /**
-       * Appends the given buffer into a file. If the file does not exist,
-       * create a new file, else, makes sure that the inserted array respects
-       * the previously set file structure.
-       *
-       * Returns the current position of the newly written array.
-       */
-      virtual size_t append (const bob::io::base::array::interface& buffer) =0;
-
-      /**
-       * Writes the data from the given buffer into the file and act like it is
-       * the only piece of data that will ever be written to such a file. Not
-       * more data appending may happen after a call to this method.
-       */
-      virtual void write (const bob::io::base::array::interface& buffer) =0;
-
-    public: //blitz::Array specific API
-
-      /**
-       * This method returns a copy of the array in the file with the element
-       * type you wish (just have to get the number of dimensions right!).
-       */
-      template <typename T, int N> blitz::Array<T,N> cast(size_t index) {
-        bob::io::base::array::blitz_array tmp(type());
-        read(tmp, index);
-        return tmp.cast<T,N>();
-      }
-
-      /**
-       * This method returns a copy of the array in the file with the element
-       * type you wish (just have to get the number of dimensions right!).
-       *
-       * This variant loads all data available into the file in a single array.
-       */
-      template <typename T, int N> blitz::Array<T,N> cast_all() {
-        bob::io::base::array::blitz_array tmp(type_all());
-        read_all(tmp);
-        return tmp.cast<T,N>();
-      }
-
-      template <typename T, int N> void read(blitz::Array<T,N>& io,
-          size_t index) {
-        bob::io::base::array::blitz_array use_this(io);
-        use_this.set(type());
-        read(use_this, index);
-        io.reference(use_this.get<T,N>());
-      }
-
-      template <typename T, int N> blitz::Array<T,N> read(size_t index) {
-        bob::io::base::array::blitz_array tmp(type());
-        read(tmp, index);
-        return tmp.get<T,N>();
-      }
-
-      template <typename T, int N> void read_all(blitz::Array<T,N>& io) {
-        bob::io::base::array::blitz_array use_this(io);
-        use_this.set(type_all());
-        read_all(use_this);
-        io.reference(use_this.get<T,N>());
-      }
-
-      template <typename T, int N> blitz::Array<T,N> read_all() {
-        bob::io::base::array::blitz_array tmp(type_all());
-        read_all(tmp);
-        return tmp.get<T,N>();
-      }
-
-      template <typename T, int N> size_t append(const blitz::Array<T,N>& in) {
-        bob::io::base::array::blitz_array use_this(in);
-        return append(use_this);
-      }
-
-      template <typename T, int N> void write (const blitz::Array<T,N>& in) {
-        bob::io::base::array::blitz_array use_this(in);
-        write(use_this);
-      }
-
-  };
-
-  /**
-   * @brief This defines the factory method F that can create codecs. Your
-   * task, as a codec developer is to create one of such methods for each of
-   * your codecs and statically register them to the codec registry.
-   *
-   * Here are the meanings of the mode flag that should be respected by your
-   * factory implementation:
-   *
-   * 'r': opens for reading only - no modifications can occur; it is an
-   *      error to open a file that does not exist for read-only operations.
-   * 'w': opens for reading and writing, but truncates the file if it
-   *      exists; it is not an error to open files that do not exist with
-   *      this flag.
-   * 'a': opens for reading and writing - any type of modification can
-   *      occur. If the file does not exist, this flag is effectively like
-   *      'w'.
-   *
-   * Returns a newly allocated File object that can read and write data to the
-   * file using a specific backend.
-   */
-  typedef boost::shared_ptr<File> (*file_factory_t) (const char* filename, char mode);
-
-}}}
-
-#endif /* BOB_IO_BASE_FILE_H */
diff --git a/bob/io/base/include/bob.io.base/HDF5Attribute.h b/bob/io/base/include/bob.io.base/HDF5Attribute.h
deleted file mode 100644
index 3af8a7a697f225e9d01ba1ffed856445774a736b..0000000000000000000000000000000000000000
--- a/bob/io/base/include/bob.io.base/HDF5Attribute.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * @author Andre Anjos <andre.anjos@idiap.ch>
- * @date Fri  2 Mar 08:19:03 2012
- *
- * @brief Simple attribute support for HDF5 files
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#ifndef BOB_IO_BASE_HDF5ATTRIBUTE_H
-#define BOB_IO_BASE_HDF5ATTRIBUTE_H
-
-#include <string>
-#include <map>
-#include <boost/shared_ptr.hpp>
-#include <hdf5.h>
-
-#include <bob.io.base/HDF5Types.h>
-
-namespace bob { namespace io { namespace base { namespace detail { namespace hdf5 {
-
-  /**
-   * Finds out the type of the attribute, if it exists, raises otherwise.
-   */
-  void gettype_attribute (const boost::shared_ptr<hid_t> location,
-      const std::string& name, HDF5Type& type);
-
-  /**
-   * Reads the attribute value, place it in "buffer"
-   */
-  void read_attribute (const boost::shared_ptr<hid_t> location,
-      const std::string& name, const bob::io::base::HDF5Type& dest, void* buffer);
-
-  /**
-   * Writes an attribute value from "buffer"
-   */
-  void write_attribute (boost::shared_ptr<hid_t> location,
-      const std::string& name, const bob::io::base::HDF5Type& dest,
-      const void* buffer);
-
-  /**
-   * Sets a scalar attribute on the given location. Setting an existing
-   * attribute overwrites its value.
-   *
-   * @note Only simple scalars are supported for the time being
-   */
-  template <typename T> void set_attribute(boost::shared_ptr<hid_t> location,
-      const std::string& name, const T& v) {
-    bob::io::base::HDF5Type dest_type(v);
-    write_attribute(location, name, dest_type,
-        reinterpret_cast<const void*>(&v));
-  }
-
-  /**
-   * Reads an attribute from the current group. Raises an error if such
-   * attribute does not exist on the group. To check for existence, use
-   * has_attribute().
-   */
-  template <typename T> T get_attribute(const boost::shared_ptr<hid_t> location,
-      const std::string& name) {
-    T v;
-    bob::io::base::HDF5Type dest_type(v);
-    read_attribute(location, name, dest_type, reinterpret_cast<void*>(&v));
-    return v;
-  }
-
-  /**
-   * Checks if a certain attribute exists in this location.
-   */
-  bool has_attribute(const boost::shared_ptr<hid_t> location,
-      const std::string& name);
-
-  /**
-   * Deletes an attribute from a location.
-   */
-  void delete_attribute(boost::shared_ptr<hid_t> location,
-      const std::string& name);
-
-  /**
-   * Lists all attributes and associated types currently available somewhere
-   */
-  void list_attributes(boost::shared_ptr<hid_t> location,
-    std::map<std::string, bob::io::base::HDF5Type>& attributes);
-
-}}}}}
-
-#endif /* BOB_IO_BASE_HDF5ATTRIBUTE_H */
diff --git a/bob/io/base/include/bob.io.base/HDF5Dataset.h b/bob/io/base/include/bob.io.base/HDF5Dataset.h
deleted file mode 100644
index 557241079ca1a289f8ea5d778cb082837ea648a9..0000000000000000000000000000000000000000
--- a/bob/io/base/include/bob.io.base/HDF5Dataset.h
+++ /dev/null
@@ -1,536 +0,0 @@
-/**
- * @author Andre Anjos <andre.anjos@idiap.ch>
- * @date Wed 29 Feb 17:27:45 2012
- *
- * @brief Describes HDF5 datasets
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#ifndef BOB_IO_BASE_HDF5DATASET_H
-#define BOB_IO_BASE_HDF5DATASET_H
-
-#include <vector>
-
-#include <boost/shared_ptr.hpp>
-#include <blitz/array.h>
-#include <hdf5.h>
-
-#include <bob.core/assert.h>
-#include <bob.core/array_copy.h>
-
-#include <bob.io.base/HDF5Attribute.h>
-#include <bob.io.base/HDF5Types.h>
-
-namespace bob { namespace io { namespace base { namespace detail { namespace hdf5 {
-
-  class File;
-  class Group;
-
-  /**
-   * An HDF5 C-style dataset that knows how to close itself.
-   */
-  class Dataset {
-
-    public: //better to protect?
-
-      /**
-       * Creates a new HDF5 dataset by reading its contents from a certain
-       * file.
-       */
-      Dataset(boost::shared_ptr<Group> parent, const std::string& name);
-
-      /**
-       * Creates a new HDF5 dataset from scratch and inserts it in the given
-       * group. If the Dataset already exists on file and the types are
-       * compatible, we attach to that type, otherwise, we raise an exception.
-       *
-       * If a new Dataset is to be created, you can also set if you would like
-       * to have as a list and the compression level. Note these settings have
-       * no effect if the Dataset already exists on file, in which case the
-       * current settings for that dataset are respected. The maximum value for
-       * the gzip compression is 9. The value of zero turns compression off
-       * (the default).
-       *
-       * The effect of setting "list" to false is that the created dataset:
-       *
-       * a) Will not be expandable (chunked)
-       * b) Will contain the exact number of dimensions of the input type.
-       *
-       * When you set "list" to true (the default), datasets are created with
-       * chunking automatically enabled (the chunk size is set to the size of
-       * the given variable) and an extra dimension is inserted to accommodate
-       * list operations.
-       */
-      Dataset(boost::shared_ptr<Group> parent, const std::string& name,
-          const bob::io::base::HDF5Type& type, bool list=true,
-          size_t compression=0);
-
-    public: //api
-
-      /**
-       * Destructor virtualization
-       */
-      virtual ~Dataset();
-
-      /**
-       * Returns the number of objects installed at this dataset from the
-       * perspective of the default compatible type.
-       */
-      size_t size() const;
-
-      /**
-       * Returns the number of objects installed at this dataset from the
-       * perspective of the default compatible type. If the given type is not
-       * compatible, raises a type error.
-       */
-      size_t size(const bob::io::base::HDF5Type& type) const;
-
-      /**
-       * Get parent group
-       */
-      virtual const boost::shared_ptr<Group> parent() const;
-      virtual boost::shared_ptr<Group> parent();
-
-      /**
-       * Filename where I'm sitting
-       */
-      virtual const std::string& filename() const;
-
-      /**
-       * Full path to myself. Constructed each time it is called.
-       */
-      virtual std::string path() const;
-
-      /**
-       * Path with filename. Constructed each time it is called.
-       */
-      virtual std::string url() const;
-
-      /**
-       * Access file
-       */
-      virtual const boost::shared_ptr<File> file() const;
-      virtual boost::shared_ptr<File> file();
-
-      /**
-       * My name
-       */
-      virtual const std::string& name() const {
-        return m_name;
-      }
-
-      /**
-       * Accesses the current location id of this dataset
-       */
-      const boost::shared_ptr<hid_t> location() const {
-        return m_id;
-      }
-      boost::shared_ptr<hid_t> location() {
-        return m_id;
-      }
-
-      /**
-       * DATA READING FUNCTIONALITY
-       */
-
-      /**
-       * Reads data from the file into a scalar. The conditions bellow have to
-       * be respected:
-       *
-       * a. My internal shape is 1D **OR** my internal shape is 2D, but the
-       *    extent of the second dimension is 1.
-       * b. The indexed position exists
-       *
-       * If the internal shape is not like defined above, raises a type error.
-       * If the indexed position does not exist, raises an index error.
-       */
-      template <typename T> void read(size_t index, T& value) {
-        bob::io::base::HDF5Type dest_type(value);
-        read_buffer(index, dest_type, reinterpret_cast<void*>(&value));
-      }
-
-      /**
-       * Reads data from the file into a scalar (allocated internally). The
-       * same conditions as for read(index, value) apply.
-       */
-      template <typename T> T read(size_t index) {
-        T retval;
-        read(index, retval);
-        return retval;
-      }
-
-      /**
-       * Reads data from the file into a scalar. This is equivalent to using
-       * read(0). The same conditions as for read(index=0, value) apply.
-       */
-      template <typename T> T read() {
-        T retval;
-        read(0, retval);
-        return retval;
-      }
-
-      /**
-       * Reads data from the file into a array. The following conditions have
-       * to be respected:
-       *
-       * a. My internal shape is the same as the shape of the given value
-       *    **OR** my internal shape has one more dimension as the given value.
-       *    In this case, the first dimension of the internal shape is
-       *    considered to be an index and the remaining shape values the
-       *    dimension of the value to be read. The given array has to be
-       *    compatible with this re-defined N-1 shape.
-       * b. The indexed position exists
-       *
-       * If the internal shape is not like defined above, raises a type error.
-       * If the index does not exist, raises an index error.
-       *
-       * @param index Which of the arrays to read in the current dataset, by
-       * order
-       * @param value The output array data will be stored inside this
-       * variable. This variable has to be a zero-based C-style contiguous
-       * storage array. If that is not the case, we will raise an exception.
-       */
-      template <typename T, int N>
-        void readArray(size_t index, blitz::Array<T,N>& value) {
-          bob::core::array::assertCZeroBaseContiguous(value);
-          bob::io::base::HDF5Type dest_type(value);
-          read_buffer(index, dest_type, reinterpret_cast<void*>(value.data()));
-        }
-
-      /**
-       * Reads data from the file into an array allocated dynamically. The same
-       * conditions as for readArray(index, value) apply.
-       *
-       * @param index Which of the arrays to read in the current dataset, by
-       * order
-       */
-      template <typename T, int N>
-        blitz::Array<T,N> readArray(size_t index) {
-          for (size_t k=m_descr.size(); k>0; --k) {
-            const bob::io::base::HDF5Shape& S = m_descr[k-1].type.shape();
-            if(S.n() == N) {
-              blitz::TinyVector<int,N> shape;
-              S.set(shape);
-              blitz::Array<T,N> retval(shape);
-              readArray(index, retval);
-              return retval;
-            }
-          }
-          boost::format m("trying to read or write `%s' at `%s' that only accepts `%s'");
-          m % "unknown dynamic shape" % url() % m_descr[0].type.str();
-          throw std::runtime_error(m.str());
-        }
-
-      /**
-       * Reads data from the file into a array. This is equivalent to using
-       * readArray(0, value). The same conditions as for readArray(index=0,
-       * value) apply.
-       *
-       * @param value The output array data will be stored inside this
-       * variable. This variable has to be a zero-based C-style contiguous
-       * storage array. If that is not the case, we will raise an exception.
-       */
-      template <typename T, int N>
-        void readArray(blitz::Array<T,N>& value) {
-          readArray(0, value);
-        }
-
-      /**
-       * Reads data from the file into a array. This is equivalent to using
-       * readArray(0). The same conditions as for readArray(index=0, value)
-       * apply.
-       */
-      template <typename T, int N>
-        blitz::Array<T,N> readArray() {
-          return readArray<T,N>(0);
-        }
-
-      /**
-       * DATA WRITING FUNCTIONALITY
-       */
-
-      /**
-       * Modifies the value of a scalar inside the file. Modifying a value
-       * requires that the expected internal shape for this dataset and the
-       * shape of the given scalar are consistent. To replace a scalar the
-       * conditions bellow have to be respected:
-       *
-       * a. The internal shape is 1D **OR** the internal shape is 2D, but the
-       *    second dimension of the internal shape has is extent == 1.
-       * b. The given indexing position exists
-       *
-       * If the above conditions are not met, an exception is raised.
-       */
-      template <typename T> void replace(size_t index, const T& value) {
-        bob::io::base::HDF5Type dest_type(value);
-        write_buffer(index, dest_type, reinterpret_cast<const void*>(&value));
-      }
-
-      /**
-       * Modifies the value of a scalar inside the file. This is equivalent to
-       * using replace(0, value). The same conditions as for replace(index=0,
-       * value) apply.
-       */
-      template <typename T> void replace(const T& value) {
-        replace(0, value);
-      }
-
-      /**
-       * Inserts a scalar in the current (existing ;-) dataset. This will
-       * trigger writing data to the file. Adding a scalar value requires that
-       * the expected internal shape for this dataset and the shape of the
-       * given scalar are consistent. To add a scalar the conditions
-       * bellow have to be respected:
-       *
-       * a. The internal shape is 1D **OR** the internal shape is 2D, but the
-       *    second dimension of the internal shape has is extent == 1.
-       * b. This dataset is expandible (chunked)
-       *
-       * If the above conditions are not met, an exception is raised.
-       */
-      template <typename T> void add(const T& value) {
-        bob::io::base::HDF5Type dest_type(value);
-        extend_buffer(dest_type, reinterpret_cast<const void*>(&value));
-      }
-
-      /**
-       * Replaces data at the file using a new array. Replacing an existing
-       * array requires shape consistence. The following conditions should be
-       * met:
-       *
-       * a. My internal shape is the same as the shape of the given value
-       *    **OR** my internal shape has one more dimension as the given value.
-       *    In this case, the first dimension of the internal shape is
-       *    considered to be an index and the remaining shape values the
-       *    dimension of the value to be read. The given array has to be
-       *    compatible with this re-defined N-1 shape.
-       * b. The given indexing position exists.
-       *
-       * If the internal shape is not like defined above, raises a type error.
-       * If the indexed position does not exist, raises an index error.
-       *
-       * @param index Which of the arrays to read in the current dataset, by
-       * order
-       * @param value The output array data will be stored inside this
-       * variable. This variable has to be a zero-based C-style contiguous
-       * storage array. If that is not the case, we will raise an exception.
-       */
-      template <typename T, int N>
-        void replaceArray(size_t index, const blitz::Array<T,N>& value) {
-          bob::io::base::HDF5Type dest_type(value);
-          if(!bob::core::array::isCZeroBaseContiguous(value)) {
-            blitz::Array<T,N> tmp = bob::core::array::ccopy(value);
-            write_buffer(index, dest_type, reinterpret_cast<const void*>(tmp.data()));
-          }
-          else {
-            write_buffer(index, dest_type,
-                reinterpret_cast<const void*>(value.data()));
-          }
-        }
-
-      /**
-       * Replaces data at the file using a new array. This is equivalent to
-       * calling replaceArray(0, value). The conditions for
-       * replaceArray(index=0, value) apply.
-       *
-       * @param value The output array data will be stored inside this
-       * variable. This variable has to be a zero-based C-style contiguous
-       * storage array. If that is not the case, we will raise an exception.
-       */
-      template <typename T, int N>
-        void replaceArray(const blitz::Array<T,N>& value) {
-          replaceArray(0, value);
-        }
-
-      /**
-       * Appends a array in a certain subdirectory of the file. If that
-       * subdirectory (or a "group" in HDF5 parlance) does not exist, it is
-       * created. If the dataset does not exist, it is created, otherwise, we
-       * append to it. In this case, the dimensionality of the scalar has to be
-       * compatible with the existing dataset shape (or "dataspace" in HDF5
-       * parlance). If you want to do this, first unlink and than use one of
-       * the add() methods.
-       */
-      template <typename T, int N>
-        void addArray(const blitz::Array<T,N>& value) {
-          bob::io::base::HDF5Type dest_type(value);
-          if(!bob::core::array::isCZeroBaseContiguous(value)) {
-            blitz::Array<T,N> tmp = bob::core::array::ccopy(value);
-            extend_buffer(dest_type, reinterpret_cast<const void*>(tmp.data()));
-          }
-          else {
-            extend_buffer(dest_type, reinterpret_cast<const void*>(value.data()));
-          }
-      }
-
-    private: //apis
-
-      /**
-       * Selects a bit of the file to be affected at the next read or write
-       * operation. This method encapsulate calls to H5Sselect_hyperslab().
-       *
-       * The index is checked for existence as well as the consistence of the
-       * destination type.
-       */
-      std::vector<bob::io::base::HDF5Descriptor>::iterator select (size_t index,
-          const bob::io::base::HDF5Type& dest);
-
-    public: //direct access for other bindings -- don't use these!
-
-      /**
-       * Reads a previously selected area into the given (user) buffer.
-       */
-      void read_buffer (size_t index, const bob::io::base::HDF5Type& dest, void* buffer);
-
-      /**
-       * Writes the contents of a given buffer into the file. The area that the
-       * data will occupy should have been selected beforehand.
-       */
-      void write_buffer (size_t index, const bob::io::base::HDF5Type& dest,
-          const void* buffer);
-
-      /**
-       * Extend the dataset with one extra variable.
-       */
-      void extend_buffer (const bob::io::base::HDF5Type& dest, const void* buffer);
-
-    public: //attribute support
-
-      /**
-       * Gets the current type set for an attribute
-       */
-      void gettype_attribute(const std::string& name,
-          HDF5Type& type) const;
-
-      /**
-       * Sets a scalar attribute on the current group. Setting an existing
-       * attribute overwrites its value.
-       */
-      template <typename T> void set_attribute(const std::string& name,
-          const T& v) {
-        bob::io::base::HDF5Type dest_type(v);
-        write_attribute(name, dest_type, reinterpret_cast<const void*>(&v));
-      }
-
-      /**
-       * Reads an attribute from the current dataset. Raises an error if such
-       * attribute does not exist on the group. To check for existence, use
-       * has_attribute().
-       */
-      template <typename T> T get_attribute(const std::string& name) const {
-        T v;
-        bob::io::base::HDF5Type dest_type(v);
-        read_attribute(name, dest_type, reinterpret_cast<void*>(&v));
-        return v;
-      }
-
-      /**
-       * Checks if a certain attribute exists in this group.
-       */
-      bool has_attribute(const std::string& name) const;
-
-      /**
-       * Deletes an attribute
-       */
-      void delete_attribute(const std::string& name);
-
-      /**
-       * List attributes available on this dataset.
-       */
-      void list_attributes(std::map<std::string, bob::io::base::HDF5Type>& attributes) const;
-
-    public: //array attribute support
-
-      /**
-       * Sets a array attribute on the current group. Setting an existing
-       * attribute overwrites its value. If the attribute exists it is erased
-       * and re-written.
-       */
-      template <typename T, int N> void set_array_attribute(const std::string& name,
-          const blitz::Array<T,N>& v) {
-        bob::io::base::HDF5Type dest_type(v);
-        if(!bob::core::array::isCZeroBaseContiguous(v)) {
-          blitz::Array<T,N> tmp = bob::core::array::ccopy(v);
-          write_attribute(name, dest_type, reinterpret_cast<const void*>(tmp.data()));
-        }
-        else {
-          write_attribute(name, dest_type, reinterpret_cast<const void*>(v.data()));
-        }
-      }
-
-      /**
-       * Reads an attribute from the current dataset. Raises an error if such
-       * attribute does not exist on the group. To check for existence, use
-       * has_attribute().
-       */
-      template <typename T, int N> blitz::Array<T,N> get_array_attribute(const std::string& name) const {
-        blitz::Array<T,N> v;
-        bob::io::base::HDF5Type dest_type(v);
-        read_attribute(name, dest_type, reinterpret_cast<void*>(v.data()));
-        return v;
-      }
-
-      /**
-       * Reads an attribute from the current dataset. Places the data in an
-       * already allocated array.
-       */
-      template <typename T, int N> void get_array_attribute(const std::string& name,
-          blitz::Array<T,N>& v) const {
-        bob::io::base::HDF5Type dest_type(v);
-        read_attribute(name, dest_type, reinterpret_cast<void*>(v.data()));
-      }
-
-    public: //buffer attribute support
-
-      /**
-       * Reads an attribute into a user buffer. It is the user's responsibility
-       * to have a buffer that represents the given type.
-       */
-      void read_attribute (const std::string& name,
-          const bob::io::base::HDF5Type& dest, void* buffer) const;
-
-      /**
-       * Writes the contents of a given buffer into the attribute.
-       */
-      void write_attribute (const std::string& name,
-          const bob::io::base::HDF5Type& dest, const void* buffer);
-
-    private: //not implemented
-
-      /**
-       * Copies the contents of an existing dataset -- not implemented
-       */
-      Dataset(const Dataset& other);
-
-      /**
-       * Assigns the contents of an existing dataset to myself -- not
-       * implemented
-       */
-      Dataset& operator= (const Dataset& other);
-
-    public: //representation
-
-      boost::weak_ptr<Group> m_parent; ///< my parent group
-      std::string m_name; ///< name of this object
-      boost::shared_ptr<hid_t> m_id; ///< the HDF5 Dataset this type points to
-      boost::shared_ptr<hid_t> m_dt; ///< the datatype of this Dataset
-      boost::shared_ptr<hid_t> m_filespace; ///< the "file" space for this set
-      std::vector<bob::io::base::HDF5Descriptor> m_descr; ///< read/write descr.'s
-      boost::shared_ptr<hid_t> m_memspace; ///< read/write space
-
-  };
-
-  /**
-   * std::string specialization
-   */
-  template <> void Dataset::read<std::string>(size_t index, std::string& value);
-  template <> void Dataset::replace<std::string>(size_t index, const std::string& value);
-  template <> void Dataset::add<std::string>(const std::string& value);
-  template <> void Dataset::set_attribute<std::string>(const std::string& name, const std::string& v);
-  template <> std::string Dataset::get_attribute(const std::string& name) const;
-
-}}}}}
-
-
-#endif /* BOB_IO_BASE_HDF5DATASET_H */
diff --git a/bob/io/base/include/bob.io.base/HDF5File.h b/bob/io/base/include/bob.io.base/HDF5File.h
deleted file mode 100644
index 31c65944e5088b51af3fe1307e270e466b71052a..0000000000000000000000000000000000000000
--- a/bob/io/base/include/bob.io.base/HDF5File.h
+++ /dev/null
@@ -1,558 +0,0 @@
-/**
- * @date Wed Jun 22 17:50:08 2011 +0200
- * @author Andre Anjos <andre.anjos@idiap.ch>
- *
- * @brief bob support for HDF5 files. HDF5 is a open standard for
- * self-describing data files. You can get more information in this webpage:
- * http://www.hdfgroup.org/HDF5
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#ifndef BOB_IO_BASE_HDF5FILE_H
-#define BOB_IO_BASE_HDF5FILE_H
-
-#include <boost/format.hpp>
-
-#include <bob.io.base/HDF5Utils.h>
-
-namespace bob { namespace io { namespace base {
-
-  /**
-   * This is the main type for interfacing bob with HDF5. It allows the user
-   * to create, delete and modify data objects using a very-level API. The
-   * total functionality provided by this API is, of course, much smaller than
-   * what is provided if you use the HDF5 C-APIs directly, but is much simpler
-   * as well.
-   */
-  class HDF5File {
-
-    public:
-
-      /**
-       * This enumeration defines the different values with which you can open
-       * the files with
-       */
-      typedef enum mode_t {
-        in = 0, //H5F_ACC_RDONLY    < can only read file
-        inout = 1, //H5F_ACC_RDWR   < open file for reading and writing
-        trunc = 2, //H5F_ACC_TRUNC  < if file exists, truncate it and open
-        excl = 4 //H5F_ACC_EXCL    < if file exists, raise, otherwise == inout
-      } mode_t;
-
-    public: //api
-
-      /**
-       * Constructor, starts a new HDF5File object giving it a file name and an
-       * action: excl/trunc/in/inout
-       */
-      HDF5File (const std::string& filename, mode_t mode);
-
-      /**
-       * Constructor, starts a new HDF5File object giving it a file name and an
-       * action: 'r' (read-only), 'a' (read/write/append), 'w' (read/write/truncate) or 'x' (read/write/exclusive)
-       */
-      HDF5File (const std::string& filename, const char mode='r');
-
-      /**
-       * Destructor virtualization
-       */
-      virtual ~HDF5File();
-
-      /**
-       * Flushes the current content of the file to disk.
-       */
-      void flush() {m_file->flush();}
-
-      /**
-       * Closes the file after writing its content to disk
-       */
-      void close();
-
-      /**
-       * Changes the current prefix path. When this object is started, it
-       * points to the root of the file. If you set this to a different
-       * value, it will be used as a prefix to any subsequent operation on
-       * relative paths until you reset it.
-       *
-       * @param path If path starts with '/', it is treated as an absolute
-       * path. '..' and '.' are supported. This object should be a std::string.
-       * If the value is relative, it is added to the current path.
-       *
-       * @note All operations taking a relative path, following a cd(), will be
-       * considered relative to the value returned by cwd().
-       */
-      void cd(const std::string& path);
-
-      /**
-       * Tells if a certain directory exists in a file.
-       */
-      bool hasGroup(const std::string& path);
-
-      /**
-       * Creates a directory within the file. It is an error to recreate a path
-       * that already exists. You can check this with hasGroup()
-       */
-      void createGroup(const std::string& path);
-
-      /**
-       * Returns the name of the file currently opened
-       */
-      const std::string filename() const {check_open(); return m_file->filename(); }
-
-      /**
-       * Checks if the file is open for writing
-       */
-      bool writable() const {check_open(); return m_file->writable();}
-
-      /**
-       * Returns the current working path, fully resolved. This is
-       * re-calculated every time you call this method.
-       */
-      std::string cwd() const;
-
-      /**
-       * Tells if we have a variable with the given name inside the HDF5 file.
-       * If the file path given is a relative file path, it is taken w.r.t. the
-       * current working directory, as returned by cwd().
-       */
-      bool contains(const std::string& path) const;
-
-      /**
-       * Describe a certain dataset path. If the file path is a relative one,
-       * it is taken w.r.t. the current working directory, as returned by
-       * cwd().
-       */
-      const std::vector<HDF5Descriptor>& describe (const std::string& path) const;
-
-      /**
-       * Unlinks a particular dataset from the file. Note that this will
-       * not erase the data on the current file as that functionality is not
-       * provided by HDF5. To actually reclaim the space occupied by the
-       * unlinked structure, you must re-save this file to another file. The
-       * new file will not contain the data of any dangling datasets (datasets
-       * w/o names or links). Relative paths are allowed.
-       */
-      void unlink (const std::string& path);
-
-      /**
-       * Renames an existing dataset
-       */
-      void rename (const std::string& from, const std::string& to);
-
-      /**
-       * Accesses all existing paths in one shot. Input has to be a std
-       * container with T = std::string and accepting push_back()
-       */
-      template <typename T> void paths (T& container, const bool relative = false) const {
-        m_cwd->dataset_paths(container);
-        check_open();
-        if (relative){
-          const std::string d = cwd();
-          const int len = d.length()+1;
-          for (typename T::iterator it = container.begin(); it != container.end(); ++it){
-            // assert that the string contains the current path
-            assert(it->find(d) == 0);
-            // subtract current path
-            *it = it->substr(len);
-          }
-        }
-      }
-
-      /**
-       * Accesses all existing paths in one shot. Input has to be a std
-       * container with T = std::string and accepting push_back()
-       */
-      template <typename T> void sub_groups (T& container, bool relative = false, bool recursive = true) const {
-        check_open();
-        m_cwd->subgroup_paths(container, recursive);
-        if (!relative){
-          const std::string d = cwd() + "/";
-          for (typename T::iterator it = container.begin(); it != container.end(); ++it){
-            // add current path
-            *it = d + *it;
-          }
-        }
-      }
-
-      /**
-       * Copies the contents of the other file to this file. This is a blind
-       * operation, so we try to copy everything from the given file to the
-       * current one. It is the user responsibility to make sure the "path"
-       * slots in the other file are not already taken. If that is detected, an
-       * exception will be raised.
-       *
-       * This operation will be conducted w.r.t. the currently set prefix path
-       * (verifiable using cwd()).
-       */
-      void copy (HDF5File& other);
-
-      /**
-       * Reads data from the file into a scalar. Raises an exception if the
-       * type is incompatible. Relative paths are accepted.
-       */
-      template <typename T>
-        void read(const std::string& path, size_t pos, T& value) {
-          check_open();
-          (*m_cwd)[path]->read(pos, value);
-        }
-
-      /**
-       * Reads data from the file into a scalar. Returns by copy. Raises if the
-       * type T is incompatible. Relative paths are accepted.
-       */
-      template <typename T> T read(const std::string& path, size_t pos) {
-        check_open();
-        return (*m_cwd)[path]->read<T>(pos);
-      }
-
-      /**
-       * Reads data from the file into a scalar. Raises an exception if the
-       * type is incompatible. Relative paths are accepted. Calling this method
-       * is equivalent to calling read(path, 0). Returns by copy.
-       */
-      template <typename T> T read(const std::string& path) {
-        return read<T>(path, 0);
-      }
-
-      /**
-       * Reads data from the file into a array. Raises an exception if the type
-       * is incompatible. Relative paths are accepted.
-       */
-      template <typename T, int N> void readArray(const std::string& path,
-          size_t pos, blitz::Array<T,N>& value) {
-        check_open();
-        (*m_cwd)[path]->readArray(pos, value);
-      }
-
-      /**
-       * Reads data from the file into a array. Raises an exception if the type
-       * is incompatible. Relative paths are accepted. Destination array is
-       * allocated internally and returned by value.
-       */
-      template <typename T, int N> blitz::Array<T,N> readArray
-        (const std::string& path, size_t pos) {
-        check_open();
-        return (*m_cwd)[path]->readArray<T,N>(pos);
-      }
-
-      /**
-       * Reads data from the file into a array. Raises an exception if the type
-       * is incompatible. Relative paths are accepted. Calling this method is
-       * equivalent to calling readArray(path, 0, value).
-       */
-      template <typename T, int N> void readArray(const std::string& path,
-          blitz::Array<T,N>& value) {
-        readArray(path, 0, value);
-      }
-
-      /**
-       * Reads data from the file into a array. Raises an exception if the type
-       * is incompatible. Relative paths are accepted. Calling this method is
-       * equivalent to calling readArray(path, 0). Destination array is
-       * allocated internally.
-       */
-      template <typename T, int N> blitz::Array<T,N> readArray
-        (const std::string& path) {
-          return readArray<T,N>(path, 0);
-      }
-
-      /**
-       * Modifies the value of a scalar inside the file. Relative paths are
-       * accepted.
-       */
-      template <typename T> void replace(const std::string& path, size_t pos,
-          const T& value) {
-        check_open();
-        if (!m_file->writable()) {
-          boost::format m("cannot replace value at dataset '%s' at path '%s' of file '%s' because it is not writeable");
-          m % path % m_cwd->path() % m_file->filename();
-          throw std::runtime_error(m.str());
-        }
-        (*m_cwd)[path]->replace(pos, value);
-      }
-
-      /**
-       * Modifies the value of a scalar inside the file. Relative paths are
-       * accepted. Calling this method is equivalent to calling replace(path,
-       * 0, value).
-       */
-      template <typename T> void replace(const std::string& path,
-          const T& value) {
-        replace(path, 0, value);
-      }
-
-      /**
-       * Modifies the value of a array inside the file. Relative paths are
-       * accepted.
-       */
-      template <typename T> void replaceArray(const std::string& path,
-          size_t pos, const T& value) {
-        check_open();
-        if (!m_file->writable()) {
-          boost::format m("cannot replace array at dataset '%s' at path '%s' of file '%s' because it is not writeable");
-          m % path % m_cwd->path() % m_file->filename();
-          throw std::runtime_error(m.str());
-        }
-        (*m_cwd)[path]->replaceArray(pos, value);
-      }
-
-      /**
-       * Modifies the value of a array inside the file. Relative paths are
-       * accepted. Calling this method is equivalent to calling
-       * replaceArray(path, 0, value).
-       */
-      template <typename T> void replaceArray(const std::string& path,
-          const T& value) {
-        replaceArray(path, 0, value);
-      }
-
-      /**
-       * Appends a scalar in a dataset. If the dataset does not yet exist, one
-       * is created with the type characteristics. Relative paths are accepted.
-       */
-      template <typename T> void append(const std::string& path,
-          const T& value) {
-        check_open();
-        if (!m_file->writable()) {
-          boost::format m("cannot append value to dataset '%s' at path '%s' of file '%s' because it is not writeable");
-          m % path % m_cwd->path() % m_file->filename();
-          throw std::runtime_error(m.str());
-        }
-        if (!contains(path)) m_cwd->create_dataset(path, bob::io::base::HDF5Type(value), true, 0);
-        (*m_cwd)[path]->add(value);
-      }
-
-      /**
-       * Appends a array in a dataset. If the dataset does not yet exist, one
-       * is created with the type characteristics. Relative paths are accepted.
-       *
-       * If a new Dataset is to be created, you can also set the compression
-       * level. Note this setting has no effect if the Dataset already exists
-       * on file, in which case the current setting for that dataset is
-       * respected. The maximum value for the gzip compression is 9. The value
-       * of zero turns compression off (the default).
-       */
-      template <typename T> void appendArray(const std::string& path,
-          const T& value, size_t compression=0) {
-        check_open();
-        if (!m_file->writable()) {
-          boost::format m("cannot append array to dataset '%s' at path '%s' of file '%s' because it is not writeable");
-          m % path % m_cwd->path() % m_file->filename();
-          throw std::runtime_error(m.str());
-        }
-        if (!contains(path)) m_cwd->create_dataset(path, bob::io::base::HDF5Type(value), true, compression);
-        (*m_cwd)[path]->addArray(value);
-      }
-
-      /**
-       * Sets the scalar at position 0 to the given value. This method is
-       * equivalent to checking if the scalar at position 0 exists and then
-       * replacing it. If the path does not exist, we append the new scalar.
-       */
-      template <typename T> void set(const std::string& path, const T& value) {
-        check_open();
-        if (!m_file->writable()) {
-          boost::format m("cannot set value at dataset '%s' at path '%s' of file '%s' because it is not writeable");
-          m % path % m_cwd->path() % m_file->filename();
-          throw std::runtime_error(m.str());
-        }
-        if (!contains(path)) m_cwd->create_dataset(path, bob::io::base::HDF5Type(value), false, 0);
-        (*m_cwd)[path]->replace(0, value);
-      }
-
-      /**
-       * Sets the array at position 0 to the given value. This method is
-       * equivalent to checking if the array at position 0 exists and then
-       * replacing it. If the path does not exist, we append the new array.
-       *
-       * If a new Dataset is to be created, you can also set the compression
-       * level. Note this setting has no effect if the Dataset already exists
-       * on file, in which case the current setting for that dataset is
-       * respected. The maximum value for the gzip compression is 9. The value
-       * of zero turns compression off (the default).
-       */
-      template <typename T> void setArray(const std::string& path,
-          const T& value, size_t compression=0) {
-        check_open();
-        if (!m_file->writable()) {
-          boost::format m("cannot set array at dataset '%s' at path '%s' of file '%s' because it is not writeable");
-          m % path % m_cwd->path() % m_file->filename();
-          throw std::runtime_error(m.str());
-        }
-        if (!contains(path)) m_cwd->create_dataset(path, bob::io::base::HDF5Type(value), false, compression);
-        (*m_cwd)[path]->replaceArray(0, value);
-      }
-
-    public: //api shortcuts to deal with buffers -- avoid these at all costs!
-
-      /**
-       * creates a new dataset. If the dataset already exists, checks if the
-       * existing data is compatible with the required type.
-       */
-      void create (const std::string& path, const HDF5Type& dest, bool list,
-          size_t compression);
-
-      /**
-       * Reads data from the file into a buffer. The given buffer contains
-       * sufficient space to hold the type described in "dest". Raises an
-       * exception if the type is incompatible with the expected data in the
-       * file. Relative paths are accepted.
-       */
-      void read_buffer (const std::string& path, size_t pos,
-          const HDF5Type& type, void* buffer) const;
-
-      /**
-       * writes the contents of a given buffer into the file. the area that the
-       * data will occupy should have been selected beforehand.
-       */
-      void write_buffer (const std::string& path, size_t pos,
-          const HDF5Type& type, const void* buffer);
-
-      /**
-       * extend the dataset with one extra variable.
-       */
-      void extend_buffer (const std::string& path,
-          const HDF5Type& type, const void* buffer);
-
-      /**
-       * Copy construct an already opened HDF5File; just creates a shallow copy
-       * of the file
-       */
-      HDF5File (const HDF5File& other);
-
-      /**
-       * Drop the current settings and load new ones from the other file.
-       */
-      HDF5File& operator= (const HDF5File& other);
-
-    public: // attribute handling
-
-      /**
-       * Tells if there is an attribute with a given name on the given path,
-       * relative to the current location, possibly.
-       */
-      bool hasAttribute(const std::string& path, const std::string& name) const;
-
-      /**
-       * Reads data from an attribute into a scalar. If the attribute does not
-       * exist, raise an exception. Raises a TypeError if the types are not
-       * compatible.
-       */
-      template <typename T>
-        void getAttribute(const std::string& path, const std::string& name,
-            T& value) const {
-          check_open();
-          if (m_cwd->has_dataset(path)) {
-            value = (*m_cwd)[path]->get_attribute<T>(name);
-          }
-          else if (m_cwd->has_group(path)) {
-            value = m_cwd->cd(path)->get_attribute<T>(name);
-          }
-          else {
-            boost::format m("cannot read attribute '%s' at path/dataset '%s' of file '%s' (cwd: '%s') because this path/dataset does not currently exist");
-            m % name % path % m_file->filename() % m_cwd->path();
-            throw std::runtime_error(m.str());
-          }
-        }
-
-      /**
-       * Reads data from an attribute into an array. If the attribute does not
-       * exist, raise an exception. Raises a type error if the types are not
-       * compatible.
-       */
-      template <typename T, int N>
-        void getArrayAttribute(const std::string& path,
-            const std::string& name, blitz::Array<T,N>& value) const {
-          check_open();
-          if (m_cwd->has_dataset(path)) {
-            value = (*m_cwd)[path]->get_array_attribute<T,N>(name);
-          }
-          else if (m_cwd->has_group(path)) {
-            value = m_cwd->cd(path)->get_array_attribute<T,N>(name);
-          }
-          else {
-            boost::format m("cannot read (array) attribute '%s' at path/dataset '%s' of file '%s' (cwd: '%s') because this path/dataset does not currently exist");
-            m % name % path % m_file->filename() % m_cwd->path();
-            throw std::runtime_error(m.str());
-          }
-        }
-
-      /**
-       * Writes a scalar as an attribute to a path in this file.
-       */
-      template <typename T>
-        void setAttribute(const std::string& path, const std::string& name,
-            const T value) {
-          check_open();
-          if (m_cwd->has_dataset(path)) {
-            (*m_cwd)[path]->set_attribute(name, value);
-          }
-          else if (m_cwd->has_group(path)) {
-            m_cwd->cd(path)->set_attribute(name, value);
-          }
-          else {
-            boost::format m("cannot write attribute '%s' at path/dataset '%s' of file '%s' (cwd: '%s') because this path/dataset does not currently exist");
-            m % name % path % m_file->filename() % m_cwd->path();
-            throw std::runtime_error(m.str());
-          }
-        }
-
-      /**
-       * Writes an array as an attribute to a path in this file.
-       */
-      template <typename T, int N>
-        void setArrayAttribute(const std::string& path,
-            const std::string& name, const blitz::Array<T,N>& value) {
-          check_open();
-          if (m_cwd->has_dataset(path)) {
-            (*m_cwd)[path]->set_array_attribute(name, value);
-          }
-          else if (m_cwd->has_group(path)) {
-            m_cwd->cd(path)->set_array_attribute(name, value);
-          }
-          else {
-            boost::format m("cannot write (array) attribute '%s' at path/dataset '%s' of file '%s' (cwd: '%s') because this path/dataset does not currently exist");
-            m % name % path % m_file->filename() % m_cwd->path();
-            throw std::runtime_error(m.str());
-          }
-        }
-
-      /**
-       * Gets the type information of an attribute
-       */
-      void getAttributeType(const std::string& path,
-          const std::string& name, bob::io::base::HDF5Type& type) const;
-
-      /**
-       * Deletes a given attribute
-       */
-      void deleteAttribute(const std::string& path,
-          const std::string& name);
-
-      /**
-       * List attributes available on a certain object.
-       */
-      void listAttributes(const std::string& path,
-          std::map<std::string, bob::io::base::HDF5Type>& attributes) const;
-
-    public: //raw accessors to attributes
-
-      void read_attribute(const std::string& path, const std::string& name,
-          const bob::io::base::HDF5Type& type, void* buffer) const;
-
-      void write_attribute(const std::string& path, const std::string& name,
-          const bob::io::base::HDF5Type& type, const void* buffer);
-
-    private: //representation
-
-      void check_open() const;
-
-      boost::shared_ptr<detail::hdf5::File> m_file; ///< the file itself
-      boost::shared_ptr<detail::hdf5::Group> m_cwd; ///< current working dir
-
-  };
-
-}}}
-
-#endif /* BOB_IO_BASE_HDF5FILE_H */
diff --git a/bob/io/base/include/bob.io.base/HDF5Group.h b/bob/io/base/include/bob.io.base/HDF5Group.h
deleted file mode 100644
index 9dcd7a6e76cccdb40c1e4b98b4efdec63bcc52ef..0000000000000000000000000000000000000000
--- a/bob/io/base/include/bob.io.base/HDF5Group.h
+++ /dev/null
@@ -1,468 +0,0 @@
-/**
- * @author Andre Anjos <andre.anjos@idiap.ch>
- * @date Wed 29 Feb 17:24:10 2012
- *
- * @brief Describes HDF5 groups.
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#ifndef BOB_IO_BASE_HDF5GROUP_H
-#define BOB_IO_BASE_HDF5GROUP_H
-
-#include <boost/shared_ptr.hpp>
-#include <boost/enable_shared_from_this.hpp>
-#include <hdf5.h>
-
-#include <bob.io.base/HDF5Types.h>
-#include <bob.io.base/HDF5Dataset.h>
-#include <bob.io.base/HDF5Attribute.h>
-
-namespace bob { namespace io { namespace base { namespace detail { namespace hdf5 {
-
-  class File;
-
-  /**
-   * A group represents a path inside the HDF5 file. It can contain Datasets or
-   * other Groups.
-   */
-  class Group: public boost::enable_shared_from_this<Group> {
-
-    public: //better to protect?
-
-      /**
-       * Creates a new group in a given parent.
-       */
-      Group(boost::shared_ptr<Group> parent, const std::string& name);
-
-      /**
-       * Binds to an existing group in a parent, reads all the group contents
-       * recursively. Note that the last parameter is there only to
-       * differentiate from the above constructor. It is ignored.
-       */
-      Group(boost::shared_ptr<Group> parent,  const std::string& name,
-          bool open);
-
-      /**
-       * Constructor used by the root group, just open the root group
-       */
-      Group(boost::shared_ptr<File> parent);
-
-      /**
-       * Recursively open sub-groups and datasets. This cannot be done at the
-       * constructor because of a enable_shared_from_this<> restriction that
-       * results in a bad weak pointer exception being raised.
-       */
-      void open_recursively();
-
-    public: //api
-
-      /**
-       * D'tor - presently, does nothing
-       */
-      virtual ~Group();
-
-      /**
-       * Get parent group
-       */
-      virtual const boost::shared_ptr<Group> parent() const;
-      virtual boost::shared_ptr<Group> parent();
-
-      /**
-       * Filename where I'm sitting
-       */
-      virtual const std::string& filename() const;
-
-      /**
-       * Full path to myself. Constructed each time it is called.
-       */
-      virtual std::string path() const;
-
-      /**
-       * Access file
-       */
-      virtual const boost::shared_ptr<File> file() const;
-      virtual boost::shared_ptr<File> file();
-
-      /**
-       * My name
-       */
-      virtual const std::string& name() const {
-        return m_name;
-      }
-
-      /**
-       * Deletes all children nodes and properties in this group.
-       *
-       * Note that removing data already written in a file will only be
-       * effective in terms of space saving when you actually re-write that
-       * file. This instruction just unlinks all data from this group and makes
-       * them inaccessible to any further read operation.
-       */
-      virtual void reset();
-
-      /**
-       * Accesses the current location id of this group
-       */
-      const boost::shared_ptr<hid_t> location() const {
-        return m_id;
-      }
-
-      boost::shared_ptr<hid_t> location() {
-        return m_id;
-      }
-
-      /**
-       * Path with filename. Constructed each time it is called.
-       */
-      virtual std::string url() const;
-
-      /**
-       * move up-down on the group hierarchy
-       */
-      virtual boost::shared_ptr<Group> cd(const std::string& path);
-      virtual const boost::shared_ptr<Group> cd(const std::string& path) const;
-
-      /**
-       * Get a mapping of all child groups
-       */
-      virtual const std::map<std::string, boost::shared_ptr<Group> >& groups()
-        const {
-        return m_groups;
-      }
-
-      /**
-       * Create a new subgroup with a given name.
-       */
-      virtual boost::shared_ptr<Group> create_group(const std::string& name);
-
-      /**
-       * Deletes an existing subgroup with a given name. If a relative name is
-       * given, it is interpreted w.r.t. to this group.
-       *
-       * Note that removing data already written in a file will only be
-       * effective in terms of space saving when you actually re-write that
-       * file. This instruction just unlinks all data from this group and makes
-       * them inaccessible to any further read operation.
-       */
-      virtual void remove_group(const std::string& path);
-
-      /**
-       * Rename an existing group under me.
-       */
-      virtual void rename_group(const std::string& from, const std::string& to);
-
-      /**
-       * Copies all data from an existing group into myself, creating a new
-       * subgroup, by default, with the same name as the other group. If a
-       * relative name is given, it is interpreted w.r.t. to this group.
-       *
-       * If an empty string is given as "dir", copies the other group name.
-       */
-      virtual void copy_group(const boost::shared_ptr<Group> other, const
-          std::string& path="");
-
-      /**
-       * Says if a group with a certain path exists in this group.
-       */
-      virtual bool has_group(const std::string& path) const;
-
-      /**
-       * Get all datasets attached to this group
-       */
-      virtual const std::map<std::string, boost::shared_ptr<Dataset> >&
-        datasets() const {
-          return m_datasets;
-        }
-
-      /**
-       * Creates a new HDF5 dataset from scratch and inserts it in this group.
-       * If the Dataset already exists on file and the types are compatible, we
-       * attach to that type, otherwise, we raise an exception.
-       *
-       * You can set if you would like to have the dataset created as a list
-       * and the compression level.
-       *
-       * The effect of setting "list" to false is that the created dataset:
-       *
-       * a) Will not be expandible (chunked) b) Will contain the exact number
-       * of dimensions of the input type.
-       *
-       * When you set "list" to true (the default), datasets are created with
-       * chunking automatically enabled (the chunk size is set to the size of
-       * the given variable) and an extra dimension is inserted to accomodate
-       * list operations.
-       */
-      virtual boost::shared_ptr<Dataset> create_dataset
-        (const std::string& path, const bob::io::base::HDF5Type& type, bool list=true,
-         size_t compression=0);
-
-      /**
-       * Deletes a dataset in this group
-       *
-       * Note that removing data already written in a file will only be
-       * effective in terms of space saving when you actually re-write that
-       * file. This instruction just unlinks all data from this group and makes
-       * them inaccessible to any further read operation.
-       */
-      virtual void remove_dataset(const std::string& path);
-
-      /**
-       * Rename an existing dataset under me.
-       */
-      virtual void rename_dataset(const std::string& from,
-          const std::string& to);
-
-      /**
-       * Copies the contents of the given dataset into this. By default, use
-       * the same name.
-       */
-      virtual void copy_dataset(const boost::shared_ptr<Dataset> other,
-          const std::string& path="");
-
-      /**
-       * Says if a dataset with a certain name exists in the current file.
-       */
-      virtual bool has_dataset(const std::string& path) const;
-
-      /**
-       * Accesses a certain dataset from this group
-       */
-      boost::shared_ptr<Dataset> operator[] (const std::string& path);
-      const boost::shared_ptr<Dataset> operator[] (const std::string& path) const;
-
-      /**
-       * Accesses all existing paths in one shot. Input has to be a std
-       * container with T = std::string and accepting push_back()
-       */
-      template <typename T> void dataset_paths (T& container) const {
-        for (std::map<std::string, boost::shared_ptr<io::base::detail::hdf5::Dataset> >::const_iterator it=m_datasets.begin(); it != m_datasets.end(); ++it) container.push_back(it->second->path());
-        for (std::map<std::string, boost::shared_ptr<io::base::detail::hdf5::Group> >::const_iterator it=m_groups.begin(); it != m_groups.end(); ++it) it->second->dataset_paths(container);
-      }
-
-      /**
-       * Accesses all existing sub-groups in one shot. Input has to be a std
-       * container with T = std::string and accepting push_back()
-       */
-      template <typename T> void subgroup_paths (T& container, bool recursive = true) const {
-        for (std::map<std::string, boost::shared_ptr<io::base::detail::hdf5::Group> >::const_iterator it=m_groups.begin(); it != m_groups.end(); ++it){
-          container.push_back(it->first);
-          if (recursive){
-            unsigned pos = container.size();
-            it->second->subgroup_paths(container);
-            for (unsigned p = pos; p < container.size(); ++p){
-              container[p] = it->first + "/" + container[p];
-            }
-          }
-        }
-      }
-
-      /**
-       * Callback function for group iteration. Two cases are blessed here:
-       *
-       * 1. Object is another group. In this case just instantiate the group and
-       *    recursively iterate from there
-       * 2. Object is a dataset. Instantiate it.
-       *
-       * Only hard-links are considered. At the time being, no soft links.
-       */
-      herr_t iterate_callback(hid_t group, const char *name,
-          const H5L_info_t *info);
-
-    public: //attribute support
-
-      /**
-       * Gets the current type set for an attribute
-       */
-      void gettype_attribute(const std::string& name, HDF5Type& type) const;
-
-      /**
-       * Sets a scalar attribute on the current group. Setting an existing
-       * attribute overwrites its value.
-       *
-       * @note Only simple scalars are supported for the time being
-       */
-      template <typename T> void set_attribute(const std::string& name,
-          const T& v) {
-        bob::io::base::HDF5Type dest_type(v);
-        write_attribute(name, dest_type, reinterpret_cast<const void*>(&v));
-      }
-
-      /**
-       * Reads an attribute from the current group. Raises an error if such
-       * attribute does not exist on the group. To check for existence, use
-       * has_attribute().
-       */
-      template <typename T> T get_attribute(const std::string& name) const {
-        T v;
-        bob::io::base::HDF5Type dest_type(v);
-        read_attribute(name, dest_type, reinterpret_cast<void*>(&v));
-        return v;
-      }
-
-      /**
-       * Checks if a certain attribute exists in this group.
-       */
-      bool has_attribute(const std::string& name) const;
-
-      /**
-       * Deletes an attribute
-       */
-      void delete_attribute(const std::string& name);
-
-      /**
-       * List attributes available on this dataset.
-       */
-      void list_attributes(std::map<std::string, bob::io::base::HDF5Type>& attributes) const;
-
-    public: //array attribute support
-
-      /**
-       * Sets a array attribute on the current group. Setting an existing
-       * attribute overwrites its value. If the attribute exists it is erased
-       * and re-written.
-       */
-      template <typename T, int N> void set_array_attribute(const std::string& name,
-          const blitz::Array<T,N>& v) {
-        bob::io::base::HDF5Type dest_type(v);
-        if(!bob::core::array::isCZeroBaseContiguous(v)) {
-          blitz::Array<T,N> tmp = bob::core::array::ccopy(v);
-          write_attribute(name, dest_type, reinterpret_cast<const void*>(tmp.data()));
-        }
-        else {
-          write_attribute(name, dest_type, reinterpret_cast<const void*>(v.data()));
-        }
-      }
-
-      /**
-       * Reads an attribute from the current dataset. Raises an error if such
-       * attribute does not exist on the group. To check for existence, use
-       * has_attribute().
-       */
-      template <typename T, int N> blitz::Array<T,N> get_array_attribute
-        (const std::string& name) const {
-        blitz::Array<T,N> v;
-        bob::io::base::HDF5Type dest_type(v);
-        read_attribute(name, dest_type, reinterpret_cast<void*>(v.data()));
-        return v;
-      }
-
-      /**
-       * Reads an attribute from the current dataset. Places the data in an
-       * already allocated array.
-       */
-      template <typename T, int N> void get_array_attribute
-        (const std::string& name, blitz::Array<T,N>& v) const {
-        bob::io::base::HDF5Type dest_type(v);
-        read_attribute(name, dest_type, reinterpret_cast<void*>(v.data()));
-      }
-
-    public: //buffer attribute support
-
-      /**
-       * Reads an attribute into a user buffer. It is the user's responsibility
-       * to have a buffer that represents the given type.
-       */
-      void read_attribute (const std::string& name,
-          const bob::io::base::HDF5Type& dest, void* buffer) const;
-
-      /**
-       * Writes the contents of a given buffer into the attribute.
-       */
-      void write_attribute (const std::string& name,
-          const bob::io::base::HDF5Type& dest, const void* buffer);
-
-    private: //not implemented
-
-      /**
-       * Copies the contents of an existing group -- not implemented
-       */
-      Group(const Group& other);
-
-      /**
-       * Assigns the contents of an existing group to myself -- not
-       * implemented
-       */
-      Group& operator= (const Group& other);
-
-    private: //representation
-
-      std::string m_name; ///< my name
-      boost::shared_ptr<hid_t> m_id; ///< the HDF5 Group this object points to
-      boost::weak_ptr<Group> m_parent;
-      std::map<std::string, boost::shared_ptr<Group> > m_groups;
-      std::map<std::string, boost::shared_ptr<Dataset> > m_datasets;
-      //std::map<std::string, boost::shared_ptr<Attribute> > m_attributes;
-
-  };
-
-  /**
-   * The RootGroup is a special case of the Group object that is directly
-   * attached to the File (no parents).
-   */
-  class RootGroup: public Group {
-
-    public: //api
-
-      /**
-       * Binds to the root group of a file.
-       */
-      RootGroup(boost::shared_ptr<File> parent);
-
-      /**
-       * D'tor - presently, does nothing
-       */
-      virtual ~RootGroup();
-
-      /**
-       * Get parent group
-       */
-      virtual const boost::shared_ptr<Group> parent() const {
-        return boost::shared_ptr<Group>();
-      }
-
-      /**
-       * Get parent group
-       */
-      virtual boost::shared_ptr<Group> parent() {
-        return boost::shared_ptr<Group>();
-      }
-
-      /**
-       * Filename where I'm sitting
-       */
-      virtual const std::string& filename() const;
-
-      /**
-       * Full path to myself. Constructed each time it is called.
-       */
-      virtual std::string path() const {
-        return "";
-      }
-
-      /**
-       * Access file
-       */
-      virtual const boost::shared_ptr<File> file() const {
-        return m_parent.lock();
-      }
-
-      virtual boost::shared_ptr<File> file() {
-        return m_parent.lock();
-      }
-
-    private: //representation
-
-      boost::weak_ptr<File> m_parent; ///< the file I belong to
-
-  };
-
-  /**
-   * std::string specialization
-   */
-  template <> void Group::set_attribute<std::string>(const std::string& name, const std::string& v);
-  template <> std::string Group::get_attribute(const std::string& name) const;
-
-}}}}}
-
-#endif /* BOB_IO_BASE_HDF5GROUP_H */
diff --git a/bob/io/base/include/bob.io.base/HDF5Types.h b/bob/io/base/include/bob.io.base/HDF5Types.h
deleted file mode 100644
index d19eab341873aafd33d2d4342fede82f5d7d3c79..0000000000000000000000000000000000000000
--- a/bob/io/base/include/bob.io.base/HDF5Types.h
+++ /dev/null
@@ -1,508 +0,0 @@
-/**
- * @date Wed Jun 22 17:50:08 2011 +0200
- * @author Andre Anjos <andre.anjos@idiap.ch>
- *
- * @brief A few helpers to handle HDF5 datasets in a more abstract way.
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#ifndef BOB_IO_BASE_HDF5TYPES_H
-#define BOB_IO_BASE_HDF5TYPES_H
-
-#include <vector>
-#include <string>
-#include <boost/shared_ptr.hpp>
-#include <blitz/array.h>
-#include <hdf5.h>
-
-/**
- * Checks if the version of HDF5 installed is greater or equal to some set of
- * values. (extracted from hdf5-1.8.7)
- */
-#ifndef H5_VERSION_GE
-#define H5_VERSION_GE(Maj,Min,Rel) \
- (((H5_VERS_MAJOR==Maj) && (H5_VERS_MINOR==Min) && (H5_VERS_RELEASE>=Rel)) || \
-  ((H5_VERS_MAJOR==Maj) && (H5_VERS_MINOR>Min)) || \
-  (H5_VERS_MAJOR>Maj))
-#endif
-
-#include <bob.io.base/array.h>
-
-namespace bob { namespace io { namespace base {
-
-  /**
-   * Supported types
-   */
-  typedef enum hdf5type {
-    s=0, //std::string
-    b, //bool
-    i8, //int8_t
-    i16, //int16_t
-    i32, //int32_t
-    i64, //int64_t
-    u8, //uint8_t
-    u16, //uint16_t
-    u32, //uint32_t
-    u64, //uint64_t
-    f32, //float
-    f64, //double
-    f128, //long double
-    c64, //std::complex<float>
-    c128, //std::complex<double>
-    c256, //std::complex<long double>
-    unsupported //this must be last
-  } hdf5type;
-
-  /**
-   * Converts a hdf5type enumeration into its string representation
-   */
-  const char* stringize (hdf5type t);
-
-  /**
-   * A wrapper to handle the HDF5 C-API error printing in a nicer way...
-   */
-  class HDF5ErrorStack {
-
-    public: //api
-
-      /**
-       * Binds the HDF5Error to the current default error stack.
-       */
-      HDF5ErrorStack ();
-
-      /**
-       * Binds to a specific HDF5 error stack
-       */
-      HDF5ErrorStack (hid_t stack);
-
-      /**
-       * Destructor virtualization.
-       */
-      virtual ~HDF5ErrorStack();
-
-      /**
-       * Returns the currently captured error stack
-       */
-      inline std::vector<std::string>& get() { return m_err; }
-
-      /**
-       * Clears the current error stack
-       */
-      inline void clear() { m_err.clear(); }
-
-      /**
-       * Sets muting
-       */
-      inline void mute () { m_muted = true; }
-      inline void unmute () { m_muted = false; }
-      inline bool muted () const { return m_muted; }
-
-    private: //not implemented
-
-      HDF5ErrorStack(const HDF5ErrorStack& other);
-
-      HDF5ErrorStack& operator= (const HDF5ErrorStack& other);
-
-    private: //representation
-      hid_t m_stack; ///< the stack I'm observing
-      bool m_muted; ///< if I'm currently muted
-      std::vector<std::string> m_err; ///< the current captured stack
-      herr_t (*m_func)(hid_t, void*); ///< temporary cache
-      void* m_client_data; ///< temporary cache
-
-  };
-
-  // Global default HDF5 error stack
-  extern const boost::shared_ptr<HDF5ErrorStack> DefaultHDF5ErrorStack;
-
-  /**
-   * This class defines the shape type: a counter and a variable-size hsize_t
-   * array that contains the dimensionality of a certain array. Internally, we
-   * always allocate a fixed size vector with 12 positions (after the maximum
-   * number of dimensions of a blitz::Array<T,N> + 1).
-   */
-  class HDF5Shape {
-
-# define MAX_HDF5SHAPE_SIZE 12
-
-    public: //api
-
-      /**
-       * Builds a new shape with a certain size and values. The size has to be
-       * smaller than the maximum number of supported dimensions (12).
-       */
-      template <typename T> HDF5Shape(const size_t n, const T* values):
-        m_n(n), m_shape() {
-          if (n > MAX_HDF5SHAPE_SIZE)
-            throw std::length_error("maximum number of dimensions exceeded");
-          for (size_t i=0; i<n; ++i) m_shape[i] = values[i];
-        }
-
-      /**
-       * Builds a new shape with data from a blitz::TinyVector
-       */
-      template <int N> HDF5Shape(const blitz::TinyVector<int,N>& vec):
-        m_n(N), m_shape() {
-          if (N > MAX_HDF5SHAPE_SIZE)
-            throw std::length_error("maximum number of dimensions exceeded");
-          for (size_t i=0; i<N; ++i) m_shape[i] = vec[i];
-        }
-
-      /**
-       * Allocates the shape space, but fills all with zeros
-       */
-      HDF5Shape (size_t n);
-
-      /**
-       * Default constructor (m_n = 0, no shape)
-       */
-      HDF5Shape ();
-
-      /**
-       * Copy construct the shape
-       */
-      HDF5Shape (const HDF5Shape& other);
-
-      /**
-       * Virtual destructor
-       */
-      virtual ~HDF5Shape();
-
-      /**
-       * Resets this new shape
-       */
-      HDF5Shape& operator= (const HDF5Shape& other);
-
-      /**
-       * Returns the current size of shape. If values are less than zero, the
-       * shape is not valid.
-       */
-      inline size_t n () const { return m_n; }
-
-      /**
-       * Returs a pointer to the first element of the shape
-       */
-      inline const hsize_t* get() const { return m_shape; }
-      inline hsize_t* get() { return m_shape; }
-
-      /**
-       * Copies the data from the other HDF5Shape. If the other shape is
-       * smaller, will copy up to the number of positions in the other shape,
-       * if it is bigger, will copy up to my number of positions.
-       */
-      void copy(const HDF5Shape& other);
-
-      /**
-       * Sets a TinyVector with the contents of this shape. If the tinyvector
-       * shape is smaller, will copy up to the number of positions in the
-       * current shape. If that is bigger, will copy up to my number of
-       * positions
-       */
-      template <int N> void set (blitz::TinyVector<int,N>& v) const {
-        if (N >= m_n) for (size_t i=0; i<m_n; ++i) v[i] = m_shape[i];
-        else for (size_t i=0; i<N; ++i) v[i] = m_shape[i];
-      }
-
-      /**
-       * Resets the current shape so it becomes invalid.
-       */
-      void reset();
-
-      /**
-       * Accesses a certain position of this shape (unchecked!)
-       */
-      inline const hsize_t& operator[] (size_t pos) const { return m_shape[pos]; }
-      inline hsize_t& operator[] (size_t pos) { return m_shape[pos]; }
-
-      /**
-       * Left-shift a number of positions, decreases the total size.
-       */
-      HDF5Shape& operator <<= (size_t pos);
-
-      /**
-       * Right-shift a number of positions, increases the total size. New
-       * positions are filled with 1's (ones).
-       */
-      HDF5Shape& operator >>= (size_t pos);
-
-      /**
-       * Returns the product of all dimensions
-       */
-      hsize_t product() const;
-
-      /**
-       * Compares two shapes for equality
-       */
-      bool operator== (const HDF5Shape& other) const;
-      bool operator!= (const HDF5Shape& other) const;
-
-      /**
-       * Compares a shape with a TinyVector for equality
-       */
-      template <int N>
-      bool operator== (const blitz::TinyVector<int,N>& other) const {
-        if (N != m_n) return false;
-        for (size_t i=0; i<m_n; ++i) if (m_shape[i] != other[i]) return false;
-        return true;
-      }
-
-      template <int N>
-      bool operator!= (const blitz::TinyVector<int,N>& other) const {
-        return !(*this == other);
-      }
-
-      /**
-       * Tells if this shape is invalid
-       */
-      inline bool operator! () const { return m_n == 0; }
-
-      /**
-       * Returns a tuple-like string representation for this shape
-       */
-      std::string str() const;
-
-    private: //representation
-      size_t m_n; ///< The number of valid hsize_t's in this shape
-      hsize_t m_shape[MAX_HDF5SHAPE_SIZE]; ///< The actual shape values
-
-  };
-
-  /**
-   * Support to compare data types, convert types into runtime equivalents and
-   * make our life easier when deciding what to input and output.
-   */
-  class HDF5Type {
-
-    public:
-
-      /**
-       * Specific implementations bind the type T to the support_t enum
-       */
-#     define DECLARE_SUPPORT(T) HDF5Type(const T& value);
-      DECLARE_SUPPORT(bool)
-      DECLARE_SUPPORT(int8_t)
-      DECLARE_SUPPORT(int16_t)
-      DECLARE_SUPPORT(int32_t)
-      DECLARE_SUPPORT(int64_t)
-      DECLARE_SUPPORT(uint8_t)
-      DECLARE_SUPPORT(uint16_t)
-      DECLARE_SUPPORT(uint32_t)
-      DECLARE_SUPPORT(uint64_t)
-      DECLARE_SUPPORT(float)
-      DECLARE_SUPPORT(double)
-      DECLARE_SUPPORT(long double)
-      DECLARE_SUPPORT(std::complex<float>)
-      DECLARE_SUPPORT(std::complex<double>)
-      DECLARE_SUPPORT(std::complex<long double>)
-#     undef DECLARE_SUPPORT
-
-      /**
-       * Builds the type from a string (special HDF5 handling)
-       */
-      HDF5Type(const char* value);
-      HDF5Type(const std::string& value);
-
-#     define DECLARE_SUPPORT(T,N) HDF5Type(const blitz::Array<T,N>& value);
-
-#     define DECLARE_BZ_SUPPORT(T) \
-      DECLARE_SUPPORT(T,1) \
-      DECLARE_SUPPORT(T,2) \
-      DECLARE_SUPPORT(T,3) \
-      DECLARE_SUPPORT(T,4)
-
-      DECLARE_BZ_SUPPORT(bool)
-      DECLARE_BZ_SUPPORT(int8_t)
-      DECLARE_BZ_SUPPORT(int16_t)
-      DECLARE_BZ_SUPPORT(int32_t)
-      DECLARE_BZ_SUPPORT(int64_t)
-      DECLARE_BZ_SUPPORT(uint8_t)
-      DECLARE_BZ_SUPPORT(uint16_t)
-      DECLARE_BZ_SUPPORT(uint32_t)
-      DECLARE_BZ_SUPPORT(uint64_t)
-      DECLARE_BZ_SUPPORT(float)
-      DECLARE_BZ_SUPPORT(double)
-      DECLARE_BZ_SUPPORT(long double)
-      DECLARE_BZ_SUPPORT(std::complex<float>)
-      DECLARE_BZ_SUPPORT(std::complex<double>)
-      DECLARE_BZ_SUPPORT(std::complex<long double>)
-#     undef DECLARE_BZ_SUPPORT
-#     undef DECLARE_SUPPORT
-
-      /**
-       * Default constructor, results in an unsupported type with invalid shape
-       */
-      HDF5Type();
-
-      /**
-       * Creates a HDF5Type from a type enumeration, assumes it is a scalar
-       */
-      HDF5Type(hdf5type type);
-
-      /**
-       * Creates a HDF5Type from an bob::io::base::array::typeinfo
-       */
-      HDF5Type(const bob::io::base::array::typeinfo& ti);
-
-      /**
-       * Creates a HDF5Type from a type enumeration and an explicit shape
-       */
-      HDF5Type(bob::io::base::array::ElementType eltype, const HDF5Shape& extents);
-
-      /**
-       * Creates a HDF5Type from a type enumeration and an explicit shape
-       */
-      HDF5Type(hdf5type type, const HDF5Shape& extents);
-
-      /**
-       * Creates a HDF5Type from a HDF5 Dataset, Datatype and Dataspace
-       */
-      HDF5Type(const boost::shared_ptr<hid_t>& type,
-          const HDF5Shape& extents);
-
-      /**
-       * Scalar of a certain type
-       */
-      HDF5Type(const boost::shared_ptr<hid_t>& type);
-
-      /**
-       * Copy construction
-       */
-      HDF5Type(const HDF5Type& other);
-
-      /**
-       * Virtual destructor
-       */
-      virtual ~HDF5Type();
-
-      /**
-       * Assignment
-       */
-      HDF5Type& operator= (const HDF5Type& other);
-
-      /**
-       * Checks if two types are the same
-       */
-      bool operator== (const HDF5Type& other) const;
-
-      /**
-       * Checks if two types are *not* the same
-       */
-      bool operator!= (const HDF5Type& other) const;
-
-      /**
-       * Checks if an existing object is compatible with my type
-       */
-      template <typename T> bool compatible (const T& value) const {
-        return *this == HDF5Type(value);
-      }
-
-      /**
-       * Checks if an existing object is compatible with my type
-       */
-      bool compatible (const bob::io::base::array::typeinfo& value) const;
-
-      /**
-       * Returns the HDF5Shape of this type
-       */
-      const HDF5Shape& shape() const { return m_shape; }
-
-      /**
-       * Returns the HDF5Shape of this type
-       */
-      HDF5Shape& shape() { return m_shape; }
-
-      /**
-       * Returns the equivalent HDF5 type info object for this type.
-       */
-      boost::shared_ptr<hid_t> htype() const;
-
-      /**
-       * Returns a string representation of this supported type.
-       */
-      std::string str() const;
-
-      /**
-       * Returns a string representation of the element type.
-       */
-      std::string type_str() const { return stringize(m_type); }
-
-      /**
-       * Returns the current enumeration for the type
-       */
-      inline hdf5type type() const { return m_type; }
-
-      /**
-       * Returns a mapping between the current type and the supported element
-       * types in bob::io::base::array
-       */
-      bob::io::base::array::ElementType element_type() const;
-
-      /**
-       * Copies this type information to a stock bob::io::base::array::typeinfo
-       */
-      void copy_to (bob::io::base::array::typeinfo& ti) const;
-
-    private: //representation
-
-      hdf5type m_type; ///< the precise supported type
-      HDF5Shape m_shape; ///< what is the shape of the type (scalar)
-
-  };
-
-  /**
-   * Describes ways to read a Dataset.
-   */
-  struct HDF5Descriptor {
-
-    public: //api
-
-      /**
-       * Constructor
-       */
-      HDF5Descriptor(const HDF5Type& type, size_t size = 0, bool expand = true);
-
-      /**
-       * Copy constructor
-       */
-      HDF5Descriptor(const HDF5Descriptor& other);
-
-      /**
-       * Virtual destructor
-       */
-      virtual ~HDF5Descriptor();
-
-      /**
-       * Assignment
-       */
-      HDF5Descriptor& operator= (const HDF5Descriptor& other);
-
-      /**
-       * Setup myself as I was supposed to be read from a space with N+1
-       * dimensions.
-       */
-      HDF5Descriptor& subselect();
-
-    public: //representation
-
-      HDF5Type type; ///< base type for read/write operations
-      size_t size; ///< number of objects of this type stored at dataset
-      bool expandable; ///< is this dataset expandable using this type?
-
-      /**
-       * Variables required for fast read/write operations.
-       */
-      HDF5Shape hyperslab_start; ///< offset to read/write operations
-      HDF5Shape hyperslab_count; ///< count for read/write operations
-
-  };
-
-  /**
-   * Format and returns the current HDF5 error stack. It also clears the stack
-   * before returning.
-   */
-  std::string format_hdf5_error();
-
-}}}
-
-#endif /* BOB_IO_BASE_HDF5TYPES_H */
diff --git a/bob/io/base/include/bob.io.base/HDF5Utils.h b/bob/io/base/include/bob.io.base/HDF5Utils.h
deleted file mode 100644
index 670430e2b4ffdf47d16c4953b593b89ba5352058..0000000000000000000000000000000000000000
--- a/bob/io/base/include/bob.io.base/HDF5Utils.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/**
- * @date Wed Jun 22 17:50:08 2011 +0200
- * @author Andre Anjos <andre.anjos@idiap.ch>
- *
- * @brief A bunch of private utilities to make programming against the HDF5
- * library a little bit more confortable.
- *
- * Classes and non-member methods in this file handle the low-level HDF5 C-API
- * and try to make it a little bit safer and higher-level for use by the
- * publicly visible HDF5File class. The functionality here is heavily based on
- * boost::shared_ptr's for handling automatic deletion and releasing of HDF5
- * objects. Two top-level classes do the whole work: File and Dataset. The File
- * class represents a raw HDF5 file. You can iterate with it in a very limited
- * way: create one, rename an object or delete one. The Dataset object
- * encapsulates reading and writing of data from a specific HDF5 dataset.
- * Everything is handled automatically and the user should not have to worry
- * about it too much.
- *
- * @todo Missing support for list<std::string>
- * @todo Inprint file creation time, author, comments?
- * @todo Missing support for automatic endianness conversion
- * @todo Missing true support for scalars
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#ifndef BOB_IO_BASE_HDF5UTILS_H
-#define BOB_IO_BASE_HDF5UTILS_H
-
-#include <boost/filesystem.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/enable_shared_from_this.hpp>
-#include <hdf5.h>
-
-#include <bob.io.base/HDF5Group.h>
-
-namespace bob { namespace io { namespace base { namespace detail { namespace hdf5 {
-
-  /**
-   * An HDF5 C-style file that knows how to close itself.
-   */
-  class File: public boost::enable_shared_from_this<File> {
-
-    public:
-
-      /**
-       * Creates a new HDF5 file. Optionally set the userblock size (multiple
-       * of 2 number of bytes).
-       */
-      File(const boost::filesystem::path& path, unsigned int flags,
-          size_t userblock_size=0);
-
-      /**
-       * Copies a file by creating a copy of each of its groups
-       */
-      File(const File& other);
-
-      /**
-       * Destructor virtualization
-       */
-      virtual ~File();
-
-      /**
-       * Assignment
-       */
-      File& operator= (const File& other);
-
-      /**
-       * Accesses the current location id of this file
-       */
-      const boost::shared_ptr<hid_t> location() const {
-        return m_id;
-      }
-      boost::shared_ptr<hid_t> location() {
-        return m_id;
-      }
-
-      /**
-       * Returns the userblock size
-       */
-      size_t userblock_size() const;
-
-      /**
-       * Copies the userblock into a string -- not yet implemented. If you want
-       * to do it, read the code for the command-line utilitlies h5jam and
-       * h5unjam.
-       */
-      void get_userblock(std::string& data) const;
-
-      /**
-       * Writes new data to the user block. Data is truncated up to the size
-       * set during file creation -- not yet implemented. If you want to do it,
-       * read the code for the command-line utilitlies h5jam and h5unjam.
-       */
-      void set_userblock(const std::string& data);
-
-      /**
-       * Gets the current path
-       */
-      const std::string& filename() const {
-        return m_path.string();
-      }
-
-      /**
-       * Returns the root group
-       */
-      boost::shared_ptr<RootGroup> root();
-
-      /**
-       * Resets this file, sets to read again all groups and datasets
-       */
-      void reset();
-
-      /**
-       * Flushes the current content of the file to disk
-       */
-      void flush();
-
-      /**
-       * Tells if this file is writable
-       */
-      bool writable() const;
-
-    private: //representation
-
-      const boost::filesystem::path m_path; ///< path to the file
-      unsigned int m_flags; ///< flags used to open it
-      boost::shared_ptr<hid_t> m_fcpl; ///< file creation property lists
-      boost::shared_ptr<hid_t> m_id; ///< the HDF5 id attributed to this file.
-      boost::shared_ptr<RootGroup> m_root;
-  };
-
-}}}}}
-
-#endif /* BOB_IO_BASE_HDF5UTILS_H */
diff --git a/bob/io/base/include/bob.io.base/api.h b/bob/io/base/include/bob.io.base/api.h
deleted file mode 100644
index fe714e4b8ed873031c4ba672f4d43345ef1858e0..0000000000000000000000000000000000000000
--- a/bob/io/base/include/bob.io.base/api.h
+++ /dev/null
@@ -1,304 +0,0 @@
-/**
- * @author Andre Anjos <andre.anjos@idiap.ch>
- * @date Tue  5 Nov 12:22:48 2013
- *
- * @brief Python API for bob::io::base
- */
-
-#ifndef BOB_IO_BASE_H
-#define BOB_IO_BASE_H
-
-/* Define Module Name and Prefix for other Modules
-   Note: We cannot use BOB_EXT_* macros here, unfortunately */
-#define BOB_IO_BASE_PREFIX    "bob.io.base"
-#define BOB_IO_BASE_FULL_NAME "bob.io.base._library"
-
-#include <Python.h>
-
-#include <bob.io.base/config.h>
-#include <bob.io.base/File.h>
-#include <bob.io.base/CodecRegistry.h>
-#include <bob.io.base/HDF5File.h>
-
-#include <boost/shared_ptr.hpp>
-
-/*******************
- * C API functions *
- *******************/
-
-/* Enum defining entries in the function table */
-enum _PyBobIo_ENUM{
-  PyBobIo_APIVersion_NUM = 0,
-  // Bindings for bob.io.base.File
-  PyBobIoFile_Type_NUM,
-  PyBobIoFileIterator_Type_NUM,
-  // I/O generic bindings
-  PyBobIo_AsTypenum_NUM,
-  PyBobIo_TypeInfoAsTuple_NUM,
-  PyBobIo_FilenameConverter_NUM,
-  // HDF5 bindings
-  PyBobIoHDF5File_Type_NUM,
-  PyBobIoHDF5File_Check_NUM,
-  PyBobIoHDF5File_Converter_NUM,
-  // Codec registration and de-registration
-  PyBobIoCodec_Register_NUM,
-  PyBobIoCodec_Deregister_NUM,
-  PyBobIoCodec_IsRegistered_NUM,
-  PyBobIoCodec_GetDescription_NUM,
-  // Total number of C API pointers
-  PyBobIo_API_pointers
-};
-
-/**************
- * Versioning *
- **************/
-
-#define PyBobIo_APIVersion_TYPE int
-
-/**********************************
- * Bindings for bob.io.base.File *
- **********************************/
-
-/* Type definition for PyBobIoFileObject */
-typedef struct {
-  PyObject_HEAD
-
-  /* Type-specific fields go here. */
-  boost::shared_ptr<bob::io::base::File> f;
-
-} PyBobIoFileObject;
-
-#define PyBobIoFile_Type_TYPE PyTypeObject
-
-typedef struct {
-  PyObject_HEAD
-
-  /* Type-specific fields go here. */
-  PyBobIoFileObject* pyfile;
-  Py_ssize_t curpos;
-
-} PyBobIoFileIteratorObject;
-
-#define PyBobIoFileIterator_Type_TYPE PyTypeObject
-
-/************************
- * I/O generic bindings *
- ************************/
-
-#define PyBobIo_AsTypenum_RET int
-#define PyBobIo_AsTypenum_PROTO (bob::io::base::array::ElementType et)
-
-#define PyBobIo_TypeInfoAsTuple_RET PyObject*
-#define PyBobIo_TypeInfoAsTuple_PROTO (const bob::io::base::array::typeinfo& ti)
-
-#define PyBobIo_FilenameConverter_RET int
-#define PyBobIo_FilenameConverter_PROTO (PyObject* o, const char** b)
-
-/*****************
- * HDF5 bindings *
- *****************/
-
-typedef struct {
-  PyObject_HEAD
-
-  /* Type-specific fields go here. */
-  boost::shared_ptr<bob::io::base::HDF5File> f;
-
-} PyBobIoHDF5FileObject;
-
-#define PyBobIoHDF5File_Type_TYPE PyTypeObject
-
-#define PyBobIoHDF5File_Check_RET int
-#define PyBobIoHDF5File_Check_PROTO (PyObject* o)
-
-#define PyBobIoHDF5File_Converter_RET int
-#define PyBobIoHDF5File_Converter_PROTO (PyObject* o, PyBobIoHDF5FileObject** a)
-
-/*****************************************
- * Code Registration and De-registration *
- *****************************************/
-
-#define PyBobIoCodec_Register_RET int
-#define PyBobIoCodec_Register_PROTO (const char* extension, const char* description, bob::io::base::file_factory_t factory)
-
-#define PyBobIoCodec_Deregister_RET int
-#define PyBobIoCodec_Deregister_PROTO (const char* extension)
-
-#define PyBobIoCodec_IsRegistered_RET int
-#define PyBobIoCodec_IsRegistered_PROTO (const char* extension)
-
-#define PyBobIoCodec_GetDescription_RET const char*
-#define PyBobIoCodec_GetDescription_PROTO (const char* extension)
-
-#ifdef BOB_IO_BASE_MODULE
-
-  /* This section is used when compiling `bob.io.base' itself */
-
-  /**************
-   * Versioning *
-   **************/
-
-  extern int PyBobIo_APIVersion;
-
-  /**********************************
-   * Bindings for bob.io.base.File *
-   **********************************/
-
-  extern PyBobIoFile_Type_TYPE PyBobIoFile_Type;
-  extern PyBobIoFileIterator_Type_TYPE PyBobIoFileIterator_Type;
-
-  /************************
-   * I/O generic bindings *
-   ************************/
-
-  PyBobIo_AsTypenum_RET PyBobIo_AsTypenum PyBobIo_AsTypenum_PROTO;
-
-  PyBobIo_TypeInfoAsTuple_RET PyBobIo_TypeInfoAsTuple PyBobIo_TypeInfoAsTuple_PROTO;
-
-  PyBobIo_FilenameConverter_RET PyBobIo_FilenameConverter PyBobIo_FilenameConverter_PROTO;
-
-/*****************
- * HDF5 bindings *
- *****************/
-
-  extern PyBobIoHDF5File_Type_TYPE PyBobIoHDF5File_Type;
-
-  PyBobIoHDF5File_Check_RET PyBobIoHDF5File_Check PyBobIoHDF5File_Check_PROTO;
-
-  PyBobIoHDF5File_Converter_RET PyBobIoHDF5File_Converter PyBobIoHDF5File_Converter_PROTO;
-
-/*****************************************
- * Code Registration and De-registration *
- *****************************************/
-
- PyBobIoCodec_Register_RET PyBobIoCodec_Register PyBobIoCodec_Register_PROTO;
-
- PyBobIoCodec_Deregister_RET PyBobIoCodec_Deregister PyBobIoCodec_Deregister_PROTO;
-
- PyBobIoCodec_IsRegistered_RET PyBobIoCodec_IsRegistered PyBobIoCodec_IsRegistered_PROTO;
-
- PyBobIoCodec_GetDescription_RET PyBobIoCodec_GetDescription PyBobIoCodec_GetDescription_PROTO;
-
-#else // BOB_IO_BASE_MODULE
-
-  /* This section is used in modules that use `bob.io.base's' C-API */
-
-#  if defined(NO_IMPORT_ARRAY)
-  extern void **PyBobIo_API;
-#  else
-#    if defined(PY_ARRAY_UNIQUE_SYMBOL)
-  void **PyBobIo_API;
-#    else
-  static void **PyBobIo_API=NULL;
-#    endif
-#  endif
-
-  /**************
-   * Versioning *
-   **************/
-
-# define PyBobIo_APIVersion (*(PyBobIo_APIVersion_TYPE *)PyBobIo_API[PyBobIo_APIVersion_NUM])
-
-  /*****************************
-   * Bindings for bob.io.File *
-   *****************************/
-
-# define PyBobIoFile_Type (*(PyBobIoFile_Type_TYPE *)PyBobIo_API[PyBobIoFile_Type_NUM])
-# define PyBobIoFileIterator_Type (*(PyBobIoFileIterator_Type_TYPE *)PyBobIo_API[PyBobIoFileIterator_Type_NUM])
-
-  /************************
-   * I/O generic bindings *
-   ************************/
-
-# define PyBobIo_AsTypenum (*(PyBobIo_AsTypenum_RET (*)PyBobIo_AsTypenum_PROTO) PyBobIo_API[PyBobIo_AsTypenum_NUM])
-
-# define PyBobIo_TypeInfoAsTuple (*(PyBobIo_TypeInfoAsTuple_RET (*)PyBobIo_TypeInfoAsTuple_PROTO) PyBobIo_API[PyBobIo_TypeInfoAsTuple_NUM])
-
-# define PyBobIo_FilenameConverter (*(PyBobIo_FilenameConverter_RET (*)PyBobIo_FilenameConverter_PROTO) PyBobIo_API[PyBobIo_FilenameConverter_NUM])
-
-  /*****************
-   * HDF5 bindings *
-   *****************/
-
-# define PyBobIoHDF5File_Type (*(PyBobIoHDF5File_Type_TYPE *)PyBobIo_API[PyBobIoHDF5File_Type_NUM])
-
-# define PyBobIoHDF5File_Check (*(PyBobIoHDF5File_Check_RET (*)PyBobIoHDF5File_Check_PROTO) PyBobIo_API[PyBobIoHDF5File_Check_NUM])
-
-# define PyBobIoHDF5File_Converter (*(PyBobIoHDF5File_Converter_RET (*)PyBobIoHDF5File_Converter_PROTO) PyBobIo_API[PyBobIoHDF5File_Converter_NUM])
-
-/*****************************************
- * Code Registration and De-registration *
- *****************************************/
-
-# define PyBobIoCodec_Register (*(PyBobIoCodec_Register_RET (*)PyBobIoCodec_Register_PROTO) PyBobIo_API[PyBobIoCodec_Register_NUM])
-
-# define PyBobIoCodec_Deregister (*(PyBobIoCodec_Deregister_RET (*)PyBobIoCodec_Deregister_PROTO) PyBobIo_API[PyBobIoCodec_Deregister_NUM])
-
-# define PyBobIoCodec_IsRegistered (*(PyBobIoCodec_IsRegistered_RET (*)PyBobIoCodec_IsRegistered_PROTO) PyBobIo_API[PyBobIoCodec_IsRegistered_NUM])
-
-# define PyBobIoCodec_GetDescription (*(PyBobIoCodec_GetDescription_RET (*)PyBobIoCodec_GetDescription_PROTO) PyBobIo_API[PyBobIoCodec_GetDescription_NUM])
-
-# if !defined(NO_IMPORT_ARRAY)
-
-  /**
-   * Returns -1 on error, 0 on success.
-   */
-  static int import_bob_io_base(void) {
-
-    PyObject *c_api_object;
-    PyObject *module;
-
-    module = PyImport_ImportModule(BOB_IO_BASE_FULL_NAME);
-
-    if (module == NULL) return -1;
-
-    c_api_object = PyObject_GetAttrString(module, "_C_API");
-
-    if (c_api_object == NULL) {
-      Py_DECREF(module);
-      return -1;
-    }
-
-#   if PY_VERSION_HEX >= 0x02070000
-    if (PyCapsule_CheckExact(c_api_object)) {
-      PyBobIo_API = (void **)PyCapsule_GetPointer(c_api_object,
-          PyCapsule_GetName(c_api_object));
-    }
-#   else
-    if (PyCObject_Check(c_api_object)) {
-      PyBobIo_API = (void **)PyCObject_AsVoidPtr(c_api_object);
-    }
-#   endif
-
-    Py_DECREF(c_api_object);
-    Py_DECREF(module);
-
-    if (!PyBobIo_API) {
-      PyErr_SetString(PyExc_ImportError, "cannot find C/C++ API "
-#   if PY_VERSION_HEX >= 0x02070000
-          "capsule"
-#   else
-          "cobject"
-#   endif
-          " at `" BOB_IO_BASE_FULL_NAME "._C_API'");
-      return -1;
-    }
-
-    /* Checks that the imported version matches the compiled version */
-    int imported_version = *(int*)PyBobIo_API[PyBobIo_APIVersion_NUM];
-
-    if (BOB_IO_BASE_API_VERSION != imported_version) {
-      PyErr_Format(PyExc_ImportError, BOB_IO_BASE_FULL_NAME " import error: you compiled against API version 0x%04x, but are now importing an API with version 0x%04x which is not compatible - check your Python runtime environment for errors", BOB_IO_BASE_API_VERSION, imported_version);
-      return -1;
-    }
-
-    /* If you get to this point, all is good */
-    return 0;
-
-  }
-
-# endif //!defined(NO_IMPORT_ARRAY)
-
-#endif /* BOB_IO_BASE_MODULE */
-
-#endif /* BOB_IO_BASE_H */
diff --git a/bob/io/base/include/bob.io.base/array.h b/bob/io/base/include/bob.io.base/array.h
deleted file mode 100644
index 570c09f05f52fc115cc659f207c1137e080acce0..0000000000000000000000000000000000000000
--- a/bob/io/base/include/bob.io.base/array.h
+++ /dev/null
@@ -1,255 +0,0 @@
-/**
- * @date Tue Nov 8 15:34:31 2011 +0100
- * @author Andre Anjos <andre.anjos@idiap.ch>
- *
- * @brief The array API describes a non-specific way to handle N dimensional
- * array data.
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#ifndef BOB_IO_BASE_ARRAY_INTERFACE_H
-#define BOB_IO_BASE_ARRAY_INTERFACE_H
-
-#include <stdexcept>
-#include <string>
-
-#include <boost/shared_ptr.hpp>
-#include <blitz/array.h>
-
-#include <bob.io.base/array_type.h>
-
-/* MinGW flags */
-#ifdef _WIN32
-#undef interface
-#endif
-
-/**
- * @brief Array submodule API of the I/O module
- */
-namespace bob { namespace io { namespace base { namespace array {
-
-  /**
-   * @brief Encapsulation of special type information of interfaces.
-   */
-  struct typeinfo {
-
-    ElementType dtype; ///< data type
-    size_t nd; ///< number of dimensions
-    size_t shape[BOB_MAX_DIM+1]; ///< length along each dimension
-    size_t stride[BOB_MAX_DIM+1]; ///< strides along each dimension
-
-    /**
-     * @brief Default constructor
-     */
-    typeinfo();
-
-    /**
-     * @brief Simplification to build a typeinfo from a size
-     */
-    template <typename T> typeinfo(ElementType dtype_, T nd_) {
-      set(dtype_, nd_);
-    }
-
-    /**
-     * @brief Simplification to build a typeinfo from a shape pointer.
-     */
-    template <typename T> typeinfo(ElementType dtype_, T nd_, const T* shape_) {
-      set(dtype_, nd_, shape_);
-    }
-
-    /**
-     * @brief Copies information from another typeinfo
-     */
-    typeinfo(const typeinfo& other);
-
-    /**
-     * @brief Assignment
-     */
-    typeinfo& operator= (const typeinfo& other);
-
-    /**
-     * @brief Builds with type and number of dimensions, but set the shape and
-     * strides to all zeros.
-     */
-    template <typename T>
-    void set(ElementType dtype_, T nd_) {
-      dtype = dtype_;
-      nd = nd_;
-      reset_shape();
-    }
-
-    /**
-     * @brief Set to specific values
-     */
-    template <typename T>
-    void set(ElementType dtype_, T nd_, const T* shape_) {
-      dtype = dtype_;
-      set_shape(nd_, shape_);
-    }
-
-    /**
-     * @brief Set to specific values, including strides
-     */
-    template <typename T>
-    void set(ElementType dtype_, T nd_, const T* shape_,
-        const T* stride_) {
-      dtype = dtype_;
-      nd = nd_;
-      for (size_t k=0; k<nd; ++k) {
-        shape[k] = shape_[k];
-        stride[k] = stride_[k];
-      }
-    }
-
-    /**
-     * @brief Reset to defaults -- as if uninitialized.
-     */
-    void reset();
-
-    /**
-     * @brief Is this a valid type information?
-     */
-    bool is_valid() const;
-
-    /**
-     * @brief Does this has a valid shape information?
-     */
-    bool has_valid_shape() const;
-
-    /**
-     * @brief sets the shape
-     */
-    template <typename T> void set_shape(T nd_, const T* shape_) {
-      if (nd_ > (BOB_MAX_DIM+1))
-        throw std::runtime_error("unsupported number of dimensions");
-      nd = nd_;
-      for (size_t k=0; k<nd; ++k) shape[k] = shape_[k];
-      update_strides();
-    }
-
-    /**
-     * @brief resets the shape to all zeros
-     */
-    void reset_shape();
-
-    /**
-     * @brief Update my own stride vector. Called automatically after any use
-     * of set_shape().
-     */
-    void update_strides();
-
-    /**
-     * @brief Returns the total number of elements available
-     */
-    size_t size() const;
-
-    /**
-     * @brief Returns the size of each element
-     */
-    inline size_t item_size() const { return getElementSize(dtype); }
-
-    /**
-     * @brief Returns the total size (in bytes) of the buffer that I'm
-     * associated with.
-     */
-    size_t buffer_size() const;
-
-    /**
-     * @brief Returns the item type description
-     */
-    const char* item_str() const { return stringize(dtype); }
-
-    /**
-     * @brief Checks compatibility with other typeinfo
-     */
-    bool is_compatible(const typeinfo& other) const;
-
-    /**
-     * @brief Formats and returns a string containing the full typeinfo
-     * description.
-     */
-    std::string str() const;
-
-    /**
-     * @brief Make it easy to set for blitz::Array<T,N>
-     */
-    template <typename T, int N> void set(const blitz::Array<T,N>& array) {
-      dtype = getElementType<T>();
-      set_shape(array.shape());
-    }
-
-    template <typename T, int N>
-      void set(boost::shared_ptr<blitz::Array<T,N> >& array) {
-        dtype = getElementType<T>();
-        set_shape(array->shape());
-      }
-
-    template <int N> void set_shape(const blitz::TinyVector<int,N>& tv_shape) {
-      nd = N;
-      for (size_t k=0; k<nd; ++k) shape[k] = tv_shape(k);
-      update_strides();
-    }
-
-  };
-
-  /**
-   * @brief The interface manager introduces a concept for managing the
-   * interfaces that can be handled as C-style arrays. It encapsulates methods
-   * to store and delete the buffer contents in a safe way.
-   *
-   * The interface is an entity that either stores a copy of its own data or
-   * refers to data belonging to another interface.
-   */
-  class interface {
-
-    public: //api
-
-      /**
-       * @brief By default, the interface is never freed. You must override
-       * this method to do something special for your class type.
-       */
-      virtual ~interface() { }
-
-      /**
-       * @brief Copies the data from another interface.
-       */
-      virtual void set(const interface& other) =0;
-
-      /**
-       * @brief Refers to the data of another interface.
-       */
-      virtual void set(boost::shared_ptr<interface> other) =0;
-
-      /**
-       * @brief Re-allocates this interface taking into consideration new
-       * requirements. The internal memory should be considered uninitialized.
-       */
-      virtual void set (const typeinfo& req) =0;
-
-      /**
-       * @brief Type information for this interface.
-       */
-      virtual const typeinfo& type() const =0;
-
-      /**
-       * @brief Borrows a reference from the underlying memory. This means
-       * this object continues to be responsible for deleting the memory and
-       * you should make sure that it outlives the usage of the returned
-       * pointer.
-       */
-      virtual void* ptr() =0;
-      virtual const void* ptr() const =0;
-
-      /**
-       * @brief Returns a representation of the internal cache using shared
-       * pointers.
-       */
-      virtual boost::shared_ptr<void> owner() =0;
-      virtual boost::shared_ptr<const void> owner() const =0;
-
-  };
-
-}}}}
-
-#endif /* BOB_IO_BASE_ARRAY_INTERFACE_H */
diff --git a/bob/io/base/include/bob.io.base/array_type.h b/bob/io/base/include/bob.io.base/array_type.h
deleted file mode 100644
index 89eb1e26df2000beb040f2dc47aced0429029f6e..0000000000000000000000000000000000000000
--- a/bob/io/base/include/bob.io.base/array_type.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/**
- * @date Sat Apr 9 18:10:10 2011 +0200
- * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch>
- *
- * @brief This file contains information about the supported arrays
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#ifndef BOB_IO_BASE_ARRAY_TYPE_H
-#define BOB_IO_BASE_ARRAY_TYPE_H
-
-#include <stdint.h>
-#include <cstdlib>
-#include <complex>
-
-/**
- * @ingroup IO_ARRAY
- * @brief This macro defines the maximum number of dimensions supported by bob.
- * A variable in the bob.io.array namespace is created from this macro
- * receiving the same value. Use that variable on your programs, or this macro
- * on your preprocessor code.
- */
-#define BOB_MAX_DIM 4
-
-namespace bob { namespace io { namespace base { namespace array {
-
-  /**
-   * @brief Enumeration of the supported type for multidimensional arrays
-   * @warning float128 and complex256 are defined but currently not
-   * supported
-   */
-  typedef enum ElementType {
-    t_unknown=0,
-    t_bool=1,
-    t_int8=2,
-    t_int16=3,
-    t_int32=4,
-    t_int64=5,
-    t_uint8=6,
-    t_uint16=7,
-    t_uint32=8,
-    t_uint64=9,
-    t_float32=10,
-    t_float64=11,
-    t_float128=12,
-    t_complex64=13,
-    t_complex128=14,
-    t_complex256=15
-  } ElementType;
-
-  /**
-   * @brief Maximum number of supported dimensions for multidimensional
-   * arrays.
-   */
-  const size_t N_MAX_DIMENSIONS_ARRAY = BOB_MAX_DIM;
-
-  /**
-   * @brief These are some type to element type conversions
-   */
-  template<typename T> ElementType getElementType() {
-    return t_unknown;
-  }
-
-  /**
-   * @brief Some specializations that convert type to element type.
-   */
-  template<> inline ElementType getElementType<bool>() { return t_bool; }
-  template<> inline ElementType getElementType<int8_t>() { return t_int8; }
-  template<> inline ElementType getElementType<int16_t>()
-  { return t_int16; }
-  template<> inline ElementType getElementType<int32_t>()
-  { return t_int32; }
-  template<> inline ElementType getElementType<int64_t>()
-  { return t_int64; }
-  template<> inline ElementType getElementType<uint8_t>()
-  { return t_uint8; }
-  template<> inline ElementType getElementType<uint16_t>()
-  { return t_uint16; }
-  template<> inline ElementType getElementType<uint32_t>()
-  { return t_uint32; }
-  template<> inline ElementType getElementType<uint64_t>()
-  { return t_uint64; }
-  template<> inline ElementType getElementType<float>()
-  { return t_float32; }
-  template<> inline ElementType getElementType<double>()
-  { return t_float64; }
-  template<> inline ElementType getElementType<long double>()
-  { return t_float128; }
-  template<> inline ElementType getElementType<std::complex<float> >()
-  { return t_complex64; }
-  template<> inline ElementType getElementType<std::complex<double> >()
-  { return t_complex128; }
-  template<> inline ElementType getElementType<std::complex<long double> >()
-  { return t_complex256; }
-
-  /**
-   * @brief These are some type to element size conversions
-   */
-  template<typename T> size_t getElementSize() {
-    return 0;
-  }
-
-  /**
-   * @brief Some specializations that convert the types we handle properly
-   */
-  template<> inline size_t getElementSize<bool>() { return sizeof(bool); }
-  template<> inline size_t getElementSize<int8_t>()
-  { return sizeof(int8_t); }
-  template<> inline size_t getElementSize<int16_t>()
-  { return sizeof(int16_t); }
-  template<> inline size_t getElementSize<int32_t>()
-  { return sizeof(int32_t); }
-  template<> inline size_t getElementSize<int64_t>()
-  { return sizeof(int64_t); }
-  template<> inline size_t getElementSize<uint8_t>()
-  { return sizeof(uint8_t); }
-  template<> inline size_t getElementSize<uint16_t>()
-  { return sizeof(uint16_t); }
-  template<> inline size_t getElementSize<uint32_t>()
-  { return sizeof(uint32_t); }
-  template<> inline size_t getElementSize<uint64_t>()
-  { return sizeof(uint64_t); }
-  template<> inline size_t getElementSize<float>()
-  { return sizeof(float); }
-  template<> inline size_t getElementSize<double>()
-  { return sizeof(double); }
-  template<> inline size_t getElementSize<long double>()
-  { return sizeof(long double); }
-  template<> inline size_t getElementSize<std::complex<float> >()
-  { return sizeof(std::complex<float>); }
-  template<> inline size_t getElementSize<std::complex<double> >()
-  { return sizeof(std::complex<double>); }
-  template<> inline size_t getElementSize<std::complex<long double> >()
-  { return sizeof(std::complex<long double>); }
-
-  /**
-   * @brief Returns the type size given the enumeration
-   */
-  size_t getElementSize(ElementType t);
-
-  /**
-   * @brief Gets a string representation of an element type value
-   */
-  const char* stringize(ElementType t);
-
-  /**
-   * @brief Equivalent to call stringize() on the result of
-   * getElementType<T>().
-   */
-  template<typename T> const char* stringize() {
-    return stringize(getElementType<T>());
-  }
-
-  /**
-   * @brief Returns the ElementType given the string representation
-   */
-  ElementType unstringize(const char* name);
-
-}}}}
-
-#endif /* BOB_IO_BASE_ARRAY_TYPE_H */
diff --git a/bob/io/base/include/bob.io.base/array_utils.h b/bob/io/base/include/bob.io.base/array_utils.h
deleted file mode 100644
index 8fdfa77b4d6a1bb181031152255ab4a5fd685153..0000000000000000000000000000000000000000
--- a/bob/io/base/include/bob.io.base/array_utils.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/**
- * @date Tue Nov 8 15:34:31 2011 +0100
- * @author Andre Anjos <andre.anjos@idiap.ch>
- *
- * @brief Utilities for converting data to-from blitz::Arrays and other
- * goodies.
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#ifndef BOB_IO_BASE_ARRAY_UTILS_H
-#define BOB_IO_BASE_ARRAY_UTILS_H
-
-#include <blitz/array.h>
-#include <stdint.h>
-#include <stdexcept>
-#include <boost/format.hpp>
-
-#include <bob.core/cast.h>
-#include <bob.io.base/array.h>
-
-namespace bob { namespace io { namespace base { namespace array {
-
-  /**
-   * @brief Fills in shape and stride starting from a typeinfo object
-   */
-  template <int N> void set_shape_and_stride(const typeinfo& info,
-      blitz::TinyVector<int,N>& shape, blitz::TinyVector<int,N>& stride) {
-    for (int k=0; k<N; ++k) {
-      shape[k] = info.shape[k];
-      stride[k] = info.stride[k];
-    }
-  }
-
-
-  /**
-   * @brief Takes a data pointer and assumes it is a C-style array for the
-   * defined type. Creates a wrapper as a blitz::Array<T,N> with the same
-   * number of dimensions and type. Notice that the blitz::Array<> created
-   * will have its memory tied to the passed buffer. In other words you have
-   * to make sure that the buffer outlives the returned blitz::Array<>.
-   */
-  template <typename T, int N>
-    blitz::Array<T,N> wrap(const interface& buf) {
-
-      const typeinfo& type = buf.type();
-
-      if (!buf.ptr()) throw std::runtime_error("empty buffer");
-
-      if (type.dtype != bob::io::base::array::getElementType<T>()) {
-        boost::format m("cannot efficiently retrieve blitz::Array<%s,%d> from buffer of type '%s'");
-        m % stringize<T>() % N % type.str();
-        throw std::runtime_error(m.str());
-      }
-
-      if (type.nd != N) {
-        boost::format m("cannot retrieve blitz::Array<%s,%d> from buffer of type '%s'");
-        m % stringize<T>() % N % type.str();
-        throw std::runtime_error(m.str());
-      }
-
-      blitz::TinyVector<int,N> shape;
-      blitz::TinyVector<int,N> stride;
-      set_shape_and_stride(type, shape, stride);
-
-      return blitz::Array<T,N>((T*)buf.ptr(),
-          shape, stride, blitz::neverDeleteData);
-    }
-
-
-  /**
-   * @brief Takes a data pointer and assumes it is a C-style array for the
-   * defined type. Creates a copy as a blitz::Array<T,N> with the same number
-   * of dimensions, but with a type as specified by you. If the type does not
-   * match the type of the original C-style array, a cast will happen.
-   *
-   * If a certain type cast is not supported. An appropriate exception will
-   * be raised.
-   */
-  template <typename T, int N>
-    blitz::Array<T,N> cast(const interface& buf) {
-
-      const typeinfo& type = buf.type();
-
-      if (type.nd != N) {
-        boost::format m("cannot cast blitz::Array<%s,%d> from buffer of type '%s'");
-        m % stringize<T>() % N % type.str();
-        throw std::runtime_error(m.str());
-      }
-
-      switch (type.dtype) {
-        case bob::io::base::array::t_bool:
-          return bob::core::array::cast<T>(wrap<bool,N>(buf));
-        case bob::io::base::array::t_int8:
-          return bob::core::array::cast<T>(wrap<int8_t,N>(buf));
-        case bob::io::base::array::t_int16:
-          return bob::core::array::cast<T>(wrap<int16_t,N>(buf));
-        case bob::io::base::array::t_int32:
-          return bob::core::array::cast<T>(wrap<int32_t,N>(buf));
-        case bob::io::base::array::t_int64:
-          return bob::core::array::cast<T>(wrap<int64_t,N>(buf));
-        case bob::io::base::array::t_uint8:
-          return bob::core::array::cast<T>(wrap<uint8_t,N>(buf));
-        case bob::io::base::array::t_uint16:
-          return bob::core::array::cast<T>(wrap<uint16_t,N>(buf));
-        case bob::io::base::array::t_uint32:
-          return bob::core::array::cast<T>(wrap<uint32_t,N>(buf));
-        case bob::io::base::array::t_uint64:
-          return bob::core::array::cast<T>(wrap<uint64_t,N>(buf));
-        case bob::io::base::array::t_float32:
-          return bob::core::array::cast<T>(wrap<float,N>(buf));
-        case bob::io::base::array::t_float64:
-          return bob::core::array::cast<T>(wrap<double,N>(buf));
-        case bob::io::base::array::t_float128:
-          return bob::core::array::cast<T>(wrap<long double,N>(buf));
-        case bob::io::base::array::t_complex64:
-          return bob::core::array::cast<T>(wrap<std::complex<float>,N>(buf));
-        case bob::io::base::array::t_complex128:
-          return bob::core::array::cast<T>(wrap<std::complex<double>,N>(buf));
-        case bob::io::base::array::t_complex256:
-          return bob::core::array::cast<T>(wrap<std::complex<long double>,N>(buf));
-        default:
-          break;
-      }
-
-      //if we get to this point, there is nothing much we can do...
-      throw std::runtime_error("invalid type on blitz buffer array casting -- debug me");
-
-    }
-
-}}}}
-
-#endif /* BOB_IO_BASE_ARRAY_UTILS_H */
diff --git a/bob/io/base/include/bob.io.base/blitz_array.h b/bob/io/base/include/bob.io.base/blitz_array.h
deleted file mode 100644
index 083ec1d3245d2b3bc1f92e821b71eaeffe1de0b3..0000000000000000000000000000000000000000
--- a/bob/io/base/include/bob.io.base/blitz_array.h
+++ /dev/null
@@ -1,261 +0,0 @@
-/**
- * @date Tue Nov 8 15:34:31 2011 +0100
- * @author Andre Anjos <andre.anjos@idiap.ch>
- *
- * @brief A class that implements the polimorphic behaviour required when
- * reading and writing blitz arrays to disk or memory.
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#ifndef BOB_IO_BASE_BLITZ_ARRAY_H
-#define BOB_IO_BASE_BLITZ_ARRAY_H
-
-#include <stdexcept>
-#include <boost/make_shared.hpp>
-#include <boost/format.hpp>
-#include <blitz/array.h>
-
-#include <bob.core/check.h>
-#include <bob.core/cast.h>
-#include <bob.core/array_copy.h>
-
-#include <bob.io.base/array.h>
-#include <bob.io.base/array_utils.h>
-#include <bob.io.base/array_type.h>
-
-namespace bob { namespace io { namespace base { namespace array {
-
-  /**
-   * @brief A blitz::Array representation of an array.
-   */
-  class blitz_array: public interface {
-
-    public:
-
-      /**
-       * @brief Starts by refering to the data from another blitz array.
-       */
-      blitz_array(boost::shared_ptr<blitz_array> other);
-
-      /**
-       * @brief Starts by copying the data from another blitz array.
-       */
-      blitz_array(const blitz_array& other);
-
-      /**
-       * @brief Starts by refering to the data from another buffer.
-       */
-      blitz_array(boost::shared_ptr<interface> other);
-
-      /**
-       * @brief Starts by copying the data from another buffer.
-       */
-      blitz_array(const interface& other);
-
-      /**
-       * @brief Starts with an uninitialized, pre-allocated array.
-       */
-      blitz_array(const typeinfo& info);
-
-      /**
-       * @brief Borrows the given pointer - if you use this constructor, you
-       * must make sure the pointed data outlives this object.
-       */
-      blitz_array(void* data, const typeinfo& info);
-
-      /**
-       * @brief Destroyes me
-       */
-      virtual ~blitz_array();
-
-      /**
-       * @brief Copies the data from another buffer.
-       */
-      virtual void set(const interface& other);
-
-      /**
-       * @brief Refers to the data of another buffer.
-       */
-      virtual void set(boost::shared_ptr<interface> other);
-
-      /**
-       * @brief Re-allocates this buffer taking into consideration new
-       * requirements. The internal memory should be considered uninitialized.
-       */
-      virtual void set (const typeinfo& req);
-
-      /**
-       * @brief Refers to the data of another blitz array.
-       */
-      void set(boost::shared_ptr<blitz_array> other);
-
-      /**
-       * @brief Element type
-       */
-      virtual const typeinfo& type() const { return m_type; }
-
-      /**
-       * @brief Borrows a reference from the underlying memory. This means
-       * this object continues to be responsible for deleting the memory and
-       * you should make sure that it outlives the usage of the returned
-       * pointer.
-       */
-      virtual void* ptr() { return m_ptr; }
-      virtual const void* ptr() const { return m_ptr; }
-
-      virtual boost::shared_ptr<void> owner() { return m_data; }
-      virtual boost::shared_ptr<const void> owner() const { return m_data; }
-
-
-      /******************************************************************
-       * Blitz Array specific manipulations
-       ******************************************************************/
-
-
-      /**
-       * @brief Starts me with new arbitrary data. Please note we refer to the
-       * given array. External modifications to the array memory will affect
-       * me. If you don't want that to be the case, use the const variant.
-       */
-      template <typename T, int N>
-        blitz_array(boost::shared_ptr<blitz::Array<T,N> > data) {
-          set(data);
-        }
-
-      /**
-       * @brief Starts me with new arbitrary data. Please note we copy the
-       * given array. External modifications to the array memory will not
-       * affect me. If you don't want that to be the case, start with a
-       * non-const reference.
-       */
-      template <typename T, int N>
-        blitz_array(const blitz::Array<T,N>& data) {
-          set(data);
-        }
-
-      /**
-       * @brief Starts me with new arbitrary data. Please note we don't copy
-       * the given array.
-       * @warning Any resize of the given blitz::Array after this call leads to
-       * unexpected results
-       */
-      template <typename T, int N>
-        blitz_array(blitz::Array<T,N>& data) {
-          set(data);
-        }
-
-      /**
-       * @brief This method will set my internal data to the value you
-       * specify. We will do this by referring to the data you gave.
-       */
-      template <typename T, int N>
-        void set(boost::shared_ptr<blitz::Array<T,N> > data) {
-
-          if (getElementType<T>() == t_unknown)
-            throw std::runtime_error("unsupported element type on blitz::Array<>");
-          if (N > BOB_MAX_DIM)
-            throw std::runtime_error("unsupported number of dimensions on blitz::Array<>");
-
-          if (!bob::core::array::isCContiguous(*data.get()))
-            throw std::runtime_error("cannot buffer'ize non-c contiguous array");
-
-          m_type.set(data);
-
-          m_data = data;
-          m_ptr = reinterpret_cast<void*>(data->data());
-          m_is_blitz = true;
-        }
-
-      /**
-       * @brief This method will set my internal data to the value you
-       * specify. We will do this by copying the data you gave.
-       */
-      template <typename T, int N> void set(const blitz::Array<T,N>& data) {
-        set(boost::make_shared<blitz::Array<T,N> >(bob::core::array::ccopy(data)));
-      }
-
-      /**
-       * @brief This method will set my internal data to the value you specify.
-       * We will do this by referencing the data you gave.
-       * @warning Any resize of the given blitz::Array after this call leads to
-       * unexpected results
-       */
-      template <typename T, int N> void set(blitz::Array<T,N>& data) {
-        set(boost::make_shared<blitz::Array<T,N> >(data));
-      }
-
-      /**
-       * @brief This method returns a reference to my internal data. It is the
-       * fastest way to get access to my data because it involves no data
-       * copying. This method has two limitations:
-       *
-       * 1) You need to know the correct type and number of dimensions or I'll
-       * throw an exception.
-       *
-       * 2) If this buffer was started by refering to another buffer's data
-       * which is not a blitz array, an exception will be raised.
-       * Unfortunately, blitz::Array<>'s do not offer a management mechanism
-       * for tracking external data allocation. The exception can be avoided
-       * and the referencing mechanism forced if you set the flag "temporary"
-       * to "true". In this mode, this method will always suceed, but the
-       * object returned will have its lifetime associated to this buffer. In
-       * other words, you should make sure this buffer outlives the returned
-       * blitz::Array<T,N>.
-       */
-      template <typename T, int N> blitz::Array<T,N> get(bool temporary=false) {
-
-        if (m_is_blitz) {
-
-          if (!m_data) throw std::runtime_error("empty blitz array");
-
-          if (m_type.dtype != getElementType<T>()) {
-            boost::format m("cannot efficiently retrieve blitz::Array<%s,%d> from buffer of type '%s'");
-            m % stringize<T>() % N % m_type.str();
-            throw std::runtime_error(m.str());
-          }
-
-          if (m_type.nd != N) {
-            boost::format m("cannot retrieve blitz::Array<%s,%d> from buffer of type '%s'");
-            m % stringize<T>() % N % m_type.str();
-            throw std::runtime_error(m.str());
-          }
-
-          return *boost::static_pointer_cast<blitz::Array<T,N> >(m_data).get();
-        }
-
-        else {
-
-          if (temporary) { //returns a temporary reference
-            return bob::io::base::array::wrap<T,N>(*this);
-          }
-
-          else {
-            throw std::runtime_error("cannot get() external non-temporary non-blitz array buffer -- for a temporary object, set temporary=true; if you need the returned object to outlive this buffer; use copy() or cast()");
-          }
-        }
-
-      }
-
-      /**
-       * @brief This method returns a copy to my internal data (not a
-       * reference) in the type you wish. It is the easiest method to use
-       * because I'll never throw, no matter which type you want to receive
-       * data at. Only get the number of dimensions right!
-       */
-      template <typename T, int N> blitz::Array<T,N> cast() const {
-        return bob::io::base::array::cast<T,N>(*this);
-      }
-
-    private: //representation
-
-      typeinfo m_type; ///< type information
-      void* m_ptr; ///< pointer to the data
-      bool m_is_blitz; ///< true if initiated with a blitz::Array<>
-      boost::shared_ptr<void> m_data; ///< Pointer to the data owner
-
-  };
-
-}}}}
-
-#endif /* BOB_IO_BASE_BLITZ_ARRAY_H */
diff --git a/bob/io/base/include/bob.io.base/config.h b/bob/io/base/include/bob.io.base/config.h
deleted file mode 100644
index cc07a9a3aae777e470d3db3ce142916b9d4ea859..0000000000000000000000000000000000000000
--- a/bob/io/base/include/bob.io.base/config.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * @author Andre Anjos <andre.anjos@idiap.ch>
- * @date Fri  1 Nov 07:10:59 2013
- *
- * @brief General directives for all modules in bob.io
- */
-
-#ifndef BOB_IO_BASE_CONFIG_H
-#define BOB_IO_BASE_CONFIG_H
-
-/* Macros that define versions and important names */
-#define BOB_IO_BASE_API_VERSION 0x0201
-
-
-#ifdef BOB_IMPORT_VERSION
-
-  /***************************************
-  * Here we define some functions that should be used to build version dictionaries in the version.cpp file
-  * There will be a compiler warning, when these functions are not used, so use them!
-  ***************************************/
-
-  #include <Python.h>
-  #include <boost/preprocessor/stringize.hpp>
-  #include <hdf5.h>
-
-  /**
-  * The version of HDF5
-  */
-  static PyObject* hdf5_version() {
-    boost::format f("%s.%s.%s");
-    f % BOOST_PP_STRINGIZE(H5_VERS_MAJOR);
-    f % BOOST_PP_STRINGIZE(H5_VERS_MINOR);
-    f % BOOST_PP_STRINGIZE(H5_VERS_RELEASE);
-    return Py_BuildValue("s", f.str().c_str());
-  }
-
-  /**
-   * bob.io.base c/c++ api version
-   */
-  static PyObject* bob_io_base_version() {
-    return Py_BuildValue("{ss}", "api", BOOST_PP_STRINGIZE(BOB_IO_BASE_API_VERSION));
-  }
-
-#endif // BOB_IMPORT_VERSION
-
-
-#endif /* BOB_IO_BASE_CONFIG_H */
diff --git a/bob/io/base/include/bob.io.base/reorder.h b/bob/io/base/include/bob.io.base/reorder.h
deleted file mode 100644
index 09ebf50422392cb6da05b255c4d9738f5d71d445..0000000000000000000000000000000000000000
--- a/bob/io/base/include/bob.io.base/reorder.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/**
- * @date Tue Nov 22 11:24:44 2011 +0100
- * @author Andre Anjos <andre.anjos@idiap.ch>
- *
- * @brief Row-major to column-major reordering and vice-versa
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#ifndef BOB_IO_BASE_REORDER_H
-#define BOB_IO_BASE_REORDER_H
-
-#include <stdint.h>
-
-#include <bob.io.base/array.h>
-
-namespace bob { namespace io { namespace base {
-
-  /**
-   * Returns, on the first argument, the linear indexes by calculating the
-   * linear positions relative to both row-major and column-major order
-   * matrixes given a certain index accessing a position in the matrix and the
-   * matrix shape
-   *
-   * @param row The resulting row-major linear index.
-   *            (row,col) is a 2-tuple with the results: row-major and
-   *            column-major linear indexes
-   * @param col The resulting column-major linear index. (see above)
-   * @param i   Index of the column.
-   *            (i,j) a 2-tuple with the indexes as would be accessed
-   *            [col][row]; this is the same as accessing the matrix like
-   *            on directions [y][x]
-   * @param j   Index of the row. (see above)
-   * @param shape a 2-tuple with the matrix shape like [col][row]; this is the
-   *        same as thinking about the extends of the matrix like on directions
-   *        [y][x]
-   *
-   * Detailed arithmetics with graphics and explanations can be found here:
-   * http://webster.cs.ucr.edu/AoA/Windows/HTML/Arraysa2.html
-   */
-  void rc2d(size_t& row, size_t& col, const size_t i, const size_t j,
-      const size_t* shape);
-
-  /**
-   * Same as above, but for a 3D array organized as [depth][column][row]
-   */
-  void rc3d(size_t& row, size_t& col, const size_t i, const size_t j,
-      const size_t k, const size_t* shape);
-
-  /**
-   * Same as above, but for a 4D array organized as [time][depth][column][row]
-   */
-  void rc4d(size_t& row, size_t& col, const size_t i, const size_t j,
-      const size_t k, const size_t l, const size_t* shape);
-
-  /**
-   * Converts the data from row-major order (C-Style) to column major order
-   * (Fortran style). Input parameters are the src data in row-major order, the
-   * destination (pre-allocated) array of the same size and the type
-   * information.
-   */
-  void row_to_col_order(const void* src_, void* dst_, const
-      bob::io::base::array::typeinfo& info);
-
-  /**
-   * Converts the data from column-major order (Fortran-Style) to row major
-   * order (C style), which is required by bob. Input parameters are the src
-   * data in column-major order, the destination (pre-allocated) array of the
-   * same size and the type information.
-   */
-  void col_to_row_order(const void* src_, void* dst_,
-      const bob::io::base::array::typeinfo& info);
-
-  /**
-   * Converts the data from row-major order (C-Style) to column major order
-   * (Fortran style). Input parameters are the src data in row-major order, the
-   * destination (pre-allocated) array of the same size and the type
-   * information.
-   */
-  void row_to_col_order_complex(const void* src_, void* dst_re_,
-      void* dst_im_, const bob::io::base::array::typeinfo& info);
-
-  /**
-   * Converts the data from column-major order (Fortran-Style) to row major
-   * order (C style), which is required by bob. Input parameters are the src
-   * data in column-major order, the destination (pre-allocated) array of the
-   * same size and the type information.
-   */
-  void col_to_row_order_complex(const void* src_re_, const void* src_im_,
-      void* dst_, const bob::io::base::array::typeinfo& info);
-
-}}}
-
-#endif /* BOB_IO_BASE_REORDER_H */
diff --git a/bob/io/base/include/bob.io.base/utils.h b/bob/io/base/include/bob.io.base/utils.h
deleted file mode 100644
index c42b1fac659dca6956dd241916aeeb2670c134c8..0000000000000000000000000000000000000000
--- a/bob/io/base/include/bob.io.base/utils.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/**
- * @author Andre Anjos <andre.anjos@idiap.ch>
- * @date Wed  3 Oct 07:46:49 2012
- *
- * @brief Utilities for easy manipulation of filed data.
- */
-
-#ifndef BOB_IO_BASE_BASE_UTILS_H
-#define BOB_IO_BASE_BASE_UTILS_H
-
-#include <boost/shared_ptr.hpp>
-
-#include <bob.io.base/File.h>
-
-namespace bob { namespace io { namespace base {
-
-  /**
-   * Creates a new array codec using the filename extension to determine which
-   * codec to use. The opening mode is passed to the underlying registered File
-   * implementation.
-   *
-   * Here are the meanings of the mode flag:
-   *
-   * 'r': opens for reading only - no modifications can occur; it is an
-   *      error to open a file that does not exist for read-only operations.
-   * 'w': opens for reading and writing, but truncates the file if it
-   *      exists; it is not an error to open files that do not exist with
-   *      this flag.
-   * 'a': opens for reading and writing - any type of modification can
-   *      occur. If the file does not exist, this flag is effectively like
-   *      'w'.
-   */
-  boost::shared_ptr<File> open (const char* filename, char mode);
-
-  /**
-   * Opens the file pretending it has a different extension (that is, using a
-   * different codec) then the one expected (if any). This allows you to write
-   * a file with the extension you want, but still using one of the available
-   * codecs.
-   */
-  boost::shared_ptr<File> open (const char* filename, char mode,
-      const char* pretend_extension);
-
-  /**
-   * Peeks the file and returns the typeinfo for reading individual frames (or
-   * samples) from the file.
-   *
-   * This method is equivalent to calling open() with 'r' as mode flag and then
-   * calling type() on the returned bob::io::base::File object.
-   */
-  bob::io::base::array::typeinfo peek (const char* filename);
-
-  /**
-   * Peeks the file and returns the typeinfo for reading the whole contents in
-   * a single shot.
-   *
-   * This method is equivalent to calling open() with 'r' as mode flag and then
-   * calling type_all() on the returned bob::io::base::File object.
-   */
-  bob::io::base::array::typeinfo peek_all (const char* filename);
-
-  /**
-   * Opens for reading and load all contents
-   *
-   * This method is equivalent to calling open() with 'r' as mode flag and then
-   * calling read_all() on the returned bob::io::base::File object.
-   */
-  template <typename T, int N> blitz::Array<T,N> load (const char* filename) {
-    return open(filename, 'r')->read_all<T,N>();
-  }
-
-  /**
-   * Opens for reading and load a particular frame (or sample)
-   *
-   * This method is equivalent to calling open() with 'r' as mode flag and then
-   * calling read(index) on the returned bob::io::base::File object.
-   */
-  template <typename T, int N> blitz::Array<T,N> load (const char* filename, size_t index) {
-    return open(filename, 'r')->read<T,N>(index);
-  }
-
-  /**
-   * Opens for appending and add an array to it
-   *
-   * This method is equivalent to calling open() with 'a' as mode flag and then
-   * calling append(data) on the returned bob::io::base::File object.
-   */
-  template <typename T, int N> void append (const char* filename, const blitz::Array<T,N>& data) {
-    open(filename, 'a')->append(data);
-  }
-
-  /**
-   * Opens for writing and write an array to it. If the file exists before the
-   * call to this method, it is truncated.
-   *
-   * This method is equivalent to calling open() with 'w' as mode flag and then
-   * calling write(data) on the returned bob::io::base::File object.
-   */
-  template <typename T, int N> void save (const char* filename, const blitz::Array<T,N>& data) {
-    open(filename, 'w')->write(data);
-  }
-
-}}}
-
-#endif /* BOB_IO_BASE_BASE_UTILS_H */
diff --git a/bob/io/base/main.cpp b/bob/io/base/main.cpp
deleted file mode 100644
index 01a82d992e510b3c85ff5aad299e0c6b1347f487..0000000000000000000000000000000000000000
--- a/bob/io/base/main.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
-/**
- * @author Andre Anjos <andre.anjos@idiap.ch>
- * @date Fri 25 Oct 16:54:55 2013
- *
- * @brief Bindings to bob::io
- */
-
-#define BOB_IO_BASE_MODULE
-#include <bob.io.base/api.h>
-
-#ifdef NO_IMPORT_ARRAY
-#undef NO_IMPORT_ARRAY
-#endif
-#include <bob.blitz/capi.h>
-#include <bob.blitz/cleanup.h>
-#include <bob.extension/documentation.h>
-
-extern bool init_File(PyObject* module);
-extern bool init_HDF5File(PyObject* module);
-
-/**
- * Creates an str object, from a C or C++ string. Returns a **new
- * reference**.
- */
-static PyObject* make_object(const char* s) {
-  return Py_BuildValue("s", s);
-}
-
-static auto s_extensions = bob::extension::FunctionDoc(
-  "extensions",
-  "Returns a dictionary containing all extensions and descriptions currently stored on the global codec registry",
-  "The extensions are returned as a dictionary from the filename extension to a description of the data format."
-)
-.add_prototype("", "extensions")
-.add_return("extensions", "{str : str}", "A dictionary of supported extensions");
-static PyObject* PyBobIo_Extensions(PyObject*) {
-BOB_TRY
-  typedef std::map<std::string, std::string> map_type;
-  const map_type& table = bob::io::base::CodecRegistry::getExtensions();
-
-  PyObject* retval = PyDict_New();
-  if (!retval) return 0;
-  auto retval_ = make_safe(retval);
-
-  for (auto it=table.begin(); it!=table.end(); ++it) {
-    PyObject* pyvalue = make_object(it->second.c_str());
-    if (!pyvalue) return 0;
-    auto p_ = make_safe(pyvalue);
-    if (PyDict_SetItemString(retval, it->first.c_str(), pyvalue) != 0) {
-      return 0;
-    }
-  }
-
-  return Py_BuildValue("O", retval);
-BOB_CATCH_FUNCTION("extensions", 0);
-}
-
-static PyMethodDef module_methods[] = {
-    {
-      s_extensions.name(),
-      (PyCFunction)PyBobIo_Extensions,
-      METH_NOARGS,
-      s_extensions.doc(),
-    },
-    {0}  /* Sentinel */
-};
-
-PyDoc_STRVAR(module_docstr, "Core bob::io classes and methods");
-
-int PyBobIo_APIVersion = BOB_IO_BASE_API_VERSION;
-
-#if PY_VERSION_HEX >= 0x03000000
-static PyModuleDef module_definition = {
-  PyModuleDef_HEAD_INIT,
-  BOB_EXT_MODULE_NAME,
-  module_docstr,
-  -1,
-  module_methods,
-  0, 0, 0, 0
-};
-#endif
-
-static PyObject* create_module (void) {
-
-# if PY_VERSION_HEX >= 0x03000000
-  PyObject* m = PyModule_Create(&module_definition);
-  auto m_ = make_xsafe(m);
-  const char* ret = "O";
-# else
-  PyObject* m = Py_InitModule3(BOB_EXT_MODULE_NAME, module_methods, module_docstr);
-  const char* ret = "N";
-# endif
-  if (!m) return 0;
-
-  /* register some constants */
-  if (!init_File(m)) return 0;
-  if (!init_HDF5File(m)) return 0;
-
-  static void* PyBobIo_API[PyBobIo_API_pointers];
-
-  /* exhaustive list of C APIs */
-
-  /**************
-   * Versioning *
-   **************/
-
-  PyBobIo_API[PyBobIo_APIVersion_NUM] = (void *)&PyBobIo_APIVersion;
-
-  /**********************************
-   * Bindings for bob.io.base.File *
-   **********************************/
-
-  PyBobIo_API[PyBobIoFile_Type_NUM] = (void *)&PyBobIoFile_Type;
-
-  PyBobIo_API[PyBobIoFileIterator_Type_NUM] = (void *)&PyBobIoFileIterator_Type;
-
-  /************************
-   * I/O generic bindings *
-   ************************/
-
-  PyBobIo_API[PyBobIo_AsTypenum_NUM] = (void *)PyBobIo_AsTypenum;
-
-  PyBobIo_API[PyBobIo_TypeInfoAsTuple_NUM] = (void *)PyBobIo_TypeInfoAsTuple;
-
-  PyBobIo_API[PyBobIo_FilenameConverter_NUM] = (void *)PyBobIo_FilenameConverter;
-
-  /*****************
-   * HDF5 bindings *
-   *****************/
-
-  PyBobIo_API[PyBobIoHDF5File_Type_NUM] = (void *)&PyBobIoHDF5File_Type;
-
-  PyBobIo_API[PyBobIoHDF5File_Check_NUM] = (void *)&PyBobIoHDF5File_Check;
-
-  PyBobIo_API[PyBobIoHDF5File_Converter_NUM] = (void *)&PyBobIoHDF5File_Converter;
-
-/*****************************************
- * Code Registration and De-registration *
- *****************************************/
-
-  PyBobIo_API[PyBobIoCodec_Register_NUM] = (void *)&PyBobIoCodec_Register;
-
-  PyBobIo_API[PyBobIoCodec_Deregister_NUM] = (void *)&PyBobIoCodec_Deregister;
-
-  PyBobIo_API[PyBobIoCodec_IsRegistered_NUM] = (void *)&PyBobIoCodec_IsRegistered;
-
-  PyBobIo_API[PyBobIoCodec_GetDescription_NUM] = (void *)&PyBobIoCodec_GetDescription;
-
-#if PY_VERSION_HEX >= 0x02070000
-
-  /* defines the PyCapsule */
-
-  PyObject* c_api_object = PyCapsule_New((void *)PyBobIo_API,
-      BOB_EXT_MODULE_PREFIX "." BOB_EXT_MODULE_NAME "._C_API", 0);
-
-#else
-
-  PyObject* c_api_object = PyCObject_FromVoidPtr((void *)PyBobIo_API, 0);
-
-#endif
-
-  if (!c_api_object) return 0;
-
-  if (PyModule_AddObject(m, "_C_API", c_api_object) < 0) return 0;
-
-  /* imports dependencies */
-  if (import_bob_blitz() < 0) return 0;
-
-  return Py_BuildValue(ret, m);
-}
-
-PyMODINIT_FUNC BOB_EXT_ENTRY_NAME (void) {
-# if PY_VERSION_HEX >= 0x03000000
-  return
-# endif
-    create_module();
-}
diff --git a/bob/io/base/test.cpp b/bob/io/base/test.cpp
deleted file mode 100644
index 559535a05ce6f8adbbbfc9cdbc7c81c41044bb2a..0000000000000000000000000000000000000000
--- a/bob/io/base/test.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-/**
- * @author Manuel Gunther
- * @date Tue Sep 13 13:01:31 MDT 2016
- *
- * @brief Tests for bob::io::base
- */
-
-#include <bob.io.base/api.h>
-#include <bob.blitz/cleanup.h>
-#include <bob.extension/documentation.h>
-
-#include <boost/format.hpp>
-#include <boost/filesystem.hpp>
-
-static auto s_test_api = bob::extension::FunctionDoc(
-  "_test_api",
-  "Some tests for API functions"
-)
-.add_prototype("tempdir")
-.add_parameter("tempdir", "str", "A temporary directory to write data to")
-;
-static PyObject* _test_api(PyObject*, PyObject *args, PyObject* kwds){
-BOB_TRY
-  static char** kwlist = s_test_api.kwlist();
-
-  const char* tempdir;
-  if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &tempdir)) return 0;
-
-  blitz::Array<uint8_t, 1> test_data(5);
-  for (int i = 0; i < 5; ++i){
-    test_data(i) = i+1;
-  }
-
-  auto h5file = bob::io::base::CodecRegistry::instance()->findByExtension(".hdf5");
-
-  boost::filesystem::path hdf5(tempdir); hdf5 /= std::string("test.h5");
-
-  auto output = h5file(hdf5.string().c_str(), 'w');
-  output->write(test_data);
-  output.reset();
-
-  auto input = h5file(hdf5.string().c_str(), 'r');
-  blitz::Array<uint8_t,1> read_data(input->read<uint8_t,1>(0));
-
-  // Does not compile at the moment
-  blitz::Array<uint16_t,1> read_data_2(input->cast<uint16_t,1>(0));
-
-  input.reset();
-
-  if (blitz::any(test_data - read_data))
-    throw std::runtime_error("The HDF5 IO test did not succeed");
-
-  if (blitz::any(test_data - read_data_2))
-    throw std::runtime_error("The HDF5 IO test did not succeed");
-
-  Py_RETURN_NONE;
-BOB_CATCH_FUNCTION("_test_api", 0)
-}
-
-static PyMethodDef module_methods[] = {
-  {
-    s_test_api.name(),
-    (PyCFunction)_test_api,
-    METH_VARARGS|METH_KEYWORDS,
-    s_test_api.doc(),
-  },
-  {0}  /* Sentinel */
-};
-
-PyDoc_STRVAR(module_docstr, "Tests for bob::io::base");
-
-#if PY_VERSION_HEX >= 0x03000000
-static PyModuleDef module_definition = {
-  PyModuleDef_HEAD_INIT,
-  BOB_EXT_MODULE_NAME,
-  module_docstr,
-  -1,
-  module_methods,
-  0, 0, 0, 0
-};
-#endif
-
-static PyObject* create_module (void) {
-
-# if PY_VERSION_HEX >= 0x03000000
-  PyObject* m = PyModule_Create(&module_definition);
-  auto m_ = make_xsafe(m);
-  const char* ret = "O";
-# else
-  PyObject* m = Py_InitModule3(BOB_EXT_MODULE_NAME, module_methods, module_docstr);
-  const char* ret = "N";
-# endif
-  if (!m) return 0;
-
-  return Py_BuildValue(ret, m);
-}
-
-PyMODINIT_FUNC BOB_EXT_ENTRY_NAME (void) {
-# if PY_VERSION_HEX >= 0x03000000
-  return
-# endif
-    create_module();
-}
diff --git a/bob/io/base/test/__init__.py b/bob/io/base/test/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/bob/io/base/test/data/cmyk.jpg b/bob/io/base/test/data/cmyk.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..3ed9423c9e19ec5e61298dc7dfb963e31f02a5b4
Binary files /dev/null and b/bob/io/base/test/data/cmyk.jpg differ
diff --git a/bob/io/base/test/data/grace_hopper.png b/bob/io/base/test/data/grace_hopper.png
new file mode 100644
index 0000000000000000000000000000000000000000..4a63320ab28dc6812e5eb89b1d7d50af0dbb0dcc
Binary files /dev/null and b/bob/io/base/test/data/grace_hopper.png differ
diff --git a/bob/io/base/test/data/img_gray_alpha.png b/bob/io/base/test/data/img_gray_alpha.png
new file mode 100644
index 0000000000000000000000000000000000000000..7643ce025d21ec8385a93836180167d3ce62167e
Binary files /dev/null and b/bob/io/base/test/data/img_gray_alpha.png differ
diff --git a/bob/io/base/test/data/img_indexed_color.png b/bob/io/base/test/data/img_indexed_color.png
new file mode 100644
index 0000000000000000000000000000000000000000..c21427b328350a26155841013e461fa46e406be5
Binary files /dev/null and b/bob/io/base/test/data/img_indexed_color.png differ
diff --git a/bob/io/base/test/data/img_indexed_color_alpha.png b/bob/io/base/test/data/img_indexed_color_alpha.png
new file mode 100644
index 0000000000000000000000000000000000000000..defabb829d44bcd28b8939afbc64c1b3f9143342
Binary files /dev/null and b/bob/io/base/test/data/img_indexed_color_alpha.png differ
diff --git a/bob/io/base/test/data/img_rgba_color.png b/bob/io/base/test/data/img_rgba_color.png
new file mode 100644
index 0000000000000000000000000000000000000000..0e6d2a10a91f3c36cb64f94ca00e6b971109f259
Binary files /dev/null and b/bob/io/base/test/data/img_rgba_color.png differ
diff --git a/bob/io/base/test/data/img_trns.png b/bob/io/base/test/data/img_trns.png
new file mode 100644
index 0000000000000000000000000000000000000000..7c16aab16960149a4762610eb8c6827c0814600d
Binary files /dev/null and b/bob/io/base/test/data/img_trns.png differ
diff --git a/bob/io/base/data/matlab_1d.hdf5 b/bob/io/base/test/data/matlab_1d.hdf5
similarity index 100%
rename from bob/io/base/data/matlab_1d.hdf5
rename to bob/io/base/test/data/matlab_1d.hdf5
diff --git a/bob/io/base/data/matlab_2d.hdf5 b/bob/io/base/test/data/matlab_2d.hdf5
similarity index 100%
rename from bob/io/base/data/matlab_2d.hdf5
rename to bob/io/base/test/data/matlab_2d.hdf5
diff --git a/bob/io/base/test/data/test.gif b/bob/io/base/test/data/test.gif
new file mode 100644
index 0000000000000000000000000000000000000000..8c770fb7b60d43b03b89dc695425e811339963b3
Binary files /dev/null and b/bob/io/base/test/data/test.gif differ
diff --git a/bob/io/base/test/data/test.jpg b/bob/io/base/test/data/test.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..0bf2deb6a8f29793c1ae15a880aef370c43d01fc
Binary files /dev/null and b/bob/io/base/test/data/test.jpg differ
diff --git a/bob/io/base/test/data/test.pbm b/bob/io/base/test/data/test.pbm
new file mode 100644
index 0000000000000000000000000000000000000000..0902b226f358f3b4703342c59f93200c3263d880
--- /dev/null
+++ b/bob/io/base/test/data/test.pbm
@@ -0,0 +1,3 @@
+P4
+4 6
+�@  @
\ No newline at end of file
diff --git a/bob/io/base/test/data/test.pgm b/bob/io/base/test/data/test.pgm
new file mode 100644
index 0000000000000000000000000000000000000000..32cd7fae38dc8850cb7ce244908ba749eb364327
Binary files /dev/null and b/bob/io/base/test/data/test.pgm differ
diff --git a/bob/io/base/test/data/test.ppm b/bob/io/base/test/data/test.ppm
new file mode 100644
index 0000000000000000000000000000000000000000..a5baf843114a68f76cdc36e96658bfbcd782b3eb
Binary files /dev/null and b/bob/io/base/test/data/test.ppm differ
diff --git a/bob/io/base/data/test1.hdf5 b/bob/io/base/test/data/test1.hdf5
similarity index 100%
rename from bob/io/base/data/test1.hdf5
rename to bob/io/base/test/data/test1.hdf5
diff --git a/bob/io/base/data/test7_unlimited.hdf5 b/bob/io/base/test/data/test7_unlimited.hdf5
similarity index 100%
rename from bob/io/base/data/test7_unlimited.hdf5
rename to bob/io/base/test/data/test7_unlimited.hdf5
diff --git a/bob/io/base/test/data/test_2.pgm b/bob/io/base/test/data/test_2.pgm
new file mode 100644
index 0000000000000000000000000000000000000000..863c6e80fd1144a2612fd5cd1044476c21f096d1
Binary files /dev/null and b/bob/io/base/test/data/test_2.pgm differ
diff --git a/bob/io/base/test/data/test_2.ppm b/bob/io/base/test/data/test_2.ppm
new file mode 100644
index 0000000000000000000000000000000000000000..a285afec5845554bfff4f6845393cccccbff4b46
Binary files /dev/null and b/bob/io/base/test/data/test_2.ppm differ
diff --git a/bob/io/base/data/test_array_codec.txt b/bob/io/base/test/data/test_array_codec.txt
similarity index 100%
rename from bob/io/base/data/test_array_codec.txt
rename to bob/io/base/test/data/test_array_codec.txt
diff --git a/bob/io/base/test/data/test_corrupted.pbm b/bob/io/base/test/data/test_corrupted.pbm
new file mode 100644
index 0000000000000000000000000000000000000000..5d28f04a058d99b95b7d813898dafdef75e9c2fa
--- /dev/null
+++ b/bob/io/base/test/data/test_corrupted.pbm
@@ -0,0 +1,3 @@
+P4
+4 6
+�@  @a
diff --git a/bob/io/base/test/data/test_corrupted.pgm b/bob/io/base/test/data/test_corrupted.pgm
new file mode 100644
index 0000000000000000000000000000000000000000..8f34579e2f6c6710677b5689d15099638912a948
Binary files /dev/null and b/bob/io/base/test/data/test_corrupted.pgm differ
diff --git a/bob/io/base/test/data/test_corrupted.ppm b/bob/io/base/test/data/test_corrupted.ppm
new file mode 100644
index 0000000000000000000000000000000000000000..fa528857de00ad3392bee8a35be1e94e06ffa500
Binary files /dev/null and b/bob/io/base/test/data/test_corrupted.ppm differ
diff --git a/bob/io/base/test/data/test_spaces.pgm b/bob/io/base/test/data/test_spaces.pgm
new file mode 100644
index 0000000000000000000000000000000000000000..e1d116b5e620659222a461abf0a1f139db853242
--- /dev/null
+++ b/bob/io/base/test/data/test_spaces.pgm
@@ -0,0 +1,6 @@
+P5
+# CREATOR: GIMP PNM Filter Version 1.1
+
+100 100
+255
+[\[YXY\[^^]`]aaa`d_`ba_b`aad`ddage��jhilpkjsuqnkqquypmstqrk{wrtxuxttvvww{{zxz{{w{|}}���~��������XYYYZ[^_]\_[\^^]\baabb^bbfg`aggiii}��ooitt}�x~tq|xq�lpozupt�stzuu{uywxzyzxz}zz{{zz�}�|~����������X\Z]_[][\^__^^_`__a]f_ca_``\bee`dhw�ypp~�k��op��zw~wpu|�}vvwvwwvx|wy{{}y}|z~}}�}��~}�����~�����YZ[[\]][\]]\_]^```bc`_acbaaccbadwr{x��rx~|uy��~�|z���yqs|ux�}{yyy~vuxux{wy}zz{z{}}�}~�������������WZ\\[[Z_aZ^]^_a^]]_``a_cbccdcbfn`mvw|ggdgo{y�ot�������uw{v����{~x�v{yxzy}x||{{z}~�~~|���~��������Z]]X^`^\^]`_``a_`a_^cbbbbhaeabhlninoTAE>;_]lok^gtm����y����������vwzywxyz{zxwy~{|}y}�~�����������_[[[]]\```]]`a_]cbaa_`ccabdfbhlvxuqUA:9/36=CMRX_|wo~����^`�su{w���~�zzxz{|y{{||}}~~|��~����������XZ[\_]]``a[]_^\__`Zdaa__eddbdabfxv\;6@ADB:2<D@J\d�~�no�p}���������}�}}}xyyxz|��{}{|~~��������������^\[Y\\Z\\^^^`^^^^^b^baacccegbfqil[D;EA:S@PLNMOakXlrxlmvtlQa��zy��������Ëzyxy|z{{|�|~��|}}������X\\][^]]Z^]\``_`_aab`abbcaefdheqYSE:NF28:;:GIKLGlfY`lo]MM>eoexi�����������~y{||{~{||�}����~��������]`]Z\\`^^^]b_^a`aa]b`aaab`bccem^FJL?K4:QPdA;E[J@UJKWNehN]\Vgkns����ڲ�����z|{}z~||}}~��~��������YY^]^]\a`^_a^````^d_acbbfabdbfcYZ;9MKEPXu~f?]?YQl^G^>4>LK>QWSfjlz�����������zzz|~�|�|}���}��������\][][\\a\_`\^[a^_b`b^bdabbg`gbWRHE<>RQ_rr��rB<PfTQcNE=8=7:?SCPkbki���ǫ������z|}}{~{�~~����~�����]]^\[_^\_Z]_adac]`bc_c`hfbefgdROI;A7NN\hs���UK_UIKc@640-060<Vethgg{���ǻ����{xx}z�|z~��~}���|���[\\]]\Z^_^_^__a`\aa``^d`ddfggUAFZLI57LALkz{q^XhlbD:D7/5(3)-?<>YDa_qw������ȼ��y|{|~�||���~���~���\Y[\[Y`c_]\\_b^^]a``cccdgebg_I?CTZJG87B=Ubig^U\GO^P525F)/9::1B?^VhHgz������ҝ�~}{{{||�~�������Z\\\^b^\]a`b`da_a^_`bbebcbda^n_LMRLC<2+<MPXIDL@L`XV..8+0+I1"!9E33nuNWt�����ͷ��}z}{��|~}��}�������`\_^_\^]\Zcb`__`]`[j\bbadbg^VPZWHA<F;;/8>M@H;=BGF&6<>4**>(%35,87U�\SRf����ɹ����zz~}�~���~�������[\ZaaZ^a^c^cdc`b_bbedecdee`IJ@CC@FNE?94*%7D4;59B4.+$2 %2?,.86239=6EZhk����΢�|��}}~}}�|����������^\\a\[`^][b__bad[ad``geedgZFLNID@:?27601 09/NENCUWA=;(%%&8)6+),:0.?\DSfr���л����|{|{|~|�~�������]WZ]b`]]aa_ba`c_cbbdb_edf`IRHXD878.14($&0$./LIYOPVk_?/ 3C/"0/:<94Yea`ax����Ǒ����{}}z�}~{�}~~���][[Z^]]]]^_b\c_aa_d^_cffgUPPT=3/85-'#40)46411YVi^j{�s+(,334(252::Db�vp|~����ؙ��ë�~���{|����������]]\]^^`_ab`^`]`c__eebbdg`VHK323812/&%*975.+309AFVTX;=P05+'8-618CNCx~a������ù�����͇��|}~�����z����\[`_`_Y[Z\_a\`_a^cbjdf`cGLF@/129*10-**,363CG+/;177+"12%91%*99407kuf~�w~sw���������֣�����}}|~�����\^\]\^__b`__```dac`eadcRILB87398:*$/&(,1+/;5."2;/$%#5)-->( 306<6W�ivIRWjwl{�������׺�����}�~�~����\]]]]]_]`^b`_b_a]bc_c\PHCE:;.3,=4)/.,&!(5=BL4)+'0%$#+,.5@(8/75KGM�~aX\oY_JSl�������Ѷ���~}�|��~����Y\]_`^a[^a^\c^]c`afc_VHGH@A843=:,0*+&,.0&?J7;7)+.*,#/+3><66177?V^�t@Ll�JRIX`x�¦}��ͣ����|��~��~����\\Z[]a_[^]cb`abdaace`ME2E<?5<<;6:/2/*1440::G;7+$)3*)*+=580F:;ATV�]]g=<UBDDG^~������Ʈ�Ț�}~�~���~~�]]^]``]^]`ca^b]ab_d^ZQ0-B57/<0A?==9@F88;@?;/(.+710/1-4@9;HC?EDUR_hh@18AJGXZpq���������Ӗ���~���}����\_\_][^\a\[acb_bccaaP2&0=55C5<>9<I<.4;H:25,&&14,172.0J437%8?LU_MYyV5;7@XbL[viy�������������}������\`]^b^]_aa^_a^abdb_\V8:7101@35G:P>*:A=40.9%./<95750-9DAN4/<>0LeVCPS`P,J`lnqSTw���Ȥ���������{}}~~^]^_a]]cbb__]\^^`aa[QN9>&&,0,3IHL:/%-159345;5>B773.6IC4<=O246+_jFQPQfKZx�sjj�������������|�~~~��`]`bc]\^b`bbab^bea`VHH/1H%4,09?C<.2-26<8;""<GX>@;7<M?8>F78A>4:h?DMVNI^����n��������������~~~|�~~�[]^`a]^`aaa`bb_bb[ZKEK@+A61'*HFI2)7HE@>:,/*4DF:A=<7;K:DXhM?<<<3=B4?HRLRf}~�zx�������Ŵ��}{}~z}�|��~]\Z]aab``d_aa`]b^QM>=TG-@>/&4IBZ28;;FQ:'202HH>CIIB>7F@>DZtsaDK7_kC<D<TQ`kx�����������ʓ����}|�����\Y[^]`^`\_^bbb`a[C>F3O>7=92<7CKN7=;F?:=?:JF=FGCMNG?7L9FBRUmpry~�etfGJKs������d�������С��}z}�}|��|��^^^__b`]a_bdbceb`O@7.H;;@6;@G>PN-*+/8+$ -4DNQWSQLKD9M4EKTUYjrx�roo��_UU~�x�ci���s����հ�~}�~}}~��~[^]^`[[aacbc`bcbcO@4?;81=>,6O=JH6*-)4#'1FP\^caWSLRH9B4R_[W^[]}�|�ny��IYpw��r]t`~����ظ�}}~{{}}~�]a_^a_a```_^c_bf`AAK246$=4'.S>EI5-4+8-9GUiqmkgZWTPU?EJXZ_f_YHSGPl���lDg|��~ajvTi����ʢ�~~�||�~{�`^````b^_bdbb`bh`OMN263)0/''B24@D.-26@LZanqprkYVUW_HIRXQiaefWHNOihl���R]���suiJG\����ƚ��z�|}|}|��`^a^a^cb_]`c\_cfTVYT:@5%(6+340IN23;:GWahrovqo^S_]dNAJ]dijkkcL_S_\CYv��m���xaf7Sg����Н|���|x�z|{�}][`^]^c__aaccbbeNWV;[M5%$(0052?R67GCDQ\lqqosq\Y\ccSNGUfbowocRN[eGY|��}����xR[<.mk��ӵ�|�}}}|zy|�]a^_`]_^_c`cccdcH\RI=;4'+)-%:,78>=KUKNbioos|sfg[ec^cQTWncmzYjpinXX����~n�ukYEO+wo���Λ}�}�~�}}z�~`a`\a]c_`__aae`YMRE;=7?2-!,4:,&4JTJRTRVlvzw{ymkadoi_dY]asugTc_qkqI\�|VVt�v`B:F:^s���¦���~~~�~~�}�_aa_d__]_dbd`ceY@>D8:==10/%17% :9OTSVgkqy{y��qs�w\t`pq`\ZQVQkebjx�hNTZhpsGF79AT@u��ѱ�x|x|�||}��``_^dbf^aaibdca^6@?9QC"\tE 1;ELS_ijplry��xz�}uhcw�yJY_RVTss����eU{qtS?88GTE_��ѧ�}}y�|||}}||}]^_]b]_]^_b^cbejG9=@7!%
)ZbiN?6&<?FFMhwvro~|}������y|���|_Qpslop�����ǖP:;9UbJS~�գ�zz|y|}~|~z}`^_^^``_`caaQPZVL52/$!,!#GOxsm`^P4?JRUQScvtyxz�������y�|��zW_u��ĸ����ۮ�\-:PMHXbo�ڕy~{yz}}|~~z~^a`a_aacbbbefQ:31--&))4' >qcJZdUJW^J^ic_[TR_kf}��������pon^K[b���̾�����ǔjQB4;\cWa�ԓ�|{{{}{{}z{~|}```_]`ffbbccefUB7-/8B>1%<�|iw{���~nZy�}zhjc`_o�}�������ysmz��l|�������ȸ�\:70:QaQW�ɓy{{||{}{{z}|}`]_^^aanle``]_d]OFWKI;!"$V�vWh���~|�x~}}ylnnpucv���������tmhgcvxp�������ɫmQK/;QfSi���|yz|||y}{|}||^]\_a`]adeeeebac]_YZJ(7X��b�������~������{}�wm~������sl����������������ƑYT.DKiL���~z{yyxz~}y|}]^_^_`aaabb]bbc`d_`K1(@Y��w��������������uhivru�����n����������������߽�woF6BNc^t��x�v{yyy{{}}{y}\\\aaaa_]ab`da`dcabK* .>d��v�}~�ztlnhkfZgnlZPuvy���s�������������������~��D8GM_i���|�uxzzxzz~xwxv[_]_^^_\^b``cbaa`b^?0@Ak��w�xvfn���y{usiSWMPlynq�����wfbdo{�������������9@AQic���|xz{u{wzzu{z{}x][\b__^_^]a_cbddfcb;&<L8k��s�{zx[Tml[XVONEU]Y`dw������xils{�����������ȍ��1F@Ws|w��xwyy{uu{{~xxys|^]^]aa]`]a^\dddecdi63JiBg��y����heQ<6;HIKPUhh}po���Ǔzd^RG=HWl���������r�8OIm}�~�yyxxvww~yuxxxzxx`[___b^a_cab``abddn@(<^n6^��{������wWPX^X]dagdrFn���Н�xfelmsx�����������]�^LU�����suvwuuxvz{x{wyvy\][[Z\_]_`^^_d^c`acK6CPc?n��~���������{�~{qio��N_����ž�~����������������U��Tl�����xvwvuvutwtwtzywy]\\\\_`[^^\``^`d`bkV=7NAAr��������������������wBx�����߾����������������ƽ[��S����~zwytvxwxvwywyxxvv`]^]^[^^^^_`ac^b^biMB??23�}��z����������������J[����Ǭ��IJ��������������ӥt��V��ij�zuvuvwuzxqrwvwvx{_]_[__`_^[_b__abbbi`LBA:.tv������������������jMs����ֶ���Ƽ�������������ےl�zX��Ӯ�|vusuxzwyyyswyuwx[]]]]_^_c``^a^_`bdagI>BH4hb�����������������{Jq�����������̸�������������}m��S�ͥ��twuwvuuwvtyyuwvuw[[[\^Z[_aa_ba^a_bd_deJHV7i������������������Vh��������������������������xpz�S��Ů�}vwwtsvwsvtwuuvwy[\[_]^_^a^_^`^`c`bdccWPJ=jav���|uz��������w`ey�������������ʽ����������宀u��Z��ͣ�~uxwuutuusvtutzuwY]^\_^][aab`eac`[_debh\K7Tmw����|oqnqvspi__oz{��������������Ƚ���������띆���^�����}wqrwxvsrruvxxwxuZ[_Z]][\\]]^^]`\cbachd`Z=KZs����~wxohvtrtx�|rms�������|���������������㪜���_�����yxqutsorrsrrtptvr\^[[ZZb]]^^`_bab^_]`ad_^MNGE��������������yWfq��������|q|�ɾ�����������ʳŴ���{}yrusrossssruusouwvxXXX]]^]``\^^bc`_bb_`bab^XA@=���������������qIr}��������n���������������ɯ��f��|rnrnonlrnsosqtrvpsvuZUa^[Y`_]]_]c\bacb_cc`ba_-83��������������~dQ{����������f|�������������俼��P�twqsrnpnmqorutrrqquvyu_][][W^_\^[b_a^][_`]bb_\Y,B/q������{������~bR����������ht�������������𖕭m�trmlorvponoonsntorsvsqtYZ]]Y\[]\\a__]^[`^daac_SI,F?U�������������wk]nkjv����ߣ��~��������������hm�|}pqonopmqprsqprptpqrsqqnYY\[_]]^\^]\_[^`a[^__b__UZ0\6������~�}���}zt[YHhouÝ}�����������������a�W��oppnnmlnoquoqqprssqsqtx]\\_^Y_\^[\a\^a`]^___^`_ag)`4�����|}����~yvsbb_m����������������������hgowrklmootornpopqpnotsqpsqrX]Z\\][[\X\\^_]\_a_a]d_`bbEWIs������z����{|w{v|��Ǿ������������������Srmmnlollnomprspnqrurqrqrso\Y[\YZ\Z^\]]\^]__^[[[ac``]_.[C�����|zx��������������ʿ����������������~ZtknkmllnolqmppqronsrqppoppuVX\Y[[UV\_\^b[]\^a^]_^``abd6^T������uy}����������������®�������������ljnmllmqnnomlnpmnomqprtqpporp]Y[[Y[^][[Y][]_Y[\]]^^^_\\`\&gl�����~xux~��~������������װ�������������MomkhmljpnnoloonnpopqmnpnqmomXWWZW[Z\_Y\][`YZ\[]c]^^_c^cbL8������yvy{�}�������������ο�֤��������Grlimjkjhihljjlllnooppqopmmpos[YXWX\X[ZZ\\\[\\\]]]\``__c_bd(l�������~������������������¶�������l\qkehigkkjklinlmmpoompplpnspmV[W[XYZ[\][[X]X]]Z]Z^]^]c_cb$��������~~t�s][_o����������̥���������Dk�rhkhkhkmjnlmommromnolminqsuX[YXYY\Y\\[^\[]W^][a\\_`cbS&"a�������|om[UN:))<HE@,3Ks������������Z<��hlffijhmijknnlhkknplmlkmmnmZZW\Y\[W\YX[^]`[^]a^]`c]cB$!)��������mkhNOLB-'.)1>Q���Ө���������R5u�VYspiiikhlllklmklknlllkkknmYW[`Z[YVX^\^ZX\Z]ZZZ][[eA!"#
"2d����}yojlpfj[GMJDBBt���Ϯ�������� X]rNPa7_mpmjfhomplpnlhkkmlillkV[WXXZ]_[V[[[YZ^Y]\\__a=$#  !3R{�}yxzumnppnkmdiejfd�����ë�������6inWeATgNBCOkjljjiknkojoonqmmkkoVXZZYWXTY[YZ\]^[Z\Z[bK,.<Wm}zwvwvswsmbhbjsvlgz�į���Ϫ�����+)Mg_>OYgFG?GdomjhjkimkhqllgmlolXZZWWV]ZXZ\ZZZ[[\aa`6(!"+;Sdouxstqnyxonhjmo�����������չ����F**J\2MXgOHADCMgmjikjjllmkmkjmmmWXW\XYZZYZ\\Z[\\[^G' "/:Qaqqnrtxw|zvsniiqs}~�������������B'%-JT2AZZEJIBC>>HcijijhiigjkjlmjYWZV[ZZWZ[YX[\Z^T4!):VZgrkiov}���}zokms~������������ϑ; (Ea/=NSL?BDC?A?DRdkmhmokkkkjilWYVWYZWYWXZY\`Z=&!+;:[]ormgou�}���}{w~����������������</I]1@FER9=FA>:@B@JYljeikkkjhjiUWV]XZZ\ZYZ\_E'!!-=6TXlkmunqy~��y�z}��������������y5! *>^7<?7N79=?>>;;;>BPjrmjiihkkjXWUW]XZZXX`B*""(:5MZgimoktqz��������������������ۙd) !+C_6::7I16898:73:8;BHexrllnhieXVSZX[Y_YE' %#&2:LSbehoojmwx|�w����������������χQ! #,JT4645C-2857316/273<IcoipphjfWVXW[^]@.& 
 3G>W]addhmkjru{{{��������������xP&"&.PV0730<+334210//03377?Xz`OdkkTWYXY4**!7C<QXfe``gihokosv{rqx�����ҷ���שcE.LT1.3.6.12//.+0.,.2/69;QgsdZkVY\>,.#  7D=LU[kb[hgcmncimpkho|vp�ɫ���޸�N>%#2XT,,,42,*/-(+,,),/-3128>PWhyaXT4(#!2ABMRTcd_[_hfommjd_]gt��满���ƠiA4"(6ZJ0*(-0+,(,0&)/))+*+++68?IUftP.*!  
4AF>YR]fjcb_dkqt�~zux���ޭ���Ӯ�U<)!&7\D0),/0.*+')*+%+(()(')/08=KXd+"  !(AG;JTYfmlfc_am~�xmry}��ү��κ��O9';Y<+(/070*+%')++)%'(((**05=AKZ"# !>DF@TY^gnmhjefjxww{}���������tK<  ,?O6)$+..1'')*&)'(''&'$'&,/9;AK
diff --git a/bob/io/base/test/test_hdf5.py b/bob/io/base/test/test_hdf5.py
new file mode 100644
index 0000000000000000000000000000000000000000..437709ff465a79c37619a004054f03b47e48b3f2
--- /dev/null
+++ b/bob/io/base/test/test_hdf5.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+# vim: set fileencoding=utf-8 :
+# Tiago de Freitas Pereira <tiago.pereira@idiap.ch>
+#
+# Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland
+
+"""Tests for the base HDF5 infrastructure
+"""
+
+import os
+from bob.io.base import load, save
+from .test_utils import temporary_filename
+
+
+import numpy as np
+import random
+
+
+def read_write_check(data):
+    """Testing loading and save different file types"""
+
+    tmpname = temporary_filename()
+
+    try:
+
+        save(data, tmpname)
+        data2 = load(tmpname)
+    finally:
+        os.unlink(tmpname)
+
+    assert np.allclose(data, data2, atol=10e-5, rtol=10e-5)
+
+
+def test_type_support():
+
+    # This test will go through all supported types for reading/writing data
+    # from to HDF5 files. One single file will hold all data for this test.
+    # This is also supported with HDF5: multiple variables in a single file.
+
+    N = 100
+
+    data = [int(random.uniform(0, 100)) for z in range(N)]
+
+    read_write_check(np.array(data, np.int8))
+    read_write_check(np.array(data, np.uint8))
+    read_write_check(np.array(data, np.int16))
+    read_write_check(np.array(data, np.uint16))
+    read_write_check(np.array(data, np.int32))
+    read_write_check(np.array(data, np.uint32))
+    read_write_check(np.array(data, np.int64))
+    read_write_check(np.array(data, np.uint64))
+    read_write_check(np.array(data, np.float32))
+    read_write_check(np.array(data, np.float64))
+    read_write_check(np.array(data, np.complex64))
+    read_write_check(np.array(data, np.complex128))
diff --git a/bob/io/base/test/test_image_support.py b/bob/io/base/test/test_image_support.py
new file mode 100644
index 0000000000000000000000000000000000000000..437169912ff226a588a30e2285b7e9b21d8977bf
--- /dev/null
+++ b/bob/io/base/test/test_image_support.py
@@ -0,0 +1,152 @@
+#!/usr/bin/env python
+# vim: set fileencoding=utf-8 :
+# Laurent El Shafey <laurent.el-shafey@idiap.ch>
+# Wed Aug 14 12:27:57 CEST 2013
+#
+# Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland
+
+"""Runs some image tests
+"""
+
+import os
+import numpy
+
+from bob.io.base import load, write
+from .test_utils import datafile, temporary_filename
+
+# import bob.io.image
+import nose
+
+
+# These are some global parameters for the test.
+PNG_INDEXED_COLOR = datafile("img_indexed_color.png", __name__)
+PNG_INDEXED_COLOR_ALPHA = datafile("img_indexed_color_alpha.png", __name__)
+PNG_RGBA_COLOR = datafile("img_rgba_color.png", __name__)
+PNG_GRAY_ALPHA = datafile("img_gray_alpha.png", __name__)
+PNG_tRNS = datafile("img_trns.png", __name__)
+
+
+def test_png_indexed_color():
+    # Read an indexed color PNG image, and compared with hardcoded values
+
+    img = load(PNG_INDEXED_COLOR)
+    assert img.shape == (3, 22, 32)
+    assert img[0, 0, 0] == 255
+    assert img[0, 17, 17] == 117
+
+
+def test_png_rgba_color():
+    # Read an indexed color PNG image, and compared with hardcoded values
+    img = load(PNG_RGBA_COLOR)
+    assert img.shape == (3, 22, 32)
+    assert img[0, 0, 0] == 255
+    assert img[0, 17, 17] == 117
+
+
+def test_png_indexed_color_alpha():
+    # Read an indexed color+alpha PNG image, and compared with hardcoded values
+    img = load(PNG_INDEXED_COLOR_ALPHA)
+    assert img.shape == (3, 22, 32)
+    assert img[0, 0, 0] == 255
+    assert img[0, 17, 17] == 117
+
+
+def test_png_indexed_trns():
+    # Read an tRNS PNG image (without alpha), and compared with hardcoded values
+    img = load(PNG_tRNS)
+    assert img.shape == (3, 22, 32)
+    assert img[0, 0, 0] == 255
+    assert img[0, 17, 17] == 117
+
+
+def test_png_gray_alpha():
+    # Read a gray+alpha PNG image, and compared with hardcoded values
+
+    img = load(PNG_GRAY_ALPHA)
+
+    assert img.shape == (22, 32)
+    assert img[0, 0] == 255
+    assert img[17, 17] == 51
+
+
+def transcode(filename):
+
+    tmpname = temporary_filename(suffix=os.path.splitext(filename)[1])
+    tmpnam_ = temporary_filename(suffix=os.path.splitext(filename)[1])
+
+    try:
+        # complete transcoding test
+        image = load(filename)
+
+        # save with the same extension
+        write(image, tmpname)
+
+        # reload the image from the file
+        image2 = load(tmpname)
+
+        assert numpy.array_equal(image, image2)
+
+        # test getting part of the image as well
+        if len(image.shape) == 3:
+            subsample = image[:, ::2, ::2]
+        else:
+            subsample = image[::2, ::2]
+
+        assert not subsample.flags.contiguous
+        write(subsample, tmpnam_)
+        image3 = load(tmpnam_)
+        assert numpy.array_equal(subsample, image3)
+
+    finally:
+        if os.path.exists(tmpname):
+            os.unlink(tmpname)
+        if os.path.exists(tmpnam_):
+            os.unlink(tmpnam_)
+
+
+def test_netpbm():
+
+    transcode(datafile("test.pbm", __name__))  # indexed, works fine
+    transcode(datafile("test.pgm", __name__))  # indexed, works fine
+    transcode(datafile("test.ppm", __name__))  # indexed, works fine
+    transcode(datafile("test_2.pgm", __name__))  # indexed, works fine
+    # transcode(datafile("test_2.ppm", __name__))  # indexed, works fine ----> THIS DOES NOT WORK
+    transcode(datafile("test_spaces.pgm", __name__))  # indexed, works fine
+
+    # transcode(datafile("test.jpg", __name__))  # does not work
+    # because of re-compression
+
+
+def notest_gif():
+    transcode(datafile("test.gif", __name__))
+
+
+def test_image_load():
+    # test that the generic bob.io.image.load function works as expected
+    for filename in (
+        "test.jpg",
+        "cmyk.jpg",
+        "test.pbm",
+        "test_corrupted.pbm",
+        "test.pgm",
+        "test_corrupted.pgm",
+        "test.ppm",
+        "test_corrupted.ppm",
+        "test.gif",
+    ):
+
+        full_file = datafile(filename, __name__)
+
+        # load with just image name
+        i1 = load(full_file)
+
+        assert i1.shape == (6, 4)
+
+    # Loading the last pgm file
+    full_file = datafile("test_spaces.pgm", __name__)
+    load(full_file).shape == (100, 100)
+
+    # Testing exception
+    nose.tools.assert_raises(
+        RuntimeError, lambda x: load(os.path.splitext(x)[0] + ".unknown"), full_file
+    )
diff --git a/bob/io/base/test/test_io.py b/bob/io/base/test/test_io.py
new file mode 100644
index 0000000000000000000000000000000000000000..7a31cda62c3d29180e155d192f6d82fda1c05fa1
--- /dev/null
+++ b/bob/io/base/test/test_io.py
@@ -0,0 +1,96 @@
+import nose
+import numpy as np
+import os
+from bob.io.base import vstack_features, save, load
+from .test_utils import temporary_filename
+
+
+def test_io_vstack():
+
+    paths = [1, 2, 3, 4, 5]
+
+    def oracle(reader, paths):
+        return np.vstack([reader(p) for p in paths])
+
+    def reader_same_size_C(path):
+        return np.arange(10).reshape(5, 2)
+
+    def reader_different_size_C(path):
+        return np.arange(2 * path).reshape(path, 2)
+
+    def reader_same_size_F(path):
+        return np.asfortranarray(np.arange(10).reshape(5, 2))
+
+    def reader_different_size_F(path):
+        return np.asfortranarray(np.arange(2 * path).reshape(path, 2))
+
+    def reader_same_size_C2(path):
+        return np.arange(30).reshape(5, 2, 3)
+
+    def reader_different_size_C2(path):
+        return np.arange(6 * path).reshape(path, 2, 3)
+
+    def reader_same_size_F2(path):
+        return np.asfortranarray(np.arange(30).reshape(5, 2, 3))
+
+    def reader_different_size_F2(path):
+        return np.asfortranarray(np.arange(6 * path).reshape(path, 2, 3))
+
+    def reader_wrong_size(path):
+        return np.arange(2 * path).reshape(2, path)
+
+    # when same_size is False
+    for reader in [
+        reader_different_size_C,
+        reader_different_size_F,
+        reader_same_size_C,
+        reader_same_size_F,
+        reader_different_size_C2,
+        reader_different_size_F2,
+        reader_same_size_C2,
+        reader_same_size_F2,
+    ]:
+        np.all(vstack_features(reader, paths) == oracle(reader, paths))
+
+    # when same_size is True
+    for reader in [
+        reader_same_size_C,
+        reader_same_size_F,
+        reader_same_size_C2,
+        reader_same_size_F2,
+    ]:
+        np.all(vstack_features(reader, paths, True) == oracle(reader, paths))
+
+    with nose.tools.assert_raises(AssertionError):
+        vstack_features(reader_wrong_size, paths)
+
+    # test actual files
+    paths = [temporary_filename(), temporary_filename(), temporary_filename()]
+    try:
+        # try different readers:
+        for reader in [
+            reader_different_size_C,
+            reader_different_size_F,
+            reader_same_size_C,
+            reader_same_size_F,
+            reader_different_size_C2,
+            reader_different_size_F2,
+            reader_same_size_C2,
+            reader_same_size_F2,
+        ]:
+            # save some data in files
+            for i, path in enumerate(paths):
+                save(reader(i + 1), path)
+            # test when all data is present
+            reference = oracle(load, paths)
+            np.all(vstack_features(load, paths) == reference)
+            os.remove(paths[0])
+            # Check if RuntimeError is raised when one of the files is missing
+            with nose.tools.assert_raises(RuntimeError):
+                vstack_features(load, paths)
+    finally:
+        try:
+            for path in paths:
+                os.remove(path)
+        except Exception:
+            pass
diff --git a/bob/io/base/test_utils.py b/bob/io/base/test/test_utils.py
similarity index 100%
rename from bob/io/base/test_utils.py
rename to bob/io/base/test/test_utils.py
diff --git a/bob/io/base/test_cpp.py b/bob/io/base/test_cpp.py
deleted file mode 100644
index a9f4e06bea775e012ede089dbc9034918a9414c0..0000000000000000000000000000000000000000
--- a/bob/io/base/test_cpp.py
+++ /dev/null
@@ -1,11 +0,0 @@
-from bob.io.base._test import _test_api
-
-import tempfile
-import shutil
-
-def test_api():
-  temp_dir = tempfile.mkdtemp()
-  try:
-    _test_api(temp_dir)
-  finally:
-    shutil.rmtree(temp_dir)
diff --git a/bob/io/base/test_file.py b/bob/io/base/test_file.py
deleted file mode 100644
index 12b24850e618e3036273a9a71263161804ab913e..0000000000000000000000000000000000000000
--- a/bob/io/base/test_file.py
+++ /dev/null
@@ -1,232 +0,0 @@
-#!/usr/bin/env python
-# vim: set fileencoding=utf-8 :
-# Andre Anjos <andre.anjos@idiap.ch>
-# Wed Nov 16 13:27:15 2011 +0100
-#
-# Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland
-
-"""A combined test for all built-in types of Array/interaction in
-python.
-"""
-
-import os
-import sys
-import numpy
-import nose.tools
-
-from . import load, write, peek, peek_all, File, test_utils
-
-def test_peek():
-
-  f = test_utils.datafile('test1.hdf5', __name__)
-  assert peek(f) == (numpy.uint16, (3,), (1,))
-  assert peek_all(f) == (numpy.uint16, (3,3), (3,1))
-
-def test_iteration():
-
-  fname = test_utils.datafile('matlab_2d.hdf5', __name__)
-  f = File(fname, 'r')
-  nose.tools.eq_(len(f), 512)
-
-  objs = load(fname)
-
-  for l, i in zip(objs, f):
-    assert numpy.allclose(l, i)
-
-def test_indexing():
-
-  fname = test_utils.datafile('matlab_2d.hdf5', __name__)
-  f = File(fname, 'r')
-  nose.tools.eq_(len(f), 512)
-
-  objs = load(fname)
-  nose.tools.eq_(len(f), len(objs))
-
-  # simple indexing
-  assert numpy.allclose(f[0], objs[0])
-  assert numpy.allclose(f[1], objs[1])
-  assert numpy.allclose(f[-1], objs[-1])
-  assert numpy.allclose(f[-2], objs[-2])
-
-def test_slicing_empty():
-
-  fname = test_utils.datafile('matlab_2d.hdf5', __name__)
-  f = File(fname, 'r')
-
-  objs = f[1:1]
-  assert objs.shape == tuple()
-
-def test_slicing_0():
-
-  fname = test_utils.datafile('matlab_2d.hdf5', __name__)
-  f = File(fname, 'r')
-
-  objs = f[:]
-  for i, k in enumerate(load(fname)):
-    assert numpy.allclose(k, objs[i])
-
-def test_slicing_1():
-
-  fname = test_utils.datafile('matlab_2d.hdf5', __name__)
-  f = File(fname, 'r')
-
-  # get slice
-  s1 = f[3:10:2]
-  nose.tools.eq_(len(s1), 4)
-  assert numpy.allclose(s1[0], f[3])
-  assert numpy.allclose(s1[1], f[5])
-  assert numpy.allclose(s1[2], f[7])
-  assert numpy.allclose(s1[3], f[9])
-
-def test_slicing_2():
-
-  fname = test_utils.datafile('matlab_2d.hdf5', __name__)
-  f = File(fname, 'r')
-
-  # get negative slicing
-  s = f[-10:-2:3]
-  nose.tools.eq_(len(s), 3)
-  assert numpy.allclose(s[0], f[len(f)-10])
-  assert numpy.allclose(s[1], f[len(f)-7])
-  assert numpy.allclose(s[2], f[len(f)-4])
-
-def test_slicing_3():
-
-  fname = test_utils.datafile('matlab_2d.hdf5', __name__)
-  f = File(fname, 'r')
-
-  # get negative stepping slice
-  s = f[20:10:-3]
-  nose.tools.eq_(len(s), 4)
-  assert numpy.allclose(s[0], f[20])
-  assert numpy.allclose(s[1], f[17])
-  assert numpy.allclose(s[2], f[14])
-  assert numpy.allclose(s[3], f[11])
-
-def test_slicing_4():
-
-  fname = test_utils.datafile('matlab_2d.hdf5', __name__)
-  f = File(fname, 'r')
-
-  # get all negative slice
-  s = f[-10:-20:-3]
-  nose.tools.eq_(len(s), 4)
-  assert numpy.allclose(s[0], f[len(f)-10])
-  assert numpy.allclose(s[1], f[len(f)-13])
-  assert numpy.allclose(s[2], f[len(f)-16])
-  assert numpy.allclose(s[3], f[len(f)-19])
-
-@nose.tools.raises(TypeError)
-def test_indexing_type_check():
-
-  f = File(test_utils.datafile('matlab_2d.hdf5', __name__), 'r')
-  nose.tools.eq_(len(f), 512)
-  f[4.5]
-
-@nose.tools.raises(IndexError)
-def test_indexing_boundaries():
-
-  f = File(test_utils.datafile('matlab_2d.hdf5', __name__), 'r')
-  nose.tools.eq_(len(f), 512)
-  f[512]
-
-@nose.tools.raises(IndexError)
-def test_indexing_negative_boundaries():
-  f = File(test_utils.datafile('matlab_2d.hdf5', __name__), 'r')
-  nose.tools.eq_(len(f), 512)
-  f[-513]
-
-def transcode(filename):
-  """Runs a complete transcoding test, to and from the binary format."""
-
-  tmpname = test_utils.temporary_filename(suffix=os.path.splitext(filename)[1])
-
-  try:
-    # transcode from test format into the test format -- test array access modes
-    orig_data = load(filename)
-    write(orig_data, tmpname)
-    rewritten_data = load(tmpname)
-
-    assert numpy.array_equal(orig_data, rewritten_data)
-
-    # transcode to test format -- test arrayset access modes
-    trans_file = File(tmpname, 'w')
-    index = [slice(orig_data.shape[k]) for k in range(len(orig_data.shape))]
-    for k in range(orig_data.shape[0]):
-      index[0] = k
-      trans_file.append(orig_data[index]) #slice from first dimension
-    del trans_file
-
-    rewritten_file = File(tmpname, 'r')
-
-    for k in range(orig_data.shape[0]):
-      rewritten_data = rewritten_file.read(k)
-      index[0] = k
-      assert numpy.array_equal(orig_data[index], rewritten_data)
-
-  finally:
-    # And we erase both files after this
-    if os.path.exists(tmpname): os.unlink(tmpname)
-
-def array_readwrite(extension, arr, close=False):
-  """Runs a read/write verify step using the given numpy data"""
-  tmpname = test_utils.temporary_filename(suffix=extension)
-  try:
-    write(arr, tmpname)
-    reloaded = load(tmpname)
-    if close: assert numpy.allclose(arr, reloaded)
-    else: assert numpy.array_equal(arr, reloaded)
-  finally:
-    if os.path.exists(tmpname): os.unlink(tmpname)
-
-def arrayset_readwrite(extension, arrays, close=False):
-  """Runs a read/write verify step using the given numpy data"""
-  tmpname = test_utils.temporary_filename(suffix=extension)
-  try:
-    f = File(tmpname, 'w')
-    for k in arrays:
-      f.append(k)
-    del f
-    f = File(tmpname, 'r')
-    for k, array in enumerate(arrays):
-      reloaded = f.read(k) #read the contents
-      if close:
-        assert numpy.allclose(array, reloaded)
-      else: assert numpy.array_equal(array, reloaded)
-  finally:
-    if os.path.exists(tmpname): os.unlink(tmpname)
-
-def test_hdf5():
-
-  # array writing tests
-  a1 = numpy.random.normal(size=(2,3)).astype('float32')
-  a2 = numpy.random.normal(size=(2,3,4)).astype('float64')
-  a3 = numpy.random.normal(size=(2,3,4,5)).astype('complex128')
-  a4 = (10 * numpy.random.normal(size=(3,3))).astype('uint64')
-
-  array_readwrite('.hdf5', a1) # extensions: .hdf5 or .h5
-  array_readwrite(".h5", a2)
-  array_readwrite('.h5', a3)
-  array_readwrite(".h5", a4)
-  array_readwrite('.h5', a3[:,::2,::2,::2]) #test non-contiguous
-
-  # arrayset writing tests
-  a1 = []
-  a2 = []
-  a3 = []
-  a4 = []
-  for k in range(10):
-    a1.append(numpy.random.normal(size=(2,3)).astype('float32'))
-    a2.append(numpy.random.normal(size=(2,3,4)).astype('float64'))
-    a3.append(numpy.random.normal(size=(2,3,4,5)).astype('complex128'))
-    a4.append((10*numpy.random.normal(size=(3,3))).astype('uint64'))
-
-  arrayset_readwrite('.h5', a1)
-  arrayset_readwrite(".h5", a2)
-  arrayset_readwrite('.h5', a3)
-  arrayset_readwrite(".h5", a4)
-
-  # complete transcoding tests
-  transcode(test_utils.datafile('test1.hdf5', __name__))
-  transcode(test_utils.datafile('matlab_1d.hdf5', __name__))
-  transcode(test_utils.datafile('matlab_2d.hdf5', __name__))
diff --git a/bob/io/base/test_hdf5.py b/bob/io/base/test_hdf5.py
deleted file mode 100644
index a1ed619b3b415e63485300067d669a3c2f05970e..0000000000000000000000000000000000000000
--- a/bob/io/base/test_hdf5.py
+++ /dev/null
@@ -1,546 +0,0 @@
-#!/usr/bin/env python
-# vim: set fileencoding=utf-8 :
-# Andre Anjos <andre.anjos@idiap.ch>
-# Wed Jun 22 17:50:08 2011 +0200
-#
-# Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland
-
-"""Tests for the base HDF5 infrastructure
-"""
-
-import os
-import sys
-import numpy
-import random
-import nose.tools
-
-from . import HDF5File, load, save, peek_all, test_utils
-
-def read_write_check(outfile, dname, data, dtype=None):
-  """Tests scalar input/output on HDF5 files"""
-
-  if dtype is not None: data = [dtype(k) for k in data]
-
-  # First, we test that we can read and write 1 single element
-  outfile.append(dname + '_single', data[0])
-
-  # Set attributes on the dataset and current path (single scalar)
-  outfile.set_attribute(dname + '_single_attr', data[0], dname + '_single')
-  outfile.set_attribute(dname + '_single_attr', data[0])
-
-  # Makes sure we can read the value out
-  assert numpy.array_equal(outfile.lread(dname + '_single', 0), data[0])
-
-  # Makes sure we can read the attributes out
-  assert numpy.array_equal(outfile.get_attribute(dname + '_single_attr', dname + '_single'), data[0])
-  assert numpy.array_equal(outfile.get_attribute(dname + '_single_attr'), data[0])
-
-  # Now we go for the full set
-  outfile.append(dname, data)
-
-  # Also create big attributes to see if that works
-  outfile.set_attribute(dname + '_attr', data, dname + '_single')
-  outfile.set_attribute(dname + '_attr', data)
-
-  # And that we can read it back
-  back = outfile.lread(dname) #we read all at once as it is simpler
-  for i, b in enumerate(back): assert numpy.array_equal(b, data[i])
-
-  # Check the attributes
-  assert numpy.array_equal(outfile.get_attribute(dname + '_attr', dname + '_single'), data)
-  assert numpy.array_equal(outfile.get_attribute(dname + '_attr'), data)
-
-def read_write_array_check(outfile, dtype):
-  N = 10
-  SHAPE = (2, 3, 4, 2) #48 elements in arrays
-  arrays = []
-  for k in range(N):
-    data = [random.uniform(0,N) for z in range(numpy.product(SHAPE))]
-    nparray = numpy.array(data, dtype=dtype).reshape(SHAPE)
-    arrays.append(nparray)
-  read_write_check(outfile, dtype.__name__ + '_array', arrays)
-
-def read_write_subarray_check(outfile, dtype):
-  N = 10
-  SHAPE = (2, 3, 4, 2) #48 elements in arrays
-  arrays = []
-  for k in range(N):
-    data = [random.uniform(0,N) for z in range(numpy.product(SHAPE))]
-    nparray = numpy.array(data, dtype=dtype).reshape(SHAPE)
-    usearray = nparray[:,1,1:2,:]
-    assert not usearray.flags.contiguous
-    arrays.append(usearray)
-  read_write_check(outfile, dtype.__name__ + '_subarray', arrays)
-
-def test_can_create():
-
-  # This test demonstrates how to create HDF5 files from scratch,
-  # starting from blitz::Arrays
-
-  try:
-
-    # We start by creating some arrays to play with. Please note that in
-    # normal cases you are either generating these arrays or reading from
-    # other binary files or datasets.
-    N = 2
-    SHAPE = (3, 2) #6 elements
-    NELEMENT = SHAPE[0] * SHAPE[1]
-    arrays = []
-    for k in range(N):
-      data = [int(random.uniform(0,10)) for z in range(NELEMENT)]
-      arrays.append(numpy.array(data, 'int32').reshape(SHAPE))
-
-    # Now we create a new binary output file in a temporary location and save
-    # the data there.
-    tmpname = test_utils.temporary_filename()
-    outfile = HDF5File(tmpname, 'w')
-    outfile.append('testdata', arrays)
-
-    # Data that is thrown in the file is immediately accessible, so you can
-    # interleave read and write operations without any problems.
-    # There is a single variable in the file, which is a bob arrayset:
-    nose.tools.eq_(outfile.paths(), ['/testdata'])
-
-    # And all the data is *exactly* the same recorded, bit by bit
-    back = outfile.lread('testdata') # this is how to read the whole data back
-    for i, b in enumerate(back):
-      assert numpy.array_equal(b, arrays[i])
-
-    # If you want to immediately close the HDF5 file, just delete the object
-    del outfile
-
-    # You can open the file in read-only mode using the 'r' flag. Writing
-    # operations on this file will fail.
-    readonly = HDF5File(tmpname, 'r')
-
-    # There is a single variable in the file, which is a bob arrayset:
-    nose.tools.eq_(readonly.paths(), ['/testdata'])
-
-    # You can get an overview of what is in the HDF5 dataset using the
-    # describe() method
-    description = readonly.describe('testdata')
-
-    nose.tools.eq_(description[0][0][0], arrays[0].dtype)
-    nose.tools.eq_(description[0][0][1], arrays[0].shape)
-    nose.tools.eq_(description[0][1], N) #number of elements
-    nose.tools.eq_(description[0][2], True) #expandable
-
-    # Test that writing will really fail
-    nose.tools.assert_raises(RuntimeError, readonly.append, "testdata", arrays[0])
-
-
-    # And all the data is *exactly* the same recorded, bit by bit
-    back = readonly.lread('testdata') # how to read the whole data back
-    for i, b in enumerate(back):
-      assert numpy.array_equal(b, arrays[i])
-
-  finally:
-    os.unlink(tmpname)
-
-def test_type_support():
-
-  # This test will go through all supported types for reading/writing data
-  # from to HDF5 files. One single file will hold all data for this test.
-  # This is also supported with HDF5: multiple variables in a single file.
-
-  try:
-
-    N = 100
-
-    tmpname = test_utils.temporary_filename()
-    outfile = HDF5File(tmpname, 'w')
-
-    data = [bool(int(random.uniform(0,2))) for z in range(N)]
-    read_write_check(outfile, 'bool_data', data)
-    data = [int(random.uniform(0,100)) for z in range(N)]
-    read_write_check(outfile, 'int_data', data)
-    read_write_check(outfile, 'int8_data', data, numpy.int8)
-    read_write_check(outfile, 'uint8_data', data, numpy.uint8)
-    read_write_check(outfile, 'int16_data', data, numpy.int16)
-    read_write_check(outfile, 'uint16_data', data, numpy.uint16)
-    read_write_check(outfile, 'int32_data', data, numpy.int32)
-    read_write_check(outfile, 'uint32_data', data, numpy.uint32)
-
-    if sys.version_info[0] < 3:
-      data = [long(random.uniform(0,1000000000)) for z in range(N)]
-    else:
-      data = [int(random.uniform(0,1000000000)) for z in range(N)]
-    read_write_check(outfile, 'long_data', data)
-    read_write_check(outfile, 'int64_data', data, numpy.int64)
-    read_write_check(outfile, 'uint64_data', data, numpy.uint64)
-
-    data = [float(random.uniform(0,1)) for z in range(N)]
-    read_write_check(outfile, 'float_data', data, float)
-    #Note that because of double => float precision issues, the next test will
-    #fail. Python floats are actually double precision.
-    #read_write_check(outfile, 'float32_data', data, numpy.float32)
-    read_write_check(outfile, 'float64_data', data, numpy.float64)
-    #The next construction is not supported by bob
-    #read_write_check(outfile, 'float128_data', data, numpy.float128)
-
-    data = [complex(random.uniform(0,1),random.uniform(-1,0)) for z in range(N)]
-    read_write_check(outfile, 'complex_data', data, complex)
-    #Note that because of double => float precision issues, the next test will
-    #fail. Python floats are actually double precision.
-    #read_write_check(outfile, 'complex64_data', data, numpy.complex64)
-    read_write_check(outfile, 'complex128_data', data, numpy.complex128)
-    #The next construction is not supported by bob
-    #read_write_check(outfile, 'complex256_data', data, numpy.complex256)
-
-    read_write_array_check(outfile, numpy.int8)
-    read_write_array_check(outfile, numpy.int16)
-    read_write_array_check(outfile, numpy.int32)
-    read_write_array_check(outfile, numpy.int64)
-    read_write_array_check(outfile, numpy.uint8)
-    read_write_array_check(outfile, numpy.uint16)
-    read_write_array_check(outfile, numpy.uint32)
-    read_write_array_check(outfile, numpy.uint64)
-    read_write_array_check(outfile, numpy.float32)
-    read_write_array_check(outfile, numpy.float64)
-    #read_write_array_check(outfile, numpy.float128) #no numpy conversion
-    read_write_array_check(outfile, numpy.complex64)
-    read_write_array_check(outfile, numpy.complex128)
-    #read_write_array_check(outfile, numpy.complex256) #no numpy conversion
-
-    read_write_subarray_check(outfile, numpy.int8)
-    read_write_subarray_check(outfile, numpy.int16)
-    read_write_subarray_check(outfile, numpy.int32)
-    read_write_subarray_check(outfile, numpy.int64)
-    read_write_subarray_check(outfile, numpy.uint8)
-    read_write_subarray_check(outfile, numpy.uint16)
-    read_write_subarray_check(outfile, numpy.uint32)
-    read_write_subarray_check(outfile, numpy.uint64)
-    read_write_subarray_check(outfile, numpy.float32)
-    read_write_subarray_check(outfile, numpy.float64)
-    #read_write_subarray_check(outfile, numpy.float128) #no numpy conversion
-    read_write_subarray_check(outfile, numpy.complex64)
-    read_write_subarray_check(outfile, numpy.complex128)
-    #read_write_subarray_check(outfile, numpy.complex256) #no numpy conversion
-
-  finally:
-    os.unlink(tmpname)
-
-def test_dataset_management():
-
-  try:
-
-    # This test examplifies dataset management within HDF5 files and how to
-    # copy, delete and move data around.
-
-    # Let's just create some dummy data to play with
-    N = 100
-
-    tmpname = test_utils.temporary_filename()
-    outfile = HDF5File(tmpname, 'w')
-
-    data = [int(random.uniform(0,N)) for z in range(N)]
-    outfile.append('int_data', data)
-
-    # This is how to rename a dataset.
-    outfile.rename('int_data', 'MyRenamedDataset')
-
-    # You can move the Dataset to any other hierarchy in the HDF5 file. The
-    # directory structure within the file (i.e. the HDF5 groups) will be
-    # created on demand.
-    outfile.rename('MyRenamedDataset', 'NewDirectory1/Dir2/MyDataset')
-
-    # Let's move the MyDataset dataset to another directory
-    outfile.rename('NewDirectory1/Dir2/MyDataset', 'Test2/Bla')
-
-    # So, now the original dataset name does not exist anymore
-    nose.tools.eq_(outfile.paths(), ['/Test2/Bla'])
-
-    # We can also unlink the dataset from the file. Please note this will not
-    # erase the data in the file, just make it inaccessible
-    outfile.unlink('Test2/Bla')
-
-    # Finally, nothing is there anymore
-    nose.tools.eq_(outfile.paths(), [])
-
-  finally:
-    os.unlink(tmpname)
-
-def test_resize_and_preserve():
-
-  # This test checks that non-contiguous C-style array can be saved
-  # into an HDF5 file.
-
-  try:
-    # Let's just create some dummy data to play with
-    SHAPE = (2, 3) #6 elements
-    NELEMENT = SHAPE[0] * SHAPE[1]
-    data = [int(random.uniform(0,10)) for z in range(NELEMENT)]
-    array = numpy.array(data, 'int32').reshape(SHAPE)
-
-    # Try to save a slice
-    tmpname = test_utils.temporary_filename()
-    save(array[:,0], tmpname)
-
-  finally:
-    os.unlink(tmpname)
-
-def test_can_load_hdf5_from_matlab():
-
-  # shows we can load a 2D matlab array and interpret it as a bunch of 1D
-  # arrays, correctly
-
-  t = load(test_utils.datafile('matlab_1d.hdf5', __name__))
-  nose.tools.eq_(t.shape, (512,))
-  nose.tools.eq_(t.dtype, numpy.float64)
-
-  t = load(test_utils.datafile('matlab_2d.hdf5', __name__))
-  nose.tools.eq_(t.shape, (512, 2))
-  nose.tools.eq_(t.dtype, numpy.float64)
-
-  # interestingly enough, if you load those files as arrays, you will read
-  # the whole data at once:
-
-  dtype, shape, stride = peek_all(test_utils.datafile('matlab_1d.hdf5', __name__))
-  nose.tools.eq_(shape, (512,))
-  nose.tools.eq_(dtype, numpy.dtype('float64'))
-
-  dtype, shape, stride = peek_all(test_utils.datafile('matlab_2d.hdf5', __name__))
-  nose.tools.eq_(shape, (512, 2))
-  nose.tools.eq_(dtype, numpy.dtype('float64'))
-
-def test_matlab_import():
-
-  # This test verifies we can import HDF5 datasets generated in Matlab
-  mfile = HDF5File(test_utils.datafile('matlab_1d.hdf5', __name__))
-  nose.tools.eq_(mfile.paths(), ['/array'])
-
-def test_ioload_unlimited():
-
-  # This test verifies that a 3D array whose first dimension is unlimited
-  # and size equal to 1 can be read as a 2D array
-  mfile = load(test_utils.datafile('test7_unlimited.hdf5', __name__))
-  nose.tools.eq_(mfile.ndim, 2)
-
-def test_attribute_version():
-
-  try:
-    tmpname = test_utils.temporary_filename()
-    outfile = HDF5File(tmpname, 'w')
-    outfile.set_attribute('version', 32)
-    nose.tools.eq_(outfile.get_attribute('version'), 32)
-
-  finally:
-    os.unlink(tmpname)
-
-def test_string_support():
-
-  try:
-    tmpname = test_utils.temporary_filename()
-    outfile = HDF5File(tmpname, 'w')
-    attribute = 'this is my long test string with \nNew lines'
-    outfile.set('string', attribute)
-    recovered = outfile.read('string')
-    #nose.tools.eq_(attribute, recovered)
-
-  finally:
-    del outfile
-    os.unlink(tmpname)
-
-def test_string_attribute_support():
-
-  try:
-    tmpname = test_utils.temporary_filename()
-    outfile = HDF5File(tmpname, 'w')
-    attribute = 'this is my long test string with \nNew lines'
-    outfile.set_attribute('string', attribute)
-    recovered = outfile.get_attribute('string')
-    nose.tools.eq_(attribute, recovered)
-
-    data = [1,2,3,4,5]
-    outfile.set('data', data)
-    outfile.set_attribute('string', attribute, 'data')
-    recovered = outfile.get_attribute('string', 'data')
-    nose.tools.eq_(attribute, recovered)
-
-  finally:
-    os.unlink(tmpname)
-
-def test_can_use_set_with_iterables():
-
-  try:
-    tmpname = test_utils.temporary_filename()
-    outfile = HDF5File(tmpname, 'w')
-    data = [1, 34.5, True]
-    outfile.set('data', data)
-    assert numpy.array_equal(data, outfile.read('data'))
-
-  finally:
-    os.unlink(tmpname)
-
-def test_has_attribute():
-
-  try:
-    tmpname = test_utils.temporary_filename()
-    outfile = HDF5File(tmpname, 'w')
-    i = 35
-    f = 3.14
-    outfile.set_attribute('int', i)
-    outfile.set_attribute('float', f)
-    assert outfile.has_attribute('int')
-    nose.tools.eq_(outfile.get_attribute('int'), 35)
-    assert outfile.has_attribute('float')
-    nose.tools.eq_(outfile.get_attribute('float'), 3.14)
-
-  finally:
-    os.unlink(tmpname)
-
-def test_get_attributes():
-
-  try:
-    tmpname = test_utils.temporary_filename()
-    outfile = HDF5File(tmpname, 'w')
-    nothing = outfile.get_attributes()
-    nose.tools.eq_(len(nothing), 0)
-    assert isinstance(nothing, dict)
-    i = 35
-    f = 3.14
-    outfile.set_attribute('int', i)
-    outfile.set_attribute('float', f)
-    d = outfile.get_attributes()
-    nose.tools.eq_(d['int'], i)
-    nose.tools.eq_(d['float'], f)
-
-  finally:
-    os.unlink(tmpname)
-
-def test_set_compression():
-
-  try:
-
-    tmpname = test_utils.temporary_filename()
-    outfile = HDF5File(tmpname, 'w')
-    data = numpy.random.random((50,50))
-    outfile.set('data', data, compression=9)
-    recovered = outfile.read('data')
-    assert numpy.array_equal(data, recovered)
-    del outfile
-
-  finally:
-
-    os.unlink(tmpname)
-
-def test_append_compression():
-
-  try:
-
-    tmpname = test_utils.temporary_filename()
-    outfile = HDF5File(tmpname, 'w')
-    data = numpy.random.random((50,50))
-    for k in range(len(data)): outfile.append('data', data[k], compression=9)
-    recovered = outfile.read('data')
-    assert numpy.array_equal(data, recovered)
-
-  finally:
-
-    os.unlink(tmpname)
-
-
-def test_close():
-  try:
-    tmpname = test_utils.temporary_filename()
-    outfile = HDF5File(tmpname, 'w')
-    outfile.close()
-
-    def test_set():
-      outfile.set("Test", numpy.array([1,2]))
-    nose.tools.assert_raises(RuntimeError, test_set)
-
-    def test_read():
-      test = outfile.read("Test")
-    nose.tools.assert_raises(RuntimeError, test_read)
-
-    def test_filename():
-      fn = outfile.filename
-    nose.tools.assert_raises(RuntimeError, test_filename)
-
-  finally:
-    os.unlink(tmpname)
-
-def test_copy_constructor():
-  try:
-    tmpname = test_utils.temporary_filename()
-    tmpname2 = test_utils.temporary_filename()
-    hdf5 = HDF5File(tmpname, 'w')
-    shallow = HDF5File(hdf5)
-    deep = HDF5File(tmpname2, 'w')
-    hdf5.copy(deep)
-
-    hdf5.create_group("Test")
-    hdf5.cd("Test")
-    hdf5.set("Data", numpy.random.random((10,10)))
-    hdf5.flush()
-
-    assert shallow.has_group("/Test")
-    assert shallow.has_key("/Test/Data")
-    assert hdf5.filename == shallow.filename
-    assert hdf5.keys() == shallow.keys()
-    assert hdf5.cwd == shallow.cwd
-
-    assert not deep.has_group("/Test")
-    assert hdf5.filename != deep.filename
-    assert hdf5.keys() != deep.keys()
-    assert hdf5.cwd != deep.cwd
-    assert str(shallow)
-
-    hdf5.cd("..")
-
-    assert hdf5.sub_groups() == shallow.sub_groups()
-    assert hdf5.sub_groups() != deep.sub_groups()
-
-    assert hdf5.writable
-    assert shallow.writable
-    assert deep.writable
-
-
-    hdf5.close()
-    deep.close()
-
-    def test_filename():
-      fn = shallow.filename
-    nose.tools.assert_raises(RuntimeError, test_filename)
-    def test_repr():
-      fn = str(shallow)
-    nose.tools.assert_raises(RuntimeError, test_repr)
-
-  finally:
-    os.unlink(tmpname)
-    os.unlink(tmpname2)
-
-
-def test_python_interfaces():
-  try:
-    tmpname = test_utils.temporary_filename()
-    with HDF5File(tmpname, 'w') as hdf5:
-      a = numpy.arange(10)
-      b = a * 2
-      hdf5['Data'] = a
-      hdf5.create_group('Group1')
-      hdf5['Group1/Data'] = b
-      assert "/Group1/Data" in hdf5
-      assert [key for key in hdf5] == hdf5.keys()
-      assert numpy.allclose(hdf5['Data'], hdf5.get('Data'))
-      assert all(numpy.allclose(c, d) for c, d in zip(hdf5.values(), (a, b)))
-      for key, value in hdf5.items():
-        assert numpy.allclose(value, hdf5[key])
-
-  finally:
-    os.unlink(tmpname)
-
-def unicode_test():
-  filename = u"Φîłèñäϻæ.hdf5"
-
-  # writing using unicode filename
-  hdf5 = HDF5File(filename, 'w')
-  hdf5.set('Test', range(10))
-  del hdf5
-
-  # writing using unicode filename
-  hdf5 = HDF5File(filename)
-  assert numpy.allclose(hdf5["Test"], range(10))
-  os.remove(filename)
-
diff --git a/bob/io/base/test_io.py b/bob/io/base/test_io.py
deleted file mode 100644
index f9092289667c1e6fd83bac7be9ea383fcedfb580..0000000000000000000000000000000000000000
--- a/bob/io/base/test_io.py
+++ /dev/null
@@ -1,96 +0,0 @@
-import nose
-import numpy as np
-import os
-from . import vstack_features, save, load
-from .test_utils import temporary_filename
-
-
-def test_io_vstack():
-
-  paths = [1, 2, 3, 4, 5]
-
-  def oracle(reader, paths):
-    return np.vstack([reader(p) for p in paths])
-
-  def reader_same_size_C(path):
-    return np.arange(10).reshape(5, 2)
-
-  def reader_different_size_C(path):
-    return np.arange(2 * path).reshape(path, 2)
-
-  def reader_same_size_F(path):
-    return np.asfortranarray(np.arange(10).reshape(5, 2))
-
-  def reader_different_size_F(path):
-    return np.asfortranarray(np.arange(2 * path).reshape(path, 2))
-
-  def reader_same_size_C2(path):
-    return np.arange(30).reshape(5, 2, 3)
-
-  def reader_different_size_C2(path):
-    return np.arange(6 * path).reshape(path, 2, 3)
-
-  def reader_same_size_F2(path):
-    return np.asfortranarray(np.arange(30).reshape(5, 2, 3))
-
-  def reader_different_size_F2(path):
-    return np.asfortranarray(np.arange(6 * path).reshape(path, 2, 3))
-
-  def reader_wrong_size(path):
-    return np.arange(2 * path).reshape(2, path)
-
-  # when same_size is False
-  for reader in [
-    reader_different_size_C,
-    reader_different_size_F,
-    reader_same_size_C,
-    reader_same_size_F,
-    reader_different_size_C2,
-    reader_different_size_F2,
-    reader_same_size_C2,
-    reader_same_size_F2,
-  ]:
-    np.all(vstack_features(reader, paths) == oracle(reader, paths))
-
-  # when same_size is True
-  for reader in [
-    reader_same_size_C,
-    reader_same_size_F,
-    reader_same_size_C2,
-    reader_same_size_F2,
-  ]:
-    np.all(vstack_features(reader, paths, True) == oracle(reader, paths))
-
-  with nose.tools.assert_raises(AssertionError):
-    vstack_features(reader_wrong_size, paths)
-
-  # test actual files
-  paths = [temporary_filename(), temporary_filename(), temporary_filename()]
-  try:
-    # try different readers:
-    for reader in [
-      reader_different_size_C,
-      reader_different_size_F,
-      reader_same_size_C,
-      reader_same_size_F,
-      reader_different_size_C2,
-      reader_different_size_F2,
-      reader_same_size_C2,
-      reader_same_size_F2,
-    ]:
-      # save some data in files
-      for i, path in enumerate(paths):
-        save(reader(i + 1), path)
-      # test when all data is present
-      reference = oracle(load, paths)
-      np.all(vstack_features(load, paths) == reference)
-      os.remove(paths[0])
-      # Check if RuntimeError is raised when one of the files is missing
-      with nose.tools.assert_raises(RuntimeError):
-        vstack_features(load, paths)
-  finally:
-    try:
-      for path in paths:
-        os.remove(path)
-    except Exception:
-      pass
diff --git a/bob/io/base/utils.py b/bob/io/base/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..16ccb62a660808c3b09685de599e2a17afa8152c
--- /dev/null
+++ b/bob/io/base/utils.py
@@ -0,0 +1,126 @@
+import numpy as np
+
+
+def to_matplotlib(img):
+    """Returns a view of the image from Bob format to matplotlib format.
+    This function works with images, batches of images, videos, and higher
+    dimensional arrays that contain images.
+
+    Parameters
+    ----------
+    img : numpy.ndarray
+        A N dimensional array containing an image in Bob format (channels
+        first): For an ND array (N >= 3), the image should have the following
+        format: ``(..., c, h, w)``.
+
+    Returns
+    -------
+    numpy.ndarray
+        A view of the ``img`` compatible with
+        :py:func:`matplotlib.pyplot.imshow`.
+    """
+    if img.ndim < 3:
+        return img
+    return np.moveaxis(img, -3, -1)
+
+
+def to_bob(img):
+    """Returns a view of the image from matplotlib format to Bob format.
+    This function works with images, batches of images, videos, and higher
+    dimensional arrays that contain images.
+
+    Parameters
+    ----------
+    img : numpy.ndarray
+        An image in matplotlib format (channels last): For an ND array (N >= 3),
+        the image should have the following format: ``(..., h, w, c)``.
+
+    Returns
+    -------
+    numpy.ndarray
+        A view of the ``img`` compatible with Bob.
+    """
+    if img.ndim < 3:
+        return img
+    return np.moveaxis(img, -1, -3)
+
+
+def opencvbgr_to_bob(img):
+    """Returns a view of the image from OpenCV BGR format to Bob RGB format.
+    This function works with images, batches of images, videos, and higher
+    dimensional arrays that contain images.
+
+    Parameters
+    ----------
+    img : numpy.ndarray
+        An image loaded by OpenCV. It needs to have at least 3 dimensions.
+
+    Returns
+    -------
+    numpy.ndarray
+        A view of the ``img`` compatible with Bob.
+
+    Raises
+    ------
+    ValueError
+        If the image dimension is less than 3.
+    """
+    if img.ndim < 3:
+        raise ValueError("You need to provide at least a 3 dimensional image")
+    img = img[..., ::-1]
+    return to_bob(img)
+
+
+def bob_to_opencvbgr(img):
+    """Returns a view of the image from Bob format to OpenCV BGR format.
+    This function works with images, batches of images, videos, and higher
+    dimensional arrays that contain images.
+
+    Parameters
+    ----------
+    img : numpy.ndarray
+        An image loaded by Bob. It needs to have at least 3 dimensions.
+
+    Returns
+    -------
+    numpy.ndarray
+        A view of the ``img`` compatible with OpenCV.
+
+    Raises
+    ------
+    ValueError
+        If the image dimension is less than 3.
+    """
+    if img.ndim < 3:
+        raise ValueError("You need to provide at least a 3 dimensional image")
+    img = img[..., ::-1, :, :]
+    return to_matplotlib(img)
+
+
+def imshow(img, cmap=None, **kwargs):
+    """Plots the images that are returned by :py:func:`bob.io.base.load`
+
+    Parameters
+    ----------
+    img : numpy.ndarray
+        A 2 or 3 dimensional array containing an image in
+        bob style: For a 2D array (grayscale image) should be ``(h, w)``;
+        A 3D array (color image) should be in the ``(c, h, w)`` format.
+    cmap : matplotlib.colors.Colormap
+        Colormap, optional, default: ``None``.
+        If ``cmap`` is ``None`` and ``img.ndim`` is 2, defaults to 'gray'.
+        ``cmap`` is ignored when ``img`` has RGB(A) information.
+    **kwargs
+        These are passed directly to :py:func:`matplotlib.pyplot.imshow`
+
+    Returns
+    -------
+    object
+        Returns whatever ``plt.imshow`` returns.
+    """
+    import matplotlib.pyplot as plt
+
+    if cmap is None and img.ndim == 2:
+        cmap = "gray"
+
+    return plt.imshow(to_matplotlib(img), cmap=cmap, **kwargs)
diff --git a/bob/io/base/version.cpp b/bob/io/base/version.cpp
deleted file mode 100644
index 91ccc1d8dea0d399e87458031e0e649314f09378..0000000000000000000000000000000000000000
--- a/bob/io/base/version.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-/**
- * @author Andre Anjos <andre.anjos@idiap.ch>
- * @date Thu  7 Nov 13:50:16 2013
- *
- * @brief Binds configuration information available from bob
- */
-
-#define BOB_IMPORT_VERSION
-#include <bob.blitz/config.h>
-#include <bob.blitz/cleanup.h>
-#include <bob.core/config.h>
-#include <bob.io.base/config.h>
-
-static PyObject* build_version_dictionary() {
-
-  PyObject* retval = PyDict_New();
-  if (!retval) return 0;
-  auto retval_ = make_safe(retval);
-
-  if (!dict_steal(retval, "HDF5", hdf5_version())) return 0;
-  if (!dict_steal(retval, "Boost", boost_version())) return 0;
-  if (!dict_steal(retval, "Compiler", compiler_version())) return 0;
-  if (!dict_steal(retval, "Python", python_version())) return 0;
-  if (!dict_steal(retval, "NumPy", numpy_version())) return 0;
-  if (!dict_steal(retval, "Blitz++", blitz_version())) return 0;
-  if (!dict_steal(retval, "bob.blitz", bob_blitz_version())) return 0;
-  if (!dict_steal(retval, "bob.core", bob_core_version())) return 0;
-
-  return Py_BuildValue("O", retval);
-}
-
-static PyMethodDef module_methods[] = {
-    {0}  /* Sentinel */
-};
-
-PyDoc_STRVAR(module_docstr,
-"Information about software used to compile the C++ Bob API"
-);
-
-#if PY_VERSION_HEX >= 0x03000000
-static PyModuleDef module_definition = {
-  PyModuleDef_HEAD_INIT,
-  BOB_EXT_MODULE_NAME,
-  module_docstr,
-  -1,
-  module_methods,
-  0, 0, 0, 0
-};
-#endif
-
-static PyObject* create_module (void) {
-
-# if PY_VERSION_HEX >= 0x03000000
-  PyObject* m = PyModule_Create(&module_definition);
-  auto m_ = make_xsafe(m);
-  const char* ret = "O";
-# else
-  PyObject* m = Py_InitModule3(BOB_EXT_MODULE_NAME, module_methods, module_docstr);
-  const char* ret = "N";
-# endif
-  if (!m) return 0;
-
-  /* register version numbers and constants */
-  if (PyModule_AddIntConstant(m, "api", BOB_IO_BASE_API_VERSION) < 0)
-    return 0;
-  if (PyModule_AddStringConstant(m, "module", BOB_EXT_MODULE_VERSION) < 0)
-    return 0;
-  if (PyModule_AddObject(m, "externals", build_version_dictionary()) < 0) return 0;
-
-  // call bob_io_base_version once to avoid compiler warning
-  auto _ = make_safe(bob_io_base_version());
-
-  return Py_BuildValue(ret, m);
-}
-
-PyMODINIT_FUNC BOB_EXT_ENTRY_NAME (void) {
-# if PY_VERSION_HEX >= 0x03000000
-  return
-# endif
-    create_module();
-}
diff --git a/conda/meta.yaml b/conda/meta.yaml
index 815ac14fb9d24d6cebda0f711c75f8954a06cf80..debadfadd6c2ca6b7bb206de1a8cc77943155c06 100644
--- a/conda/meta.yaml
+++ b/conda/meta.yaml
@@ -17,27 +17,16 @@ build:
     - "{{ PYTHON }} -m pip install . -vv"
 
 requirements:
-  build:
-    - {{ compiler('c') }}
-    - {{ compiler('cxx') }}
-    - pkg-config {{ pkg_config }}
-    - cmake {{ cmake }}
-    - make {{ make }}
   host:
     - python {{ python }}
     - setuptools {{ setuptools }}
     - pip {{ pip }}
     - bob.extension
-    - bob.blitz
-    - bob.core
-    - libblitz {{ libblitz }}
-    - hdf5 {{ hdf5 }}
-    - boost {{ boost }}
+    - h5py {{ h5py }}
     - numpy {{ numpy }}
   run:
     - python
     - setuptools
-    - boost
     - {{ pin_compatible('numpy') }}
 
 test:
diff --git a/doc/c_cpp_api.rst b/doc/c_cpp_api.rst
deleted file mode 100644
index 95ea2401f514b1140766803b8aba5c5ffffdef87..0000000000000000000000000000000000000000
--- a/doc/c_cpp_api.rst
+++ /dev/null
@@ -1,168 +0,0 @@
-.. vim: set fileencoding=utf-8 :
-.. Andre Anjos <andre.dos.anjos@gmail.com>
-.. Tue 15 Oct 14:59:05 2013
-
-=========
- C++ API
-=========
-
-The C++ API of ``bob.io.base`` allows users to leverage from automatic converters
-for classes in :py:class:`bob.io.base`.  To use the C API, clients should first,
-include the header file ``<bob.io.base/api.h>`` on their compilation units and
-then, make sure to call once ``import_bob_io_base()`` at their module
-instantiation, as explained at the `Python manual
-<http://docs.python.org/2/extending/extending.html#using-capsules>`_.
-
-Here is a dummy C example showing how to include the header and where to call
-the import function:
-
-.. code-block:: c++
-
-   #include <bob.io.base/api.h>
-
-   PyMODINIT_FUNC initclient(void) {
-
-     PyObject* m Py_InitModule("client", ClientMethods);
-
-     if (!m) return;
-
-     /* imports dependencies */
-     if (import_bob_blitz() < 0) {
-       PyErr_Print();
-       PyErr_SetString(PyExc_ImportError, "cannot import extension");
-       return 0;
-     }
-
-     if (import_bob_io_base() < 0) {
-       PyErr_Print();
-       PyErr_SetString(PyExc_ImportError, "cannot import extension");
-       return 0;
-     }
-
-   }
-
-
-Generic Functions
------------------
-
-.. cpp:function:: int PyBobIo_AsTypenum(bob::core::array::ElementType et)
-
-   Converts the input Bob element type into a ``NPY_<TYPE>`` enumeration value.
-   Returns ``NPY_NOTYPE`` in case of problems, and sets a
-   :py:exc:`RuntimeError`.
-
-.. cpp:function:: PyObject* PyBobIo_TypeInfoAsTuple (const bob::core::array::typeinfo& ti)
-
-   Converts the ``bob::core::array::typeinfo&`` object into a **new reference**
-   to a :py:class:`tuple` with 3 elements:
-
-     [0]
-         The data type as a :py:class:`numpy.dtype` object
-
-     [1]
-         The shape of the object, as a tuple of integers
-
-     [2]
-         The strides of the object, as a tuple of integers
-
-   Returns ``0`` in case of failure, or a **new reference** to the tuple
-   described above in case of success.
-
-
-.. cpp:function:: int PyBobIo_FilenameConverter (PyObject* o, const char** b)
-
-   This function is meant to be used with :c:func:`PyArg_ParseTupleAndKeywords`
-   family of functions in the Python C-API. It converts an arbitrary input
-   object into a ``const char*`` If the input object is of type
-   ``PyUnicodeObject`` (which is the default in Python3.x) the unicode code is
-   properly decoded using :c:func:`PyUnicode_AsEncodedString` with ``encoding``
-   set to ``Py_FileSystemDefaultEncoding`` and ``errors`` set to ``"strict"``.
-
-   Objects which are not ``PyUnicodeObject`` are first coerced into a
-   bytes/string before converting to the ``const char*`` object using
-   :c:func:`PyObject_Bytes` (on Python3.x) and :c:func:`PyObject_Str`
-   (on Python 2.x).
-
-   Returns 0 if an error is detected, 1 on success.
-
-   .. note::
-      Since version 2.2, this function converts into ``const char*`` directly.
-      Before version 2.2, it was returning either ``PyBytesObject`` (Python 3)
-      or ``PyStringObject`` (Python 2).
-
-
-Bob File Support
-----------------
-
-.. cpp:type:: PyBobIoFileObject
-
-   The pythonic object representation for a ``bob::io::base::File`` object.
-
-   .. code-block:: cpp
-
-      typedef struct {
-        PyObject_HEAD
-        boost::shared_ptr<bob::io::base::File> f;
-      } PyBobIoFileObject;
-
-   .. cpp:member:: boost::shared_ptr<bob::io::base::File> f
-
-      A pointer to a file being read or written.
-
-.. cpp:type:: PyBobIoFileIteratorObject
-
-   The pythonic object representation for an iterator over a
-   ``bob::io::base::File`` object.
-
-   .. code-block:: cpp
-
-      typedef struct {
-        PyObject_HEAD
-        PyBobIoFileObject* pyfile;
-        Py_ssize_t curpos;
-      } PyBobIoFileIteratorObject;
-
-   .. cpp:member:: PyBobIoFileObject* pyfile
-
-      A pointer to the pythonic representation of a file.
-
-   .. cpp:member:: Py_ssize_t curpos
-
-      The current position at the file being pointed to.
-
-
-Bob HDF5 Support
-----------------
-
-.. cpp:type:: PyBobIoHDF5FileObject
-
-   The pythonic object representation for a ``bob::io::base::HDF5File`` object.
-
-   .. code-block:: cpp
-
-      typedef struct {
-        PyObject_HEAD
-        boost::shared_ptr<bob::io::base::HDF5File> f;
-      } PyBobIoHDF5FileObject;
-
-   .. cpp:member:: boost::shared_ptr<bob::io::base::HDF5File> f
-
-      A pointer to a Bob object being used to read/write data into an HDF5
-      file.
-
-
-.. cpp:function:: int PyBobIoHDF5File_Check(PyObject* o)
-
-   Checks if the input object ``o`` is a ``PyBobIoHDF5FileObject``. Returns
-   ``1`` if it is, and ``0`` otherwise.
-
-
-.. cpp:function:: int PyBobIoHDF5File_Converter(PyObject* o, PyBobIoHDF5FileObject** a)
-
-   This function is meant to be used with :c:func:`PyArg_ParseTupleAndKeywords`
-   family of functions in the Python C-API. It checks the input object to be of
-   type ``PyBobIoHDF5FileObject`` and sets a **new reference** to it (in
-   ``*a``) if it is the case. Returns ``0`` in case of failure, ``1`` in case
-   of success.
-
-.. include:: links.rst
diff --git a/doc/extra-intersphinx.txt b/doc/extra-intersphinx.txt
index 4a36b0b7319763e14836e18b5c569771a8498678..9c61c73639974afe3eafae36df0f4c8f36a72206 100644
--- a/doc/extra-intersphinx.txt
+++ b/doc/extra-intersphinx.txt
@@ -1,2 +1 @@
-scipy
-bob.io.image
+scipy
\ No newline at end of file
diff --git a/doc/guide.rst b/doc/guide.rst
deleted file mode 100644
index 0c20a86418a07a15a83a09467ae05ded6ba94987..0000000000000000000000000000000000000000
--- a/doc/guide.rst
+++ /dev/null
@@ -1,382 +0,0 @@
-.. vim: set fileencoding=utf-8 :
-.. Andre Anjos <andre.dos.anjos@gmail.com>
-.. Fri 16 May 11:48:13 2014 CEST
-
-============
- User Guide
-============
-
-This section gives an overview of the operations for storing and retrieving the
-basic data structures in |project|, such as `NumPy`_ arrays. |project| uses
-`HDF5`_  format for storing binary coded data. Using the |project| support for
-`HDF5`_, it is very simple to import and export data.
-
-`HDF5`_  uses a neat descriptive language for representing the data in the HDF5
-files, called Data Description Language (`DDL`_).
-
-To perform the functionalities given in this section, you should have `NumPy`_
-and |project| loaded into the `Python`_ environment.
-
-.. testsetup:: *
-
-   import numpy
-   import bob.io.base
-   import tempfile
-   import os
-
-   current_directory = os.path.realpath(os.curdir)
-   temp_dir = tempfile.mkdtemp(prefix='bob_doctest_')
-   os.chdir(temp_dir)
-
-HDF5 standard utilities
------------------------
-
-Before explaining the basics of reading and writing to `HDF5`_ files, it is
-important to list some `HDF5`_ standard utilities for checking the content of
-an `HDF5`_ file. These are supplied by the `HDF5`_ project.
-
-``h5dump``
-  Dumps the content of the file using the DDL.
-
-``h5ls``
-  Lists the content of the file using DDL, but does not show the data.
-
-``h5diff``
-  Finds the differences between HDF5 files.
-
-I/O operations using the class `bob.io.base.HDF5File`
-------------------------------------------------------
-
-Writing operations
-~~~~~~~~~~~~~~~~~~
-
-Let's take a look at how to write simple scalar data such as integers or
-floats.
-
-.. doctest::
-
-   >>> an_integer = 5
-   >>> a_float = 3.1416
-   >>> f = bob.io.base.HDF5File('testfile1.hdf5', 'w')
-   >>> f.set('my_integer', an_integer)
-   >>> f.set('my_float', a_float)
-   >>> del f
-
-If after this you use the **h5dump** utility on the file ``testfile1.hdf5``,
-you will verify that the file now contains:
-
-.. code-block:: none
-
-  HDF5 "testfile1.hdf5" {
-  GROUP "/" {
-    DATASET "my_float" {
-       DATATYPE  H5T_IEEE_F64LE
-       DATASPACE  SIMPLE { ( 1 ) / ( 1 ) }
-       DATA {
-       (0): 3.1416
-       }
-    }
-    DATASET "my_integer" {
-       DATATYPE  H5T_STD_I32LE
-       DATASPACE  SIMPLE { ( 1 ) / ( 1 ) }
-       DATA {
-       (0): 5
-       }
-    }
-  }
-  }
-
-.. note::
-
-   In |project|, when you open a HDF5 file, you can choose one of the following
-   options:
-
-   **'r'** Open the file in reading mode; writing operations will fail (this is the default).
-
-   **'a'** Open the file in reading and writing mode with appending.
-
-   **'w'** Open the file in reading and writing mode, but truncate it.
-
-   **'x'** Read/write/append with exclusive access.
-
-The dump shows that there are two datasets inside a group named ``/`` in the
-file.  HDF5 groups are like file system directories. They create namespaces for
-the data. In the root group (or directory), you will find the two variables,
-named as you set them to be.  The variable names are the complete path to the
-location where they live. You could write a new variable in the same file but
-in a different directory like this:
-
-.. doctest::
-
-  >>> f = bob.io.base.HDF5File('testfile1.hdf5', 'a')
-  >>> f.create_group('/test')
-  >>> f.set('/test/my_float', numpy.float32(6.28))
-  >>> del f
-
-Line 1 opens the file for reading and writing, but without truncating it. This
-will allow you to access the file contents. Next, the directory ``/test`` is
-created and a new variable is written inside the subdirectory. As you can
-verify, **for simple scalars**, you can also force the storage type. Where
-normally one would have a 64-bit real value, you can impose that this variable
-is saved as a 32-bit real value. You can verify the dump correctness with
-``h5dump``:
-
-.. code-block:: none
-
-  GROUP "/" {
-  ...
-   GROUP "test" {
-      DATASET "my_float" {
-         DATATYPE  H5T_IEEE_F32LE
-         DATASPACE  SIMPLE { ( 1 ) / ( 1 ) }
-         DATA {
-         (0): 6.28
-         }
-      }
-   }
-  }
-
-Notice the subdirectory ``test`` has been created and inside it a floating
-point number has been stored. Such a float point number has a 32-bit precision
-as it was defined.
-
-.. note::
-
-  If you need to place lots of variables in a subfolder, it may be better to
-  setup the prefix folder before starting the writing operations on the
-  :py:class:`bob.io.base.HDF5File` object. You can do this using the method
-  :py:meth:`bob.io.base.HDF5File.cd`.  Look up its help for more information and usage
-  instructions.
-
-Writing arrays is a little simpler as the :py:class:`numpy.ndarray` objects
-encode all the type information we need to write and read them correctly. Here
-is an example:
-
-.. doctest::
-
-  >>> A = numpy.array(range(4), 'int8').reshape(2,2)
-  >>> f = bob.io.base.HDF5File('testfile1.hdf5', 'a')
-  >>> f.set('my_array', A)
-  >>> f.close()
-
-The result of running ``h5dump`` on the file ``testfile1.hdf5`` should be:
-
-.. code-block:: none
-
-  ...
-   DATASET "my_array" {
-      DATATYPE  H5T_STD_I8LE
-      DATASPACE  SIMPLE { ( 2, 2 ) / ( 2, 2 ) }
-      DATA {
-      (0,0): 0, 1,
-      (1,0): 2, 3
-      }
-   }
-  ...
-
-You don't need to limit yourself to single variables, you can also save lists
-of scalars and arrays using the function :py:meth:`bob.io.base.HDF5File.append`
-instead of :py:meth:`bob.io.base.HDF5File.set`.
-
-Reading operations
-~~~~~~~~~~~~~~~~~~
-
-Reading data from a file that you just wrote to is just as easy. For this task
-you should use :py:meth:`bob.io.base.HDF5File.read`. The read method will read
-all the contents of the variable pointed to by the given path. This is the
-normal way to read a variable you have written with
-:py:meth:`bob.io.base.HDF5File.set`. If you decided to create a list of scalar
-or arrays, the way to read that up would be using
-:py:meth:`bob.io.base.HDF5File.lread` instead. Here is an example:
-
-.. doctest::
-
-  >>> f = bob.io.base.HDF5File('testfile1.hdf5') #read only
-  >>> f.read('my_integer') #reads integer
-  5
-  >>> print(f.read('my_array')) # reads the array
-  [[0 1]
-   [2 3]]
-  >>> del f
-
-Now let's look at an example where we have used
-:py:meth:`bob.io.base.HDF5File.append` instead of
-:py:meth:`bob.io.base.HDF5File.set` to write data to a file. That is normally
-the case when you write lists of variables to a dataset.
-
-.. doctest::
-
-  >>> f = bob.io.base.HDF5File('testfile2.hdf5', 'w')
-  >>> f.append('arrayset', numpy.array(range(10), 'float64'))
-  >>> f.append('arrayset', 2*numpy.array(range(10), 'float64'))
-  >>> f.append('arrayset', 3*numpy.array(range(10), 'float64'))
-  >>> numpy.allclose((f.lread('arrayset', 0)),[ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9.])
-  True
-  >>> numpy.allclose( (f.lread('arrayset', 2)), [  0.,   3.,   6.,   9.,  12.,  15.,  18.,  21.,  24.,  27.])
-  True
-  >>> del f
-
-This is what the ``h5dump`` of the file would look like:
-
-.. code-block:: none
-
-  HDF5 "testfile4.hdf5" {
-  GROUP "/" {
-     DATASET "arrayset" {
-        DATATYPE  H5T_IEEE_F64LE
-        DATASPACE  SIMPLE { ( 3, 10 ) / ( H5S_UNLIMITED, 10 ) }
-        DATA {
-        (0,0): 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
-        (1,0): 0, 2, 4, 6, 8, 10, 12, 14, 16, 18,
-        (2,0): 0, 3, 6, 9, 12, 15, 18, 21, 24, 27
-        }
-     }
-  }
-  }
-
-Notice that the expansion limits for the first dimension have been correctly
-set by |project| so you can insert an *unlimited* number of 1D float vectors.
-Of course, you can also read the whole contents of the arrayset in a single
-shot:
-
-.. doctest::
-
-  >>> f = bob.io.base.HDF5File('testfile2.hdf5')
-  >>> numpy.allclose((f.read('arrayset')),[[  0.,   1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.],[  0.,   2.,   4.,   6.,   8.,  10.,  12.,  14.,  16.,  18.],[  0.,   3.,   6.,   9.,  12.,  15.,  18.,  21.,  24.,  27.]])
-  True
-
-As you can see, the only difference between
-:py:meth:`bob.io.base.HDF5File.read` and
-:py:meth:`bob.io.base.HDF5File.lread` is on how |project| considers the
-available data (as a single array with N dimensions or as a set of arrays with
-N-1 dimensions). In the first example, you would have also been able to read
-the variable `my_array` as an arrayset using
-:py:meth:`bob.io.base.HDF5File.lread` instead of
-:py:meth:`bob.io.base.HDF5File.read`. In this case, each position readout
-would return a 1D uint8 array instead of a 2D array.
-
-
-Pythonic operations on HDF5 files
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-You can use some Pythonic opertations on :py:class:`bob.io.base.HDF5File`:
-
-* Use the ``with`` statement to open (and automatically close) HDF5 files.
-* iterate over :py:class:`bob.io.base.HDF5File` objects to get an
-  iterable of keys instead of calling :py:meth:`bob.io.base.HDF5File.keys`.
-* use the ``in`` keyword instead of calling
-  :py:meth:`bob.io.base.HDF5File.has_key`.
-* use Python's dictionary syntax instead of :py:meth:`bob.io.base.HDF5File.set`
-  and :py:meth:`bob.io.base.HDF5File.get`.
-
-For example:
-
-
-.. doctest::
-
-  >>> f = bob.io.base.HDF5File('testfile3.hdf5', 'w')
-  >>> array = numpy.arange(5)
-  >>> f['my_array'] = array # f.set('my_array', array)
-  >>> f['my_array'] # f.get('my_array')
-  array([0, 1, 2, 3, 4])
-  >>> 'my_array' in f # f.has_key('my_array')
-  True
-  >>> [key for key in f] # f.keys()
-  ['/my_array']
-  >>> f.create_group('group1')
-  >>> f.cd('group1')
-  >>> f['my_array_in_group'] = array
-  >>> f.cd('/')
-  >>> # keys(), values(), and items() just like a dictionary
-  >>> [key for key in f.keys()]
-  ['/my_array', '/group1/my_array_in_group']
-  >>> [value for value in f.values()]
-  [array([0, 1, 2, 3, 4]), array([0, 1, 2, 3, 4])]
-  >>> [(key, value) for key, value in f.items()]
-  [('/my_array', array([0, 1, 2, 3, 4])), ('/group1/my_array_in_group', array([0, 1, 2, 3, 4]))]
-  >>> f.close()
-  >>> # using a with statement to open and close files
-  >>> with bob.io.base.HDF5File('testfile3.hdf5', 'a') as f:
-  ...   f['second_array'] = array
-  >>> f = bob.io.base.HDF5File('testfile3.hdf5', 'r')
-  >>> 'second_array' in f
-  True
-
-Array interfaces
-----------------
-
-What we have shown so far is the generic API to read and write data using HDF5.
-You will use it when you want to import or export data from |project| into
-other software frameworks, debug your data or just implement your own classes
-that can serialize and de-serialize from HDF5 file containers. In |project|,
-most of the time you will be working with :py:class:`numpy.ndarray`\s. In
-special situations though, you may be asked to handle
-:py:class:`bob.io.base.File`\s. :py:class:`bob.io.base.File` objects create a
-transparent connection between C++ (`Blitz++`_) / Python (`NumPy`_) arrays and
-file access.  You specify the filename from which you want to input data and
-the :py:class:`bob.io.base.File` object decides what is the best codec to be
-used (from the extension) and how to read the data back into your array.
-
-To create an :py:class:`bob.io.base.File` from a file path, just do the
-following:
-
-.. doctest::
-
-  >>> a = bob.io.base.File('testfile2.hdf5', 'r')
-  >>> a.filename
-  'testfile2.hdf5'
-
-:py:class:`bob.io.base.File`\s simulate containers for
-:py:class:`numpy.ndarray`\s, transparently accessing the file data when
-requested. Note, however, that when you instantiate an
-:py:class:`bob.io.base.File` it does **not** load the file contents into
-memory. It waits until you emit another explicit instruction to do so. We do
-this with the :py:meth:`bob.io.base.File.read` method:
-
-.. doctest::
-
-  >>> array = a.read()
-  >>> numpy.allclose(array, [[  0.,   1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.],[  0.,   2.,   4.,   6.,   8.,  10.,  12.,  14.,  16.,  18.],[  0.,   3.,   6.,   9.,  12.,  15.,  18.,  21.,  24.,  27.]])
-  True
-
-Every time you say :py:meth:`bob.io.base.File.read`, the file contents will be
-read from the file and into a new array.
-
-Saving arrays to the :py:class:`bob.io.base.File` is as easy, just call the
-:py:meth:`bob.io.base.File.write` method:
-
-.. doctest::
-
-  >>> f = bob.io.base.File('copy1.hdf5', 'w')
-  >>> f.write(array)
-
-Numpy ndarray shortcuts
------------------------
-
-To just load an :py:class:`numpy.ndarray` in memory, you can use a short cut
-that lives at :py:func:`bob.io.base.load`. With it, you don't have to go
-through the :py:class:`bob.io.base.File` container:
-
-.. doctest::
-
-  >>> t = bob.io.base.load('testfile2.hdf5')
-  >>> numpy.allclose(t, [[  0.,   1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.], [  0.,   2.,   4.,   6.,   8.,  10.,  12.,  14.,  16.,  18.],[  0.,   3.,   6.,   9.,  12.,  15.,  18.,  21.,  24.,  27.]])
-  True
-
-You can also directly save :py:class:`numpy.ndarray`\s without going through
-the :py:class:`bob.io.base.File` container:
-
-.. doctest::
-
-  >>> bob.io.base.save(t, 'copy2.hdf5')
-
-.. note::
-
-  Under the hood, we still use the :py:class:`bob.io.base.File` API to execute
-  the read and write operations. Have a look at the manual section for
-  :py:mod:`bob.io.base` for more details and other shortcuts available.
-
-
-.. Place here your external references
-.. include:: links.rst
-.. _ddl: http://www.hdfgroup.org/HDF5/doc/ddl.html
diff --git a/doc/index.rst b/doc/index.rst
index c24f65185d8b46f4ae7b482ff5ba5ee694b11490..74ade76611a9b7954f0f7e8fdfd6a44817f9f477 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -13,12 +13,10 @@ Below is the old documentation.
 
 This module contains a basic interface to read and write files of various
 types.  It provides generic functions :py:func:`bob.io.base.save` and
-:py:func:`bob.io.base.load` to write and read various types of data.  In this
-interface, data is mainly written using the :py:class:`bob.io.base.HDF5File`
-interface.  To enable further types of IO, please import one of the following
+:py:func:`bob.io.base.load` to write and read various types of data. 
+To enable further types of IO, please import one of the following
 packages (the list might not be exhaustive):
 
-* :ref:`bob.io.image` to load and save images of various kinds
 
 
 Documentation
@@ -27,9 +25,7 @@ Documentation
 .. toctree::
    :maxdepth: 2
 
-   guide
-   py_api
-   c_cpp_api
+   py_api   
 
 TODO
 ----
diff --git a/doc/nitpick-exceptions.txt b/doc/nitpick-exceptions.txt
index 97040cc3e01e18ad17e72a44d841e4a36b663f7e..f61551fb3429356607e4f0c7f299aa2537fcc3e1 100644
--- a/doc/nitpick-exceptions.txt
+++ b/doc/nitpick-exceptions.txt
@@ -1,37 +1,6 @@
-# these are actually c types
-cpp:type PyObject
-cpp:type Py_ssize_t
-cpp:typeOrConcept PyObject
-cpp:typeOrConcept Py_ssize_t
-
-# no reference exists for these
-cpp:type bob
-cpp:type bob::core
-cpp:type bob::core::array
-cpp:type bob::core::array::typeinfo
-cpp:type bob::core::array::ElementType
-cpp:type boost
-cpp:type boost::shared_ptr
-cpp:type bob::io
-cpp:type bob::io::base
-cpp:type bob::io::base::File
-cpp:type bob::io::base::HDF5File
-cpp:typeOrConcept bob
-cpp:typeOrConcept bob::core
-cpp:typeOrConcept bob::core::array
-cpp:typeOrConcept bob::core::array::typeinfo
-cpp:typeOrConcept bob::core::array::ElementType
-cpp:typeOrConcept boost
-cpp:typeOrConcept boost::shared_ptr
-cpp:typeOrConcept bob::io
-cpp:typeOrConcept bob::io::base
-cpp:typeOrConcept bob::io::base::File
-cpp:typeOrConcept bob::io::base::HDF5File
-
 # exceptions are not found in python 2.7
 py:exc RuntimeError
 py:class tuple
-c:func PyUnicode_FSConverter
 
 # these don't exists on numpy's manual
 py:class numpy.uint8
diff --git a/doc/py_api.rst b/doc/py_api.rst
index 512c928a6cc045817a8fb067bdeac926530cc066..bec56c499f404a46c25d909bdad0e191c5d57959 100644
--- a/doc/py_api.rst
+++ b/doc/py_api.rst
@@ -8,46 +8,14 @@
 
 This section includes information for using the pure Python API of ``bob.io.base``.
 
-
-Classes
--------
-
-.. autosummary::
-   bob.io.base.File
-   bob.io.base.HDF5File
-
 Functions
 ---------
 
 .. autosummary::
    bob.io.base.load
-   bob.io.base.merge
    bob.io.base.save
-   bob.io.base.append
-   bob.io.base.peek
-   bob.io.base.peek_all
    bob.io.base.create_directories_safe
    bob.io.base.vstack_features
 
-   bob.io.base.extensions
-   bob.io.base.get_config
-
-Test Utilities
---------------
-
-These functions might be useful when you are writing your nose tests.
-Please note that this is not part of the default ``bob.io.base`` API, so in order to use it, you have to ``import bob.io.base.test_utils`` separately.
-
-.. autosummary::
-   bob.io.base.test_utils.datafile
-   bob.io.base.test_utils.temporary_filename
-   bob.io.base.test_utils.extension_available
-
-
-Details
--------
 
-.. automodule:: bob.io.base
-   :inherited-members:
 
-.. automodule:: bob.io.base.test_utils
diff --git a/requirements.txt b/requirements.txt
index f2e31dbe624eabd83f221582a1e9862ccf937535..8fd79bb91084c43678b904bdba2638a0a481bcda 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,3 +1 @@
 bob.extension
-bob.blitz
-bob.core > 2.1.3
diff --git a/setup.py b/setup.py
index 76389924fd4a5b8b7ee470e0b787c90cb6ea5d66..99c943d9a5f182e1ec0025264f3fb9ceb9fa9444 100644
--- a/setup.py
+++ b/setup.py
@@ -2,217 +2,44 @@
 # vim: set fileencoding=utf-8 :
 # Andre Anjos <andre.anjos@idiap.ch>
 # Mon 16 Apr 08:18:08 2012 CEST
+#
+from setuptools import setup, dist
 
-bob_packages = ['bob.core']
+dist.Distribution(dict(setup_requires=["bob.extension"]))
 
-from setuptools import setup, find_packages, dist
-dist.Distribution(dict(setup_requires=['bob.extension', 'bob.blitz'] + bob_packages))
-from bob.extension.utils import egrep, find_header, find_library
-from bob.extension import pkgconfig
-from bob.blitz.extension import Extension, Library, build_ext
-
-from bob.extension.utils import load_requirements
-build_requires = load_requirements()
-
-# Define package version
-version = open("version.txt").read().rstrip()
-
-packages = ['boost']
-boost_modules = ['system', 'filesystem']
-
-def libhdf5_version(header):
-
-  vv = egrep(header, r"#\s*define\s+H5_VERSION\s+\"([\d\.]+)\"")
-  if not len(vv): return None
-  return vv[0].group(1)
-
-class hdf5:
-
-  def __init__ (self):
-    """
-    Searches for libhdf5 in stock locations. Allows user to override.
-
-    If the user sets the environment variable BOB_PREFIX_PATH, that prefixes
-    the standard path locations.
-
-    """
-    import os
-
-    self.name = 'hdf5'
-
-    # try to locate pkg-config on our own first
-    try:
-
-      header = 'hdf5.h'
-
-      candidates = find_header(header)
-
-      if not candidates:
-        raise RuntimeError("could not find %s's `%s' - have you installed %s on this machine?" % (self.name, header, self.name))
-
-      self.include_directories = [os.path.dirname(candidates[0])]
-      directory = os.path.dirname(candidates[0])
-      version_header = os.path.join(directory, 'H5pubconf.h')
-      self.version = libhdf5_version(version_header)
-
-      # normalize
-      self.include_directories = [os.path.normpath(i) for i in self.include_directories]
-
-      # find library
-      prefix = os.path.dirname(os.path.dirname(self.include_directories[0]))
-      module = 'hdf5'
-      candidates = find_library(module, version=self.version, prefixes=[prefix], only_static=False)
-
-      if not candidates:
-        raise RuntimeError("cannot find required %s binary module `%s' - make sure libhdf5 is installed on `%s'" % (self.name, module, prefix))
-
-      # libraries
-      self.libraries = []
-      name, ext = os.path.splitext(os.path.basename(candidates[0]))
-      if ext in ['.so', '.a', '.dylib', '.dll']:
-        self.libraries.append(name[3:]) #strip 'lib' from the name
-      else: #link against the whole thing
-        self.libraries.append(':' + os.path.basename(candidates[0]))
-
-      # library path
-      self.library_directories = [os.path.dirname(candidates[0])]
-
-    except RuntimeError:
-      # now, we try to use pkg-config, which seems to be only available on Debian
-      pkg = pkgconfig('hdf5')
-      self.include_directories = pkg.include_directories()
-      version_header = os.path.join(self.include_directories[0], 'H5pubconf.h')
-      self.version = libhdf5_version(version_header)
-      self.libraries = pkg.libraries()
-      self.library_directories = pkg.library_directories()
-
-
-  def macros(self):
-    return [
-        ('HAVE_%s' % self.name.upper(), '1'),
-        # see https://portal.hdfgroup.org/display/HDF5/Migrating+from+HDF5+1.10+to+HDF5+1.12
-        ('H5_USE_110_API', '1'),
-      ]
-
-
-hdf5_pkg = hdf5()
-
-system_include_dirs = hdf5_pkg.include_directories
-
-library_dirs = hdf5_pkg.library_directories
-
-libraries = hdf5_pkg.libraries
-
-define_macros = hdf5_pkg.macros()
+from bob.extension.utils import load_requirements, find_packages
 
+install_requires = load_requirements()
 
+# The only thing we do in this file is to call the setup() function with all
+# parameters that define our package.
 setup(
-
-    name='bob.io.base',
-    version=version,
-    description='Basic IO for Bob',
-    url='http://gitlab.idiap.ch/bob/bob.io.base',
-    license='BSD',
-    author='Andre Anjos',
-    author_email='andre.anjos@idiap.ch',
-
-    long_description=open('README.rst').read(),
-
+    # This is the basic information about your project. Modify all this
+    # information before releasing code publicly.
+    name="bob.io.base",
+    version=open("version.txt").read().rstrip(),
+    description="Basic IO for Bob",
+    url="http://gitlab.idiap.ch/bob/bob.io.base",
+    license="BSD",
+    author="Andre Anjos",
+    author_email="andre.anjos@idiap.ch",
+    long_description=open("README.rst").read(),
     packages=find_packages(),
     include_package_data=True,
     zip_safe=False,
-
-    setup_requires = build_requires,
-    install_requires = build_requires,
-
-
-
-    ext_modules = [
-      Extension("bob.io.base.version",
-        [
-          "bob/io/base/version.cpp",
-        ],
-        define_macros = define_macros,
-        system_include_dirs = system_include_dirs,
-        version = version,
-        bob_packages = bob_packages,
-        packages = packages,
-        boost_modules = boost_modules,
-      ),
-
-      Library("bob.io.base.bob_io_base",
-        [
-          "bob/io/base/cpp/CodecRegistry.cpp",
-          "bob/io/base/cpp/File.cpp",
-          "bob/io/base/cpp/HDF5ArrayFile.cpp",
-          "bob/io/base/cpp/HDF5Attribute.cpp",
-          "bob/io/base/cpp/HDF5Dataset.cpp",
-          "bob/io/base/cpp/HDF5File.cpp",
-          "bob/io/base/cpp/HDF5Group.cpp",
-          "bob/io/base/cpp/HDF5Types.cpp",
-          "bob/io/base/cpp/HDF5Utils.cpp",
-          "bob/io/base/cpp/reorder.cpp",
-          "bob/io/base/cpp/utils.cpp",
-          "bob/io/base/cpp/array.cpp",
-          "bob/io/base/cpp/array_type.cpp",
-          "bob/io/base/cpp/blitz_array.cpp",
-        ],
-        libraries = libraries,
-        library_dirs = library_dirs,
-        system_include_dirs = system_include_dirs,
-        define_macros = define_macros,
-        version = version,
-        bob_packages = bob_packages,
-        packages = packages,
-        boost_modules = boost_modules,
-      ),
-
-      Extension("bob.io.base._library",
-        [
-          "bob/io/base/bobskin.cpp",
-          "bob/io/base/codec.cpp",
-          "bob/io/base/file.cpp",
-          "bob/io/base/hdf5.cpp",
-          "bob/io/base/main.cpp",
-        ],
-        library_dirs = library_dirs,
-        libraries = libraries,
-        define_macros = define_macros,
-        system_include_dirs = system_include_dirs,
-        version = version,
-        bob_packages = bob_packages,
-        packages = packages,
-        boost_modules = boost_modules,
-      ),
-
-      Extension("bob.io.base._test",
-        [
-          "bob/io/base/test.cpp",
-        ],
-        library_dirs = library_dirs,
-        libraries = libraries,
-        define_macros = define_macros,
-        system_include_dirs = system_include_dirs,
-        version = version,
-        bob_packages = bob_packages,
-        packages = packages,
-        boost_modules = boost_modules,
-      ),
+    setup_requires=install_requires,
+    install_requires=install_requires,
+    # Classifiers are important if you plan to distribute this package through
+    # PyPI. You can find the complete list of classifiers that are valid and
+    # useful here (http://pypi.python.org/pypi?%3Aaction=list_classifiers).
+    classifiers=[
+        "Framework :: Bob",
+        "Development Status :: 4 - Beta",
+        "Intended Audience :: Developers",
+        "License :: OSI Approved :: BSD License",
+        "Natural Language :: English",
+        "Programming Language :: Python",
+        "Programming Language :: Python :: 3",
+        "Topic :: Software Development :: Libraries :: Python Modules",
     ],
-
-    cmdclass = {
-      'build_ext': build_ext
-    },
-
-    classifiers = [
-      'Framework :: Bob',
-      'Development Status :: 4 - Beta',
-      'Intended Audience :: Developers',
-      'License :: OSI Approved :: BSD License',
-      'Natural Language :: English',
-      'Programming Language :: Python',
-      'Programming Language :: Python :: 3',
-      'Topic :: Software Development :: Libraries :: Python Modules',
-    ],
-
-  )
+)