diff --git a/bob/io/base/bobskin.cpp b/bob/io/base/bobskin.cpp
index 8a23c6627861bfd6c1f378f464acdc382c23ea32..494bdafc26fe3520f67b7a5f826d8a9982ba3557 100644
--- a/bob/io/base/bobskin.cpp
+++ b/bob/io/base/bobskin.cpp
@@ -5,46 +5,129 @@
  * @brief Implementation of our bobskin class
  */
 
-#define BOB_IO_BASE_MODULE
 #include "bobskin.h"
 #include <stdexcept>
 
-bobskin::bobskin(PyObject* array, int dtype) {
+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");
   }
 
-  if (!BobIoTypeinfo_SignedSetWithStrides(&m_type, dtype,
-        PyArray_NDIM((PyArrayObject*)array),
-        PyArray_DIMS((PyArrayObject*)array),
-        PyArray_STRIDES((PyArrayObject*)array))) {
-    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, int dtype) {
+bobskin::bobskin(PyArrayObject* array, bob::io::base::array::ElementType eltype) {
 
-  if (!BobIoTypeinfo_SignedSetWithStrides(&m_type, dtype,
-        PyArray_NDIM((PyArrayObject*)array),
-        PyArray_DIMS((PyArrayObject*)array),
-        PyArray_STRIDES((PyArrayObject*)array))) {
-    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);
 
 }
 
+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) {
-  if (!BobIoTypeinfo_SignedSetWithStrides(&m_type, array->type_num,
-        array->ndim, array->shape, array->stride)) {
+  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;
 }
 
@@ -60,8 +143,8 @@ void bobskin::set(boost::shared_ptr<interface>) {
   throw std::runtime_error("error is already set");
 }
 
-void bobskin::set (const BobIoTypeinfo&) {
-  PyErr_SetString(PyExc_NotImplementedError, "setting C++ bobskin with (const type-information&) implemented - DEBUG ME!");
+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");
 }
 
diff --git a/bob/io/base/bobskin.h b/bob/io/base/bobskin.h
index a5035627f13c801162230b2e337b8b2530510937..7e69132a01e663b86dcd645f8301f8f6e3e33816 100644
--- a/bob/io/base/bobskin.h
+++ b/bob/io/base/bobskin.h
@@ -10,8 +10,13 @@
 #define PYTHON_BOB_IO_BOBSKIN_H
 
 #include <Python.h>
+
 #include <bob.io.base/array.h>
-#include <bob.blitz/cppapi.h>
+
+extern "C" {
+#include <bob.blitz/capi.h>
+}
+
 
 /**
  * Wraps a PyArrayObject such that we can access it from bob::io
@@ -23,12 +28,12 @@ class bobskin: public bob::io::base::array::interface {
     /**
      * @brief Builds a new skin from an array like object
      */
-    bobskin(PyObject* array, int dtype);
+    bobskin(PyObject* array, bob::io::base::array::ElementType eltype);
 
     /**
      * @brief Builds a new skin from a numpy array object
      */
-    bobskin(PyArrayObject* array, int dtype);
+    bobskin(PyArrayObject* array, bob::io::base::array::ElementType eltype);
 
     /**
      * @brief Builds a new skin around a blitz array object
@@ -55,12 +60,12 @@ class bobskin: public bob::io::base::array::interface {
      * @brief Re-allocates this interface taking into consideration new
      * requirements. The internal memory should be considered uninitialized.
      */
-    virtual void set (const BobIoTypeinfo& req);
+    virtual void set (const bob::io::base::array::typeinfo& req);
 
     /**
      * @brief Type information for this interface.
      */
-    virtual const BobIoTypeinfo& type() const { return m_type; }
+    virtual const bob::io::base::array::typeinfo& type() const { return m_type; }
 
     /**
      * @brief Borrows a reference from the underlying memory. This means
@@ -80,7 +85,7 @@ class bobskin: public bob::io::base::array::interface {
 
   private: //representation
 
-    BobIoTypeinfo m_type; ///< type information
+    bob::io::base::array::typeinfo m_type; ///< type information
     void* m_ptr; ///< pointer to the data
 
 };
diff --git a/bob/io/base/codec.cpp b/bob/io/base/codec.cpp
index 767fd20c31fb3bf7810a3f74c068c72d8f6e54aa..bfc3eb94de0f9b29371f3d4b9c6a85f45837b441 100644
--- a/bob/io/base/codec.cpp
+++ b/bob/io/base/codec.cpp
@@ -7,9 +7,8 @@
 
 #define BOB_IO_BASE_MODULE
 #include <bob.io.base/api.h>
-#include "cpp/CodecRegistry.h"
 
-int PyBobIoCodec_Register (const char* extension, const char* description, BobIoFileFactory factory) {
+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();
 
diff --git a/bob/io/base/csv.cpp b/bob/io/base/cpp/CSVFile.cpp
similarity index 73%
rename from bob/io/base/csv.cpp
rename to bob/io/base/cpp/CSVFile.cpp
index 7932ad833caf34c50bae4a46549421e35a8f9598..1200523a09b74eee343a14686b39ba76995cc058 100644
--- a/bob/io/base/csv.cpp
+++ b/bob/io/base/cpp/CSVFile.cpp
@@ -8,10 +8,6 @@
  * Copyright (C) Idiap Research Institute, Martigny, Switzerland
  */
 
-#define BOB_IO_BASE_MODULE
-#include <bob.io.base/api.h>
-#include <bob.io.base/File.h>
-
 #include <sstream>
 #include <fstream>
 #include <string>
@@ -24,6 +20,8 @@
 #include <boost/shared_array.hpp>
 #include <boost/algorithm/string.hpp>
 
+#include <bob.io.base/CodecRegistry.h>
+
 typedef boost::tokenizer<boost::escaped_list_separator<char> > Tokenizer;
 
 class CSVFile: public bob::io::base::File {
@@ -64,16 +62,16 @@ class CSVFile: public bob::io::base::File {
         return;
       }
 
-      m_arrayset_type.dtype = NPY_FLOAT64;
+      m_arrayset_type.dtype = bob::io::base::array::t_float64;
       m_arrayset_type.nd = 1;
       m_arrayset_type.shape[0] = entries;
-      BobIoTypeinfo_UpdateStrides(&m_arrayset_type);
+      m_arrayset_type.update_strides();
 
       m_array_type = m_arrayset_type;
       m_array_type.nd = 2;
       m_array_type.shape[0] = m_pos.size();
       m_array_type.shape[1] = entries;
-      BobIoTypeinfo_UpdateStrides(&m_array_type);
+      m_array_type.update_strides();
     }
 
     CSVFile(const char* path, char mode):
@@ -118,11 +116,11 @@ class CSVFile: public bob::io::base::File {
       return m_filename.c_str();
     }
 
-    virtual const BobIoTypeinfo& type() const {
+    virtual const bob::io::base::array::typeinfo& type() const {
       return m_arrayset_type;
     }
 
-    virtual const BobIoTypeinfo& type_all() const {
+    virtual const bob::io::base::array::typeinfo& type_all() const {
       return m_array_type;
     }
 
@@ -138,7 +136,7 @@ class CSVFile: public bob::io::base::File {
       if (m_newfile)
         throw std::runtime_error("uninitialized CSV file cannot be read");
 
-      if (!BobIoTypeinfo_IsCompatible(&buffer.type(), &m_array_type)) buffer.set(m_array_type);
+      if (!buffer.type().is_compatible(m_array_type)) buffer.set(m_array_type);
 
       //read contents
       std::string line;
@@ -158,7 +156,7 @@ class CSVFile: public bob::io::base::File {
       if (m_newfile)
         throw std::runtime_error("uninitialized CSV file cannot be read");
 
-      if (!BobIoTypeinfo_IsCompatible(&buffer.type(), &m_arrayset_type))
+      if (!buffer.type().is_compatible(m_arrayset_type))
         buffer.set(m_arrayset_type);
 
       if (index >= m_pos.size()) {
@@ -186,12 +184,12 @@ class CSVFile: public bob::io::base::File {
 
     virtual size_t append (const bob::io::base::array::interface& buffer) {
 
-      const BobIoTypeinfo& type = buffer.type();
+      const bob::io::base::array::typeinfo& type = buffer.type();
 
       if (m_newfile) {
-        if (type.nd != 1 || type.dtype != NPY_FLOAT64) {
+        if (type.nd != 1 || type.dtype != bob::io::base::array::t_float64) {
           boost::format m("cannot append %s to file '%s' - CSV files only accept 1D double precision float arrays");
-          m % BobIoTypeinfo_Str(&type) % m_filename;
+          m % type.str() % m_filename;
           throw std::runtime_error(m.str());
         }
         m_pos.clear();
@@ -203,9 +201,9 @@ class CSVFile: public bob::io::base::File {
       else {
 
         //check compatibility
-        if (!BobIoTypeinfo_IsCompatible(&m_arrayset_type, &buffer.type())) {
+        if (!m_arrayset_type.is_compatible(buffer.type())) {
           boost::format m("CSV file '%s' only accepts arrays of type %s");
-          m % m_filename % BobIoTypeinfo_Str(&m_arrayset_type);
+          m % m_filename % m_arrayset_type.str();
           throw std::runtime_error(m.str());
         }
 
@@ -217,19 +215,19 @@ class CSVFile: public bob::io::base::File {
       for (size_t k=1; k<type.shape[0]; ++k) m_file << *(p++) << ",";
       m_file << *(p++);
       m_array_type.shape[0] = m_pos.size();
-      BobIoTypeinfo_UpdateStrides(&m_array_type);
+      m_array_type.update_strides();
       return (m_pos.size()-1);
 
     }
 
     virtual void write (const bob::io::base::array::interface& buffer) {
 
-      const BobIoTypeinfo& type = buffer.type();
+      const bob::io::base::array::typeinfo& type = buffer.type();
 
       if (m_newfile) {
-        if (type.nd != 2 || type.dtype != NPY_FLOAT64) {
+        if (type.nd != 2 || type.dtype != bob::io::base::array::t_float64) {
           boost::format m("cannot write %s to file '%s' - CSV files only accept a single 2D double precision float array as input");
-          m % BobIoTypeinfo_Str(&type) % m_filename;
+          m % type.str() % m_filename;
           throw std::runtime_error(m.str());
         }
         const double* p = static_cast<const double*>(buffer.ptr());
@@ -243,7 +241,7 @@ class CSVFile: public bob::io::base::File {
         m_arrayset_type = type;
         m_arrayset_type.nd = 1;
         m_arrayset_type.shape[0] = type.shape[1];
-        BobIoTypeinfo_UpdateStrides(&m_arrayset_type);
+        m_arrayset_type.update_strides();
         m_array_type = type;
         m_newfile = false;
         return;
@@ -258,8 +256,8 @@ class CSVFile: public bob::io::base::File {
     std::fstream m_file;
     std::string m_filename;
     bool m_newfile;
-    BobIoTypeinfo m_array_type;
-    BobIoTypeinfo m_arrayset_type;
+    bob::io::base::array::typeinfo m_array_type;
+    bob::io::base::array::typeinfo m_arrayset_type;
     std::vector<std::streampos> m_pos; ///< dictionary of line starts
 
     static std::string s_codecname;
@@ -269,10 +267,48 @@ class CSVFile: public bob::io::base::File {
 std::string CSVFile::s_codecname = "bob.csv";
 
 /**
- * Registration method: use an unique name. Copy the definition to "plugin.h"
- * and then call it on "main.cpp" to register the codec.
+ * 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.
  */
-boost::shared_ptr<bob::io::base::File>
-  make_csv_file (const char* path, char mode) {
+static boost::shared_ptr<bob::io::base::File> make_file (const char* path, char mode) {
   return boost::make_shared<CSVFile>(path, mode);
 }
+
+/**
+ * Takes care of codec registration per se.
+ */
+static bool register_codec() {
+
+  boost::shared_ptr<bob::io::base::CodecRegistry> instance =
+    bob::io::base::CodecRegistry::instance();
+
+  instance->registerExtension(".csv", "Comma-Separated Values", &make_file);
+  instance->registerExtension(".txt", "Comma-Separated Values", &make_file);
+
+  return true;
+
+}
+
+static bool codec_registered = register_codec();
diff --git a/bob/io/base/cpp/CodecRegistry.cpp b/bob/io/base/cpp/CodecRegistry.cpp
index 483215e46471d68e80a7ab8003eb2a86b866ef31..229d5802f0eaf6538b83d440ebdeeda4ab862488 100644
--- a/bob/io/base/cpp/CodecRegistry.cpp
+++ b/bob/io/base/cpp/CodecRegistry.cpp
@@ -7,16 +7,15 @@
  * Copyright (C) Idiap Research Institute, Martigny, Switzerland
  */
 
-#define BOB_IO_BASE_MODULE
-#include <bob.core/logging.h>
-
-#include "CodecRegistry.h"
-
 #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;
@@ -33,7 +32,7 @@ const char* bob::io::base::CodecRegistry::getDescription(const char* ext) {
   return it->second.c_str();
 }
 
-void bob::io::base::CodecRegistry::deregisterFactory(BobIoFileFactory factory) {
+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) {
@@ -48,7 +47,7 @@ void bob::io::base::CodecRegistry::deregisterFactory(BobIoFileFactory factory) {
 }
 
 void bob::io::base::CodecRegistry::registerExtension(const char* extension,
-    const char* description, BobIoFileFactory codec) {
+    const char* description, bob::io::base::file_factory_t codec) {
 
   auto it = s_extension2codec.find(extension);
 
@@ -59,8 +58,7 @@ void bob::io::base::CodecRegistry::registerExtension(const char* extension,
   else if (!s_ignore) {
     boost::format m("extension already registered: %s - ignoring second registration with description `%s'");
     m % extension % description;
-    auto& error_stream = PyBobCoreLogging_Error();
-    error_stream << m.str() << std::endl;
+    bob::core::error << m.str() << std::endl;
     throw std::runtime_error(m.str());
   }
 
@@ -73,13 +71,13 @@ bool bob::io::base::CodecRegistry::isRegistered(const char* ext) {
   return (s_extension2codec.find(lower_extension) != s_extension2codec.end());
 }
 
-BobIoFileFactory bob::io::base::CodecRegistry::findByExtension (const char* ext) {
+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, BobIoFileFactory>::iterator it =
+  std::map<std::string, bob::io::base::file_factory_t >::iterator it =
     s_extension2codec.find(lower_extension);
 
   if (it == s_extension2codec.end()) {
@@ -92,7 +90,7 @@ BobIoFileFactory bob::io::base::CodecRegistry::findByExtension (const char* ext)
 
 }
 
-BobIoFileFactory bob::io::base::CodecRegistry::findByFilenameExtension
+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
new file mode 100644
index 0000000000000000000000000000000000000000..bbdfedfe7e2a5d3dc733e2c6360e933475c0ad4d
--- /dev/null
+++ b/bob/io/base/cpp/File.cpp
@@ -0,0 +1,10 @@
+/**
+ * @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/hdf5plugin.cpp b/bob/io/base/cpp/HDF5ArrayFile.cpp
similarity index 70%
rename from bob/io/base/hdf5plugin.cpp
rename to bob/io/base/cpp/HDF5ArrayFile.cpp
index 5982adfe6317f4e66546d0203a12d1a2f832ca08..8a9aa97f888fa38ea24ea37e85d74c883ed646b3 100644
--- a/bob/io/base/hdf5plugin.cpp
+++ b/bob/io/base/cpp/HDF5ArrayFile.cpp
@@ -7,15 +7,13 @@
  * Copyright (C) Idiap Research Institute, Martigny, Switzerland
  */
 
-#define BOB_IO_BASE_MODULE
-#include <bob.io.base/api.h>
-#include <bob.io.base/File.h>
-#include <bob.io.base/HDF5File.h>
-
 #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
  */
@@ -67,11 +65,11 @@ class HDF5ArrayFile: public bob::io::base::File {
       return m_filename.c_str();
     }
 
-    virtual const BobIoTypeinfo& type_all () const {
+    virtual const bob::io::base::array::typeinfo& type_all () const {
       return m_type_array;
     }
 
-    virtual const BobIoTypeinfo& type () const {
+    virtual const bob::io::base::array::typeinfo& type () const {
       return m_type_arrayset;
     }
 
@@ -91,7 +89,7 @@ class HDF5ArrayFile: public bob::io::base::File {
         throw std::runtime_error(f.str());
       }
 
-      if(!BobIoTypeinfo_IsCompatible(&buffer.type(), &m_type_array)) buffer.set(m_type_array);
+      if(!buffer.type().is_compatible(m_type_array)) buffer.set(m_type_array);
 
       m_file.read_buffer(m_path, 0, buffer.type(), buffer.ptr());
     }
@@ -104,7 +102,7 @@ class HDF5ArrayFile: public bob::io::base::File {
         throw std::runtime_error(f.str());
       }
 
-      if(!BobIoTypeinfo_IsCompatible(&buffer.type(), &m_type_arrayset)) buffer.set(m_type_arrayset);
+      if(!buffer.type().is_compatible(m_type_arrayset)) buffer.set(m_type_arrayset);
 
       m_file.read_buffer(m_path, index, buffer.type(), buffer.ptr());
     }
@@ -154,8 +152,8 @@ class HDF5ArrayFile: public bob::io::base::File {
 
     bob::io::base::HDF5File m_file;
     std::string  m_filename;
-    BobIoTypeinfo m_type_array;    ///< type for reading all data at once
-    BobIoTypeinfo m_type_arrayset; ///< type for reading data by sub-arrays
+    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
@@ -167,11 +165,32 @@ class HDF5ArrayFile: public bob::io::base::File {
 std::string HDF5ArrayFile::s_codecname = "bob.hdf5";
 
 /**
- * Registration method: use an unique name. Copy the definition to "plugin.h"
- * and then call it on "main.cpp" to register the codec.
+ * 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.
  */
-boost::shared_ptr<bob::io::base::File>
-  make_hdf5_file (const char* path, char mode) {
+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;
@@ -182,3 +201,22 @@ boost::shared_ptr<bob::io::base::File>
   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
index 2d42802a65a7ad51eff3eca6d760f2b62e4cb9ae..e701aced85c99ade1009ded61aaaf8e1e46b30cc 100644
--- a/bob/io/base/cpp/HDF5Attribute.cpp
+++ b/bob/io/base/cpp/HDF5Attribute.cpp
@@ -7,12 +7,11 @@
  * Copyright (C) Idiap Research Institute, Martigny, Switzerland
  */
 
-#define BOB_IO_BASE_MODULE
-#include <bob.core/logging.h>
+#include <boost/format.hpp>
 
-#include <bob.io.base/HDF5Attribute.h>
+#include <bob/core/logging.h>
 
-#include <boost/format.hpp>
+#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");
@@ -32,9 +31,8 @@ static void delete_h5dataspace (hid_t* p) {
   if (*p >= 0) {
     herr_t err = H5Sclose(*p);
     if (err < 0) {
-      auto& error_stream = PyBobCoreLogging_Error();
-      error_stream << "H5Sclose() exited with an error (" << err << "). The stack trace follows:" << std::endl;
-      error_stream << bob::io::base::format_hdf5_error() << std::endl;
+      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;
@@ -64,9 +62,8 @@ static void delete_h5type (hid_t* p) {
   if (*p >= 0) {
     herr_t err = H5Tclose(*p);
     if (err < 0) {
-      auto& error_stream = PyBobCoreLogging_Error();
-      error_stream << "H5Tclose() exited with an error (" << err << "). The stack trace follows:" << std::endl;
-      error_stream << bob::io::base::format_hdf5_error() << std::endl;
+      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;
@@ -102,9 +99,8 @@ static void delete_h5attribute (hid_t* p) {
   if (*p >= 0) {
     herr_t err = H5Aclose(*p);
     if (err < 0) {
-      auto& error_stream = PyBobCoreLogging_Error();
-      error_stream << "H5Aclose() exited with an error (" << err << "). The stack trace follows:" << std::endl;
-      error_stream << bob::io::base::format_hdf5_error() << std::endl;
+      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;
diff --git a/bob/io/base/cpp/HDF5Dataset.cpp b/bob/io/base/cpp/HDF5Dataset.cpp
index 3e4b93d8b1e9b2328702a3f822c1ec2b89b0258c..59b20939f77394d1ce287555bc397200d9fc5347 100644
--- a/bob/io/base/cpp/HDF5Dataset.cpp
+++ b/bob/io/base/cpp/HDF5Dataset.cpp
@@ -7,13 +7,12 @@
  * Copyright (C) Idiap Research Institute, Martigny, Switzerland
  */
 
-#define BOB_IO_BASE_MODULE
-#include <bob.core/logging.h>
-
 #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>
@@ -31,9 +30,8 @@ static void delete_h5dataset (hid_t* p) {
   if (*p >= 0) {
     herr_t err = H5Dclose(*p);
     if (err < 0) {
-      auto& error_stream = PyBobCoreLogging_Error();
-      error_stream << "H5Dclose() exited with an error (" << err << "). The stack trace follows:" << std::endl;
-      error_stream << bob::io::base::format_hdf5_error() << std::endl;
+      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;
@@ -63,9 +61,8 @@ static void delete_h5datatype (hid_t* p) {
   if (*p >= 0) {
     herr_t err = H5Tclose(*p);
     if (err < 0) {
-      auto& error_stream = PyBobCoreLogging_Error();
-      error_stream << "H5Tclose() exited with an error (" << err << "). The stack trace follows:" << std::endl;
-      error_stream << bob::io::base::format_hdf5_error() << std::endl;
+      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;
@@ -89,9 +86,8 @@ static void delete_h5plist (hid_t* p) {
   if (*p >= 0) {
     herr_t err = H5Pclose(*p);
     if (err < 0) {
-      auto& error_stream = PyBobCoreLogging_Error();
-      error_stream << "H5Pclose() exited with an error (" << err << "). The stack trace follows:" << std::endl;
-      error_stream << bob::io::base::format_hdf5_error() << std::endl;
+      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;
@@ -113,9 +109,8 @@ static void delete_h5dataspace (hid_t* p) {
   if (*p >= 0) {
     herr_t err = H5Sclose(*p);
     if (err < 0) {
-      auto& error_stream = PyBobCoreLogging_Error();
-      error_stream << "H5Sclose() exited with an error (" << err << "). The stack trace follows:" << std::endl;
-      error_stream << bob::io::base::format_hdf5_error() << std::endl;
+      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;
diff --git a/bob/io/base/cpp/HDF5File.cpp b/bob/io/base/cpp/HDF5File.cpp
index 3f838b48e188937cd0512548db72807e5d1d47fe..549069f8ab821df603ef35727d0da07a4a757137 100644
--- a/bob/io/base/cpp/HDF5File.cpp
+++ b/bob/io/base/cpp/HDF5File.cpp
@@ -7,10 +7,10 @@
  * Copyright (C) Idiap Research Institute, Martigny, Switzerland
  */
 
-#define BOB_IO_BASE_MODULE
-#include <bob.io.base/HDF5File.h>
 #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;
diff --git a/bob/io/base/cpp/HDF5Group.cpp b/bob/io/base/cpp/HDF5Group.cpp
index 486b7ea5e2e3221eec7e353f40a693683c67c1be..aab916684071b0f51c260483f15c3a4dd3f0766d 100644
--- a/bob/io/base/cpp/HDF5Group.cpp
+++ b/bob/io/base/cpp/HDF5Group.cpp
@@ -7,15 +7,14 @@
  * Copyright (C) Idiap Research Institute, Martigny, Switzerland
  */
 
-#define BOB_IO_BASE_MODULE
-#include <bob.core/logging.h>
-
 #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>
 
@@ -26,9 +25,8 @@ static void delete_h5g (hid_t* p) {
   if (*p >= 0) {
     herr_t err = H5Gclose(*p);
     if (err < 0) {
-      auto& error_stream = PyBobCoreLogging_Error();
-      error_stream << "H5Gclose() exited with an error (" << err << "). The stack trace follows:" << std::endl;
-      error_stream << bob::io::base::format_hdf5_error() << std::endl;
+      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;
@@ -313,9 +311,8 @@ static void delete_h5plist (hid_t* p) {
   if (*p >= 0) {
     herr_t err = H5Pclose(*p);
     if (err < 0) {
-      auto& error_stream = PyBobCoreLogging_Error();
-      error_stream << "H5Pclose() exited with an error (" << err << "). The stack trace follows:" << std::endl;
-      error_stream << bob::io::base::format_hdf5_error() << std::endl;
+      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;
diff --git a/bob/io/base/cpp/HDF5Types.cpp b/bob/io/base/cpp/HDF5Types.cpp
index e628d5299bf347f9fe30dce110619a9de5f87a9d..16795bf8ba17e07326bcef4807cfe61188b15ab4 100644
--- a/bob/io/base/cpp/HDF5Types.cpp
+++ b/bob/io/base/cpp/HDF5Types.cpp
@@ -7,11 +7,8 @@
  * Copyright (C) Idiap Research Institute, Martigny, Switzerland
  */
 
-#define BOB_IO_BASE_MODULE
-#include <bob.core/logging.h>
-
-#include <sstream>
 #include <boost/format.hpp>
+#include <sstream>
 #include <boost/make_shared.hpp>
 
 /**
@@ -27,6 +24,8 @@
 #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) {
@@ -214,9 +213,8 @@ static void delete_h5datatype (hid_t* p) {
   if (*p >= 0) {
     herr_t err = H5Tclose(*p);
     if (err < 0) {
-      auto& error_stream = PyBobCoreLogging_Error();
-      error_stream << "H5Tclose() exited with an error (" << err << "). The stack trace follows:" << std::endl;
-      error_stream << bob::io::base::format_hdf5_error() << std::endl;
+      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;
@@ -416,7 +414,7 @@ static bob::io::base::hdf5type get_datatype
   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 BobIoTypeinfo& value) const
+bool bob::io::base::HDF5Type::compatible (const bob::io::base::array::typeinfo& value) const
 {
   return *this == HDF5Type(value);
 }
@@ -620,9 +618,9 @@ bob::io::base::HDF5Type::HDF5Type(const std::string& value):
     (const blitz::Array<T,N>& value): \
       m_type(E), \
       m_shape(value.shape()) { \
-        if (N > BOB_BLITZ_MAXDIMS) {\
+        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_BLITZ_MAXDIMS; \
+          m % N % bob::io::base::array::N_MAX_DIMENSIONS_ARRAY; \
           throw std::runtime_error(m.str()); \
         } \
       }
@@ -670,56 +668,53 @@ bob::io::base::HDF5Type::HDF5Type(bob::io::base::hdf5type type, const bob::io::b
 {
 }
 
-static bob::io::base::hdf5type array_to_hdf5 (int dtype) {
-  switch(dtype) {
-    case NPY_NOTYPE:
+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 NPY_BOOL:
+    case bob::io::base::array::t_bool:
       return bob::io::base::b;
-    case NPY_INT8:
+    case bob::io::base::array::t_int8:
       return bob::io::base::i8;
-    case NPY_INT16:
+    case bob::io::base::array::t_int16:
       return bob::io::base::i16;
-    case NPY_INT32:
+    case bob::io::base::array::t_int32:
       return bob::io::base::i32;
-    case NPY_INT64:
+    case bob::io::base::array::t_int64:
       return bob::io::base::i64;
-    case NPY_UINT8:
+    case bob::io::base::array::t_uint8:
       return bob::io::base::u8;
-    case NPY_UINT16:
+    case bob::io::base::array::t_uint16:
       return bob::io::base::u16;
-    case NPY_UINT32:
+    case bob::io::base::array::t_uint32:
       return bob::io::base::u32;
-    case NPY_UINT64:
+    case bob::io::base::array::t_uint64:
       return bob::io::base::u64;
-    case NPY_FLOAT32:
+    case bob::io::base::array::t_float32:
       return bob::io::base::f32;
-    case NPY_FLOAT64:
+    case bob::io::base::array::t_float64:
       return bob::io::base::f64;
-#   ifdef NPY_FLOAT128
-    case NPY_FLOAT128:
+    case bob::io::base::array::t_float128:
       return bob::io::base::f128;
-#   endif
-    case NPY_COMPLEX64:
+    case bob::io::base::array::t_complex64:
       return bob::io::base::c64;
-    case NPY_COMPLEX128:
+    case bob::io::base::array::t_complex128:
       return bob::io::base::c128;
-#   ifdef NPY_COMPLEX256
-    case NPY_COMPLEX256:
+    case bob::io::base::array::t_complex256:
       return bob::io::base::c256;
-#   endif
   }
   throw std::runtime_error("unsupported dtype <=> hdf5 type conversion -- FIXME");
 }
 
-bob::io::base::HDF5Type::HDF5Type(const BobIoTypeinfo& ti):
+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(int dtype, const HDF5Shape& extents):
-  m_type(array_to_hdf5(dtype)),
+bob::io::base::HDF5Type::HDF5Type(bob::io::base::array::ElementType eltype,
+    const HDF5Shape& extents):
+  m_type(array_to_hdf5(eltype)),
   m_shape(extents)
 {
 }
@@ -769,63 +764,56 @@ std::string bob::io::base::HDF5Type::str() const {
   return retval.str();
 }
 
-int bob::io::base::HDF5Type::element_type() const {
-
+bob::io::base::array::ElementType bob::io::base::HDF5Type::element_type() const {
   switch (m_type) {
     case b:
-      return NPY_BOOL;
+      return bob::io::base::array::t_bool;
     case i8:
-      return NPY_INT8;
+      return bob::io::base::array::t_int8;
     case i16:
-      return NPY_INT16;
+      return bob::io::base::array::t_int16;
     case i32:
-      return NPY_INT32;
+      return bob::io::base::array::t_int32;
     case i64:
-      return NPY_INT64;
+      return bob::io::base::array::t_int64;
     case u8:
-      return NPY_UINT8;
+      return bob::io::base::array::t_uint8;
     case u16:
-      return NPY_UINT16;
+      return bob::io::base::array::t_uint16;
     case u32:
-      return NPY_UINT32;
+      return bob::io::base::array::t_uint32;
     case u64:
-      return NPY_UINT64;
+      return bob::io::base::array::t_uint64;
     case f32:
-      return NPY_FLOAT32;
+      return bob::io::base::array::t_float32;
     case f64:
-      return NPY_FLOAT64;
-#   ifdef NPY_FLOAT128
+      return bob::io::base::array::t_float64;
     case f128:
-      return NPY_FLOAT128;
-#   endif
+      return bob::io::base::array::t_float128;
     case c64:
-      return NPY_COMPLEX64;
+      return bob::io::base::array::t_complex64;
     case c128:
-      return NPY_COMPLEX128;
-#   ifdef NPY_COMPLEX256
+      return bob::io::base::array::t_complex128;
     case c256:
-      return NPY_COMPLEX256;
-#   endif
+      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 NPY_NOTYPE;
-
+  return bob::io::base::array::t_unknown;
 }
 
-void bob::io::base::HDF5Type::copy_to (BobIoTypeinfo& ti) const {
+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_BLITZ_MAXDIMS+1)) {
+  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_BLITZ_MAXDIMS+1);
+    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];
-  BobIoTypeinfo_UpdateStrides(&ti);
+  ti.update_strides();
 }
 
 bob::io::base::HDF5Descriptor::HDF5Descriptor(const HDF5Type& type, size_t size,
diff --git a/bob/io/base/cpp/HDF5Utils.cpp b/bob/io/base/cpp/HDF5Utils.cpp
index f06bd11ba9748e8051e962ef6161324c44ce0685..b735be4a22414eee60c8d3a30c83b2246648b881 100644
--- a/bob/io/base/cpp/HDF5Utils.cpp
+++ b/bob/io/base/cpp/HDF5Utils.cpp
@@ -7,12 +7,11 @@
  * Copyright (C) Idiap Research Institute, Martigny, Switzerland
  */
 
-#define BOB_IO_BASE_MODULE
-#include <bob.core/logging.h>
-
 #include <boost/format.hpp>
 #include <boost/make_shared.hpp>
 
+#include <bob/core/logging.h>
+
 #include <bob.io.base/HDF5Utils.h>
 
 /**
@@ -22,9 +21,8 @@ static void delete_h5file (hid_t* p) {
   if (*p >= 0) {
     herr_t err = H5Fclose(*p);
     if (err < 0) {
-      auto& error_stream = PyBobCoreLogging_Error();
-      error_stream << "H5Fclose(hid=" << *p << ") exited with an error (" << err << "). The stack trace follows:" << std::endl;
-      error_stream << bob::io::base::format_hdf5_error() << std::endl;
+      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;
@@ -37,9 +35,8 @@ static void delete_h5p (hid_t* p) {
   if (*p >= 0) {
     herr_t err = H5Pclose(*p);
     if (err < 0) {
-      auto& error_stream = PyBobCoreLogging_Error();
-      error_stream << "H5Pclose(hid=" << *p << ") exited with an error (" << err << "). The stack trace follows:" << std::endl;
-      error_stream << bob::io::base::format_hdf5_error() << std::endl;
+      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;
     }
   }
diff --git a/bob/io/base/torch3.cpp b/bob/io/base/cpp/T3File.cpp
similarity index 68%
rename from bob/io/base/torch3.cpp
rename to bob/io/base/cpp/T3File.cpp
index 5910da8f64d44fc00ef19a5d16449a7cdbc1c2b0..8380a62fd912aa370f06f7e307c6fe614559eb81 100644
--- a/bob/io/base/torch3.cpp
+++ b/bob/io/base/cpp/T3File.cpp
@@ -18,11 +18,6 @@
  * Copyright (C) Idiap Research Institute, Martigny, Switzerland
  */
 
-#define BOB_IO_BASE_MODULE
-#include <bob.io.base/api.h>
-#include <bob.io.base/File.h>
-#include <bob.io.base/blitz_array.h>
-
 #include <fstream>
 #include <boost/filesystem.hpp>
 #include <boost/make_shared.hpp>
@@ -35,6 +30,9 @@
 
 #include <bob.core/check.h>
 
+#include <bob.io.base/CodecRegistry.h>
+#include <bob.io.base/blitz_array.h>
+
 static inline size_t get_filesize(const char* filename) {
   struct stat filestatus;
   stat(filename, &filestatus);
@@ -71,12 +69,12 @@ class T3File: public bob::io::base::File {
 
           // are those floats or doubles?
           if (fsize == (nsamples*framesize*sizeof(float))) {
-            m_type_array.dtype = NPY_FLOAT32;
-            m_type_arrayset.dtype = NPY_FLOAT32;
+            m_type_array.dtype = bob::io::base::array::t_float32;
+            m_type_arrayset.dtype = bob::io::base::array::t_float32;
           }
           else if (fsize == (nsamples*framesize*sizeof(double))) {
-            m_type_array.dtype = NPY_FLOAT64;
-            m_type_arrayset.dtype = NPY_FLOAT64;
+            m_type_array.dtype = bob::io::base::array::t_float64;
+            m_type_arrayset.dtype = bob::io::base::array::t_float64;
           }
           else {
             boost::format s("Cannot read file '%s', mode = '%c': fsize (%d) != %d*%d*sizeof(float32) nor *sizeof(float64)");
@@ -85,8 +83,8 @@ class T3File: public bob::io::base::File {
           }
 
           size_t shape[2] = {nsamples, framesize};
-          BobIoTypeinfo_Set(&m_type_array, m_type_array.dtype, 2, &shape[0]);
-          BobIoTypeinfo_Set(&m_type_arrayset, m_type_arrayset.dtype, 1, &shape[1]);
+          m_type_array.set_shape<size_t>(2, &shape[0]);
+          m_type_arrayset.set_shape<size_t>(1, &shape[1]);
           m_newfile = false;
 
         }
@@ -98,11 +96,11 @@ class T3File: public bob::io::base::File {
       return m_filename.c_str();
     }
 
-    virtual const BobIoTypeinfo& type_all () const {
+    virtual const bob::io::base::array::typeinfo& type_all () const {
       return m_type_array;
     }
 
-    virtual const BobIoTypeinfo& type () const {
+    virtual const bob::io::base::array::typeinfo& type () const {
       return m_type_arrayset;
     }
 
@@ -122,14 +120,14 @@ class T3File: public bob::io::base::File {
         throw std::runtime_error(f.str());
       }
 
-      if (!BobIoTypeinfo_IsCompatible(&buffer.type(), &m_type_array)) buffer.set(m_type_array);
+      if (!buffer.type().is_compatible(m_type_array)) buffer.set(m_type_array);
 
       //open the file, now for reading the contents...
       std::ifstream ifile(m_filename.c_str(), std::ios::binary|std::ios::in);
 
       //skip the first 8 bytes, that contain the header that we already read
       ifile.seekg(8, std::ios::beg);
-      ifile.read(static_cast<char*>(buffer.ptr()), BobIoTypeinfo_BufferSize(&buffer.type()));
+      ifile.read(static_cast<char*>(buffer.ptr()), buffer.type().buffer_size());
 
     }
 
@@ -141,26 +139,26 @@ class T3File: public bob::io::base::File {
         throw std::runtime_error(f.str());
       }
 
-      const BobIoTypeinfo& type = buffer.type();
+      const bob::io::base::array::typeinfo& type = buffer.type();
 
-      if (!BobIoTypeinfo_IsCompatible(&buffer.type(), &m_type_arrayset)) buffer.set(m_type_arrayset);
+      if (!buffer.type().is_compatible(m_type_arrayset)) buffer.set(m_type_arrayset);
 
       //open the file, now for reading the contents...
       std::ifstream ifile(m_filename.c_str(), std::ios::binary|std::ios::in);
 
       //skip the first 8 bytes, that contain the header that we already read
-      ifile.seekg(8 + (index*BobIoTypeinfo_BufferSize(&type)), std::ios::beg);
-      ifile.read(static_cast<char*>(buffer.ptr()), BobIoTypeinfo_BufferSize(&type));
+      ifile.seekg(8 + (index*type.buffer_size()), std::ios::beg);
+      ifile.read(static_cast<char*>(buffer.ptr()), type.buffer_size());
 
     }
 
     virtual size_t append (const bob::io::base::array::interface& buffer) {
 
-      const BobIoTypeinfo& info = buffer.type();
+      const bob::io::base::array::typeinfo& info = buffer.type();
 
-      if (!m_newfile && !BobIoTypeinfo_IsCompatible(&info, &m_type_arrayset)) {
+      if (!m_newfile && !info.is_compatible(m_type_arrayset)) {
         boost::format f("input buffer of type %s cannot be appended to already initialized torch3vision binary file of type %s");
-        f % BobIoTypeinfo_Str(&info) % BobIoTypeinfo_Str(&m_type_arrayset);
+        f % info.str() % m_type_arrayset.str();
         throw std::runtime_error(f.str());
       }
 
@@ -170,15 +168,15 @@ class T3File: public bob::io::base::File {
         //can only save uni-dimensional data, so throw if that is not the case
         if (info.nd != 1) {
           boost::format m("codec for torch3vision binary files can only save uni-dimensional data, but you passed: %s");
-          m % BobIoTypeinfo_Str(&info);
+          m % info.str();
           throw std::runtime_error(m.str());
         }
 
         //can only save float32 or float64, otherwise, throw.
-        if ((info.dtype != NPY_FLOAT32) &&
-            (info.dtype != NPY_FLOAT64)) {
+        if ((info.dtype != bob::io::base::array::t_float32) &&
+            (info.dtype != bob::io::base::array::t_float64)) {
           boost::format f("cannot have T3 bindata files with type %s - only float32 or float64");
-          f % PyBlitzArray_TypenumAsString(info.dtype);
+          f % bob::io::base::array::stringize(info.dtype);
           throw std::runtime_error(f.str());
         }
 
@@ -207,13 +205,13 @@ class T3File: public bob::io::base::File {
         throw std::runtime_error(f.str());
       }
 
-      ofile.write(static_cast<const char*>(buffer.ptr()), BobIoTypeinfo_BufferSize(&info));
+      ofile.write(static_cast<const char*>(buffer.ptr()), info.buffer_size());
       ofile.close();
 
       //setup new type information
       ++m_length;
       size_t shape[2] = {m_length, info.shape[0]};
-      BobIoTypeinfo_Set(&m_type_array, m_type_array.dtype, 2, &shape[0]);
+      m_type_array.set_shape<size_t>(2, &shape[0]);
 
       //update the header information on the file
       ofile.open(m_filename.c_str(), std::ios::binary|std::ios::in|std::ios::out);
@@ -232,7 +230,7 @@ class T3File: public bob::io::base::File {
     virtual void write (const bob::io::base::array::interface& buffer) {
 
       m_newfile = true; //force file re-setting
-      const BobIoTypeinfo& info = buffer.type();
+      const bob::io::base::array::typeinfo& info = buffer.type();
 
       if (info.nd == 1) {//just do a normal append
         append(buffer);
@@ -241,10 +239,10 @@ class T3File: public bob::io::base::File {
       else if (info.nd == 2) { //append every array individually
 
         const uint8_t* ptr = static_cast<const uint8_t*>(buffer.ptr());
-        BobIoTypeinfo slice_info;
-        BobIoTypeinfo_Set(&slice_info, info.dtype, 1, &info.shape[1]);
+        bob::io::base::array::typeinfo slice_info(info.dtype, static_cast<size_t>(1),
+            &info.shape[1]);
         for (size_t k=0; k<info.shape[0]; ++k) {
-          const void* slice_ptr=static_cast<const void*>(ptr+k*BobIoTypeinfo_BufferSize(&slice_info));
+          const void* slice_ptr=static_cast<const void*>(ptr+k*slice_info.buffer_size());
           bob::io::base::array::blitz_array slice(const_cast<void*>(slice_ptr), slice_info);
           append(slice);
         }
@@ -253,7 +251,7 @@ class T3File: public bob::io::base::File {
 
       else {
         boost::format f("cannot do single write of torch3vision .bindata file with array with type '%s' - only supports 1D or 2D arrays of types float32 or float64");
-        f % BobIoTypeinfo_Str(&info);
+        f % info.str();
         throw std::runtime_error(f.str());
       }
 
@@ -263,8 +261,8 @@ class T3File: public bob::io::base::File {
 
     std::string m_filename;
     bool m_newfile;
-    BobIoTypeinfo m_type_array;
-    BobIoTypeinfo m_type_arrayset;
+    bob::io::base::array::typeinfo m_type_array;
+    bob::io::base::array::typeinfo m_type_arrayset;
     size_t m_length;
 
     static std::string s_codecname;
@@ -274,10 +272,47 @@ class T3File: public bob::io::base::File {
 std::string T3File::s_codecname = "torch3.binary";
 
 /**
- * Registration method: use an unique name. Copy the definition to "plugin.h"
- * and then call it on "main.cpp" to register the codec.
+ * 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.
  */
-boost::shared_ptr<bob::io::base::File>
-  make_torch3_file (const char* path, char mode) {
+static boost::shared_ptr<bob::io::base::File> make_file (const char* path, char mode) {
   return boost::make_shared<T3File>(path, mode);
 }
+
+/**
+ * Takes care of codec registration per se.
+ */
+static bool register_codec() {
+
+  boost::shared_ptr<bob::io::base::CodecRegistry> instance =
+    bob::io::base::CodecRegistry::instance();
+
+  instance->registerExtension(".bindata", "torch3 binary data format", &make_file);
+
+  return true;
+
+}
+
+static bool codec_registered = register_codec();
diff --git a/bob/io/base/tensor.cpp b/bob/io/base/cpp/TensorArrayFile.cpp
similarity index 56%
rename from bob/io/base/tensor.cpp
rename to bob/io/base/cpp/TensorArrayFile.cpp
index 8d51dbcb77dc8723b150e8f28fb3c0433124f3f5..d0cb72d82c948519126ac0e4dcfe237197d017b4 100644
--- a/bob/io/base/tensor.cpp
+++ b/bob/io/base/cpp/TensorArrayFile.cpp
@@ -7,11 +7,8 @@
  * Copyright (C) Idiap Research Institute, Martigny, Switzerland
  */
 
-#define BOB_IO_BASE_MODULE
-#include <bob.io.base/api.h>
-#include <bob.io.base/File.h>
-
-#include "cpp/TensorFile.h"
+#include "TensorFile.h"
+#include <bob.io.base/CodecRegistry.h>
 
 class TensorArrayFile: public bob::io::base::File {
 
@@ -29,11 +26,11 @@ class TensorArrayFile: public bob::io::base::File {
       return m_filename.c_str();
     }
 
-    virtual const BobIoTypeinfo& type_all () const {
+    virtual const bob::io::base::array::typeinfo& type_all () const {
       return m_type;
     }
 
-    virtual const BobIoTypeinfo& type () const {
+    virtual const bob::io::base::array::typeinfo& type () const {
       return m_type;
     }
 
@@ -83,7 +80,7 @@ class TensorArrayFile: public bob::io::base::File {
   private: //representation
 
     bob::io::base::TensorFile m_file;
-    BobIoTypeinfo m_type;
+    bob::io::base::array::typeinfo m_type;
     std::string m_filename;
 
     static std::string s_codecname;
@@ -93,11 +90,32 @@ class TensorArrayFile: public bob::io::base::File {
 std::string TensorArrayFile::s_codecname = "bob.tensor";
 
 /**
- * Registration method: use an unique name. Copy the definition to "plugin.h"
- * and then call it on "main.cpp" to register the codec.
+ * 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.
  */
-boost::shared_ptr<bob::io::base::File>
-  make_tensor_file (const char* path, char mode) {
+
+/**
+ * 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::TensorFile::openmode _mode;
   if (mode == 'r') _mode = bob::io::base::TensorFile::in;
@@ -108,3 +126,19 @@ boost::shared_ptr<bob::io::base::File>
   return boost::make_shared<TensorArrayFile>(path, _mode);
 
 }
+
+/**
+ * Takes care of codec registration per se.
+ */
+static bool register_codec() {
+
+  boost::shared_ptr<bob::io::base::CodecRegistry> instance =
+    bob::io::base::CodecRegistry::instance();
+
+  instance->registerExtension(".tensor", "torch3vision v2.1 tensor files", &make_file);
+
+  return true;
+
+}
+
+static bool codec_registered = register_codec();
diff --git a/bob/io/base/cpp/TensorFile.cpp b/bob/io/base/cpp/TensorFile.cpp
index d559ba67f9950de724e714016cb3f9163b424402..66b72160ed861cf97126c4ff4bf4b26fc1f18046 100644
--- a/bob/io/base/cpp/TensorFile.cpp
+++ b/bob/io/base/cpp/TensorFile.cpp
@@ -7,10 +7,11 @@
  * Copyright (C) Idiap Research Institute, Martigny, Switzerland
  */
 
-#define BOB_IO_BASE_MODULE
-#include <bob.io.base/api.h>
 #include "TensorFile.h"
 
+#include <bob.io.base/reorder.h>
+#include <bob.io.base/array_type.h>
+
 bob::io::base::TensorFile::TensorFile(const std::string& filename,
     bob::io::base::TensorFile::openmode flag):
   m_header_init(false),
@@ -24,7 +25,7 @@ bob::io::base::TensorFile::TensorFile(const std::string& filename,
     if(m_stream)
     {
       m_header.read(m_stream);
-      m_buffer.reset(new char[BobIoTypeinfo_BufferSize(&m_header.m_type)]);
+      m_buffer.reset(new char[m_header.m_type.buffer_size()]);
       m_header_init = true;
       m_n_arrays_written = m_header.m_n_samples;
 
@@ -39,7 +40,7 @@ bob::io::base::TensorFile::TensorFile(const std::string& filename,
       m_stream.open(filename.c_str(), std::ios::out | std::ios::in |
           std::ios::binary);
       m_header.read(m_stream);
-      m_buffer.reset(new char[BobIoTypeinfo_BufferSize(&m_header.m_type)]);
+      m_buffer.reset(new char[m_header.m_type.buffer_size()]);
       m_header_init = true;
       m_n_arrays_written = m_header.m_n_samples;
       m_stream.seekp(0, std::ios::end);
@@ -52,7 +53,7 @@ bob::io::base::TensorFile::TensorFile(const std::string& filename,
     m_stream.open(filename.c_str(), std::ios::in | std::ios::binary);
     if(m_stream) {
       m_header.read(m_stream);
-      m_buffer.reset(new char[BobIoTypeinfo_BufferSize(&m_header.m_type)]);
+      m_buffer.reset(new char[m_header.m_type.buffer_size()]);
       m_header_init = true;
       m_n_arrays_written = m_header.m_n_samples;
 
@@ -70,7 +71,7 @@ bob::io::base::TensorFile::~TensorFile() {
   close();
 }
 
-void bob::io::base::TensorFile::peek(BobIoTypeinfo& info) const {
+void bob::io::base::TensorFile::peek(bob::io::base::array::typeinfo& info) const {
   info = m_header.m_type;
 }
 
@@ -82,7 +83,7 @@ void bob::io::base::TensorFile::close() {
   m_stream.close();
 }
 
-void bob::io::base::TensorFile::initHeader(const BobIoTypeinfo& info) {
+void bob::io::base::TensorFile::initHeader(const bob::io::base::array::typeinfo& info) {
   // Check that data have not already been written
   if (m_n_arrays_written > 0 ) {
     throw std::runtime_error("cannot init the header of an output stream in which data have already been written");
@@ -94,25 +95,25 @@ void bob::io::base::TensorFile::initHeader(const BobIoTypeinfo& info) {
   m_header.write(m_stream);
 
   // Temporary buffer to help with data transposition...
-  m_buffer.reset(new char[BobIoTypeinfo_BufferSize(&m_header.m_type)]);
+  m_buffer.reset(new char[m_header.m_type.buffer_size()]);
 
   m_header_init = true;
 }
 
 void bob::io::base::TensorFile::write(const bob::io::base::array::interface& data) {
 
-  const BobIoTypeinfo& info = data.type();
+  const bob::io::base::array::typeinfo& info = data.type();
 
   if (!m_header_init) initHeader(info);
   else {
     //checks compatibility with previously written stuff
-    if (!BobIoTypeinfo_IsCompatible(&m_header.m_type, &info))
+    if (!m_header.m_type.is_compatible(info))
       throw std::runtime_error("buffer does not conform to expected type");
   }
 
-  BobIoReorder_RowToCol(data.ptr(), m_buffer.get(), &info);
+  bob::io::base::row_to_col_order(data.ptr(), m_buffer.get(), info);
 
-  m_stream.write(static_cast<const char*>(m_buffer.get()), BobIoTypeinfo_BufferSize(&info));
+  m_stream.write(static_cast<const char*>(m_buffer.get()), info.buffer_size());
 
   // increment m_n_arrays_written and m_current_array
   ++m_current_array;
@@ -124,12 +125,12 @@ void bob::io::base::TensorFile::read (bob::io::base::array::interface& buf) {
   if(!m_header_init) {
     throw std::runtime_error("TensorFile: header is not initialized");
   }
-  if(!BobIoTypeinfo_IsCompatible(&buf.type(), &m_header.m_type)) buf.set(m_header.m_type);
+  if(!buf.type().is_compatible(m_header.m_type)) buf.set(m_header.m_type);
 
   m_stream.read(reinterpret_cast<char*>(m_buffer.get()),
-      BobIoTypeinfo_BufferSize(&m_header.m_type));
+      m_header.m_type.buffer_size());
 
-  BobIoReorder_ColToRow(m_buffer.get(), buf.ptr(), &m_header.m_type);
+  bob::io::base::col_to_row_order(m_buffer.get(), buf.ptr(), m_header.m_type);
 
   ++m_current_array;
 }
diff --git a/bob/io/base/cpp/TensorFile.h b/bob/io/base/cpp/TensorFile.h
index 2c342a4a8746c691125108b834b16e4837abaab6..35d42bfcea4d9a25084b82c28f008acb0f9f0609 100644
--- a/bob/io/base/cpp/TensorFile.h
+++ b/bob/io/base/cpp/TensorFile.h
@@ -10,12 +10,13 @@
 #ifndef BOB_IO_TENSORFILE_H
 #define BOB_IO_TENSORFILE_H
 
-#include "TensorFileHeader.h"
-
-#include <bob.io.base/blitz_array.h>
 #include <boost/format.hpp>
 #include <stdexcept>
 
+#include <bob.io.base/blitz_array.h>
+
+#include "TensorFileHeader.h"
+
 namespace bob { namespace io { namespace base {
 
   /**
@@ -93,9 +94,9 @@ namespace bob { namespace io { namespace base {
       void read (size_t index, bob::io::base::array::interface& data);
 
       /**
-       * Peeks the file and returns the currently set type information
+       * Peeks the file and returns the currently set typeinfo
        */
-      void peek(BobIoTypeinfo& info) const;
+      void peek(bob::io::base::array::typeinfo& info) const;
 
       /**
        * Gets the number of samples/arrays written so far
@@ -129,7 +130,7 @@ namespace bob { namespace io { namespace base {
       /**
        * Initializes the tensor file with the given type and shape.
        */
-      inline void initTensorFile(const BobIoTypeinfo& info) {
+      inline void initTensorFile(const bob::io::base::array::typeinfo& info) {
         initHeader(info);
       }
 
@@ -160,7 +161,7 @@ namespace bob { namespace io { namespace base {
        * Initializes the header of the (output) stream with the given type
        * and shape
        */
-      void initHeader(const BobIoTypeinfo& info);
+      void initHeader(const bob::io::base::array::typeinfo& info);
 
     public:
 
@@ -185,7 +186,7 @@ namespace bob { namespace io { namespace base {
        * multiarrays saved have the same dimensions.
        */
       template <typename T, int D> inline blitz::Array<T,D> read() {
-        BobIoTypeinfo info;
+        bob::io::base::array::typeinfo info;
         peek(info);
         bob::io::base::array::blitz_array buf(info);
         read(buf);
@@ -194,7 +195,7 @@ namespace bob { namespace io { namespace base {
 
       template <typename T, int D> inline blitz::Array<T,D> read(size_t
           index) {
-        BobIoTypeinfo info;
+        bob::io::base::array::typeinfo info;
         peek(info);
         bob::io::base::array::blitz_array buf(info);
         read(index, buf);
diff --git a/bob/io/base/cpp/TensorFileHeader.cpp b/bob/io/base/cpp/TensorFileHeader.cpp
index 8d8dfeefce3fd1cc70c1de1212293f3cd831a53d..fb96a13b5d383eebed1c59467185272ded2a2547 100644
--- a/bob/io/base/cpp/TensorFileHeader.cpp
+++ b/bob/io/base/cpp/TensorFileHeader.cpp
@@ -7,11 +7,10 @@
  * Copyright (C) Idiap Research Institute, Martigny, Switzerland
  */
 
-#define BOB_IO_BASE_MODULE
-#include "TensorFileHeader.h"
-#include <bob.blitz/capi.h>
 #include <boost/format.hpp>
 
+#include "TensorFileHeader.h"
+
 bob::io::base::detail::TensorFileHeader::TensorFileHeader()
   : m_tensor_type(bob::io::base::Char),
     m_type(),
@@ -32,28 +31,28 @@ void bob::io::base::detail::TensorFileHeader::read(std::istream& str) {
   str.seekg(std::ios_base::beg);
 
   int val;
-  str.read(reinterpret_cast<char*>(&val), sizeof(int));
+  str.read( reinterpret_cast<char*>(&val), sizeof(int));
   m_tensor_type = (bob::io::base::TensorType)val;
   m_type.dtype = bob::io::base::tensorTypeToArrayType(m_tensor_type);
 
-  str.read(reinterpret_cast<char*>(&val), sizeof(int));
+  str.read( reinterpret_cast<char*>(&val), sizeof(int));
   m_n_samples = (size_t)val;
 
-  str.read(reinterpret_cast<char*>(&val), sizeof(int));
-  size_t nd = (size_t)val;
+  int nd;
+  str.read(reinterpret_cast<char*>(&nd), sizeof(int));
 
-  size_t shape[BOB_BLITZ_MAXDIMS];
+  int shape[BOB_MAX_DIM];
 
-  str.read(reinterpret_cast<char*>(&val), sizeof(int));
+  str.read( reinterpret_cast<char*>(&val), sizeof(int));
   shape[0] = (size_t)val;
-  str.read(reinterpret_cast<char*>(&val), sizeof(int));
+  str.read( reinterpret_cast<char*>(&val), sizeof(int));
   shape[1] = (size_t)val;
   str.read( reinterpret_cast<char*>(&val), sizeof(int));
   shape[2] = (size_t)val;
   str.read( reinterpret_cast<char*>(&val), sizeof(int));
   shape[3] = (size_t)val;
 
-  BobIoTypeinfo_Set(&m_type, m_type.dtype, nd, shape);
+  m_type.set_shape(nd, shape);
 
   header_ok();
 }
@@ -65,19 +64,19 @@ void bob::io::base::detail::TensorFileHeader::write(std::ostream& str) const
 
   int val;
   val = (int)m_tensor_type;
-  str.write(reinterpret_cast<char*>(&val), sizeof(int));
+  str.write( reinterpret_cast<char*>(&val), sizeof(int));
   val = (int)m_n_samples;
-  str.write(reinterpret_cast<char*>(&val), sizeof(int));
+  str.write( reinterpret_cast<char*>(&val), sizeof(int));
   val = (int)m_type.nd;
-  str.write(reinterpret_cast<char*>(&val), sizeof(int));
+  str.write( reinterpret_cast<char*>(&val), sizeof(int));
   val = (int)m_type.shape[0];
-  str.write(reinterpret_cast<char*>(&val), sizeof(int));
+  str.write( reinterpret_cast<char*>(&val), sizeof(int));
   val = (int)m_type.shape[1];
-  str.write(reinterpret_cast<char*>(&val), sizeof(int));
+  str.write( reinterpret_cast<char*>(&val), sizeof(int));
   val = (int)m_type.shape[2];
-  str.write(reinterpret_cast<char*>(&val), sizeof(int));
+  str.write( reinterpret_cast<char*>(&val), sizeof(int));
   val = (int)m_type.shape[3];
-  str.write(reinterpret_cast<char*>(&val), sizeof(int));
+  str.write( reinterpret_cast<char*>(&val), sizeof(int));
 }
 
 void bob::io::base::detail::TensorFileHeader::header_ok()
@@ -101,7 +100,7 @@ void bob::io::base::detail::TensorFileHeader::header_ok()
   // Check the number of samples and dimensions
   if( m_type.nd < 1 || m_type.nd > 4) {
     boost::format m("header for tensor file indicates an unsupported type: %s");
-    m % BobIoTypeinfo_Str(&m_type);
+    m % m_type.str();
     throw std::runtime_error(m.str());
   }
 
@@ -131,43 +130,43 @@ void bob::io::base::detail::TensorFileHeader::update()
 }
 
 
-bob::io::base::TensorType bob::io::base::arrayTypeToTensorType(int dtype)
+bob::io::base::TensorType bob::io::base::arrayTypeToTensorType(bob::io::base::array::ElementType eltype)
 {
-  switch(dtype)
+  switch(eltype)
   {
-    case NPY_INT8:
+    case bob::io::base::array::t_int8:
       return bob::io::base::Char;
-    case NPY_INT16:
+    case bob::io::base::array::t_int16:
       return bob::io::base::Short;
-    case NPY_INT32:
+    case bob::io::base::array::t_int32:
       return bob::io::base::Int;
-    case NPY_INT64:
+    case bob::io::base::array::t_int64:
       return bob::io::base::Long;
-    case NPY_FLOAT32:
+    case bob::io::base::array::t_float32:
       return bob::io::base::Float;
-    case NPY_FLOAT64:
+    case bob::io::base::array::t_float64:
       return bob::io::base::Double;
     default:
       throw std::runtime_error("unsupported data type found while converting array type to tensor type");
   }
 }
 
-int bob::io::base::tensorTypeToArrayType(bob::io::base::TensorType tensortype)
+bob::io::base::array::ElementType bob::io::base::tensorTypeToArrayType(bob::io::base::TensorType tensortype)
 {
   switch(tensortype)
   {
     case bob::io::base::Char:
-      return NPY_INT8;
+      return bob::io::base::array::t_int8;
     case bob::io::base::Short:
-      return NPY_INT16;
+      return bob::io::base::array::t_int16;
     case bob::io::base::Int:
-      return NPY_INT32;
+      return bob::io::base::array::t_int32;
     case bob::io::base::Long:
-      return NPY_INT64;
+      return bob::io::base::array::t_int64;
     case bob::io::base::Float:
-      return NPY_FLOAT32;
+      return bob::io::base::array::t_float32;
     case bob::io::base::Double:
-      return NPY_FLOAT64;
+      return bob::io::base::array::t_float64;
     default:
       throw std::runtime_error("unsupported data type found while converting tensor type to array type");
   }
diff --git a/bob/io/base/cpp/TensorFileHeader.h b/bob/io/base/cpp/TensorFileHeader.h
index 7f3275d038e74d3375dbbee09ffc19fdf362ee56..7e852b829997eb2f07914123e88646ccbd1f2fcb 100644
--- a/bob/io/base/cpp/TensorFileHeader.h
+++ b/bob/io/base/cpp/TensorFileHeader.h
@@ -11,9 +11,10 @@
 #ifndef BOB_IO_BASE_TENSORFILEHEADER_H
 #define BOB_IO_BASE_TENSORFILEHEADER_H
 
-#include <bob.io.base/api.h>
-#include <blitz/array.h>
 #include <fstream>
+#include <blitz/array.h>
+
+#include <bob.io.base/array.h>
 
 namespace bob { namespace io { namespace base {
 
@@ -28,8 +29,8 @@ namespace bob { namespace io { namespace base {
     Double
   };
 
-  TensorType arrayTypeToTensorType(int dtype);
-  int tensorTypeToArrayType(bob::io::base::TensorType tensortype);
+  TensorType arrayTypeToTensorType(bob::io::base::array::ElementType eltype);
+  bob::io::base::array::ElementType tensorTypeToArrayType(bob::io::base::TensorType tensortype);
 
   namespace detail {
     /**
@@ -84,7 +85,7 @@ namespace bob { namespace io { namespace base {
 
       //representation
       TensorType m_tensor_type; ///< array element type
-      BobIoTypeinfo m_type; ///< the type information
+      bob::io::base::array::typeinfo m_type; ///< the type information
       size_t m_n_samples; ///< total number of arrays in the file
       size_t m_tensor_size; ///< the number of dimensions in each array
     };
diff --git a/bob/io/base/cpp/array.cpp b/bob/io/base/cpp/array.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2ffc94d77a13adec893f99fa8b052a55c45554ff
--- /dev/null
+++ b/bob/io/base/cpp/array.cpp
@@ -0,0 +1,134 @@
+/**
+ * @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
new file mode 100644
index 0000000000000000000000000000000000000000..d42368e9175199572724f337ba5623d6a8a76a71
--- /dev/null
+++ b/bob/io/base/cpp/array_type.cpp
@@ -0,0 +1,126 @@
+/**
+ * @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
index 9439a4c46abeceb1af564fa91ec24e15c2e6dd77..2bc723a71d4b2770207fb24732641e1e67a1948f 100644
--- a/bob/io/base/cpp/blitz_array.cpp
+++ b/bob/io/base/cpp/blitz_array.cpp
@@ -7,10 +7,10 @@
  * Copyright (C) Idiap Research Institute, Martigny, Switzerland
  */
 
-#define BOB_IO_BASE_MODULE
-#include <bob.io.base/blitz_array.h>
 #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);
 }
@@ -27,26 +27,21 @@ bob::io::base::array::blitz_array::blitz_array(const interface& other) {
   set(other);
 }
 
-bob::io::base::array::blitz_array::blitz_array(const BobIoTypeinfo& info) {
+bob::io::base::array::blitz_array::blitz_array(const typeinfo& info) {
   set(info);
 }
 
-bob::io::base::array::blitz_array::blitz_array(void* data, const BobIoTypeinfo& info):
-  m_type(),
+bob::io::base::array::blitz_array::blitz_array(void* data, const typeinfo& info):
+  m_type(info),
   m_ptr(data),
   m_is_blitz(false) {
-  if (!BobIoTypeinfo_Copy(&m_type, &info)) {
-    throw std::runtime_error("error already set");
-  }
 }
 
 bob::io::base::array::blitz_array::~blitz_array() {
 }
 
 void bob::io::base::array::blitz_array::set(boost::shared_ptr<blitz_array> other) {
-  if (!BobIoTypeinfo_Copy(&m_type, &other->m_type)) {
-    throw std::runtime_error("error already set");
-  }
+  m_type = other->m_type;
   m_ptr = other->m_ptr;
   m_is_blitz = other->m_is_blitz;
   m_data = other->m_data;
@@ -54,13 +49,11 @@ void bob::io::base::array::blitz_array::set(boost::shared_ptr<blitz_array> other
 
 void bob::io::base::array::blitz_array::set(const interface& other) {
   set(other.type());
-  memcpy(m_ptr, other.ptr(), BobIoTypeinfo_BufferSize(&m_type));
+  memcpy(m_ptr, other.ptr(), m_type.buffer_size());
 }
 
 void bob::io::base::array::blitz_array::set(boost::shared_ptr<interface> other) {
-  if (!BobIoTypeinfo_Copy(&m_type, &other->type())) {
-    throw std::runtime_error("error already set");
-  }
+  m_type = other->type();
   m_ptr = other->ptr();
   m_is_blitz = false;
   m_data = other;
@@ -112,66 +105,58 @@ static boost::shared_ptr<void> make_array(size_t nd, const size_t* shape,
   throw std::runtime_error("unsupported number of dimensions -- debug me");
 }
 
-void bob::io::base::array::blitz_array::set (const BobIoTypeinfo& req) {
-  if (BobIoTypeinfo_IsCompatible(&m_type, &req)) return; ///< double-check requirement first!
-
-  //have to go through reallocation
-  if (!BobIoTypeinfo_Copy(&m_type, &req)) {
-    throw std::runtime_error("error already set");
-  }
+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 NPY_BOOL:
+    case bob::io::base::array::t_bool:
       m_data = make_array<bool>(req.nd, req.shape, m_ptr);
       return;
-    case NPY_INT8:
+    case bob::io::base::array::t_int8:
       m_data = make_array<int8_t>(req.nd, req.shape, m_ptr);
       return;
-    case NPY_INT16:
+    case bob::io::base::array::t_int16:
       m_data = make_array<int16_t>(req.nd, req.shape, m_ptr);
       return;
-    case NPY_INT32:
+    case bob::io::base::array::t_int32:
       m_data = make_array<int32_t>(req.nd, req.shape, m_ptr);
       return;
-    case NPY_INT64:
+    case bob::io::base::array::t_int64:
       m_data = make_array<int64_t>(req.nd, req.shape, m_ptr);
       return;
-    case NPY_UINT8:
+    case bob::io::base::array::t_uint8:
       m_data = make_array<uint8_t>(req.nd, req.shape, m_ptr);
       return;
-    case NPY_UINT16:
+    case bob::io::base::array::t_uint16:
       m_data = make_array<uint16_t>(req.nd, req.shape, m_ptr);
       return;
-    case NPY_UINT32:
+    case bob::io::base::array::t_uint32:
       m_data = make_array<uint32_t>(req.nd, req.shape, m_ptr);
       return;
-    case NPY_UINT64:
+    case bob::io::base::array::t_uint64:
       m_data = make_array<uint64_t>(req.nd, req.shape, m_ptr);
       return;
-    case NPY_FLOAT32:
+    case bob::io::base::array::t_float32:
       m_data = make_array<float>(req.nd, req.shape, m_ptr);
       return;
-    case NPY_FLOAT64:
+    case bob::io::base::array::t_float64:
       m_data = make_array<double>(req.nd, req.shape, m_ptr);
       return;
-#   ifdef NPY_FLOAT128
-    case NPY_FLOAT128:
+    case bob::io::base::array::t_float128:
       m_data = make_array<long double>(req.nd, req.shape, m_ptr);
       return;
-#   endif
-    case NPY_COMPLEX64:
+    case bob::io::base::array::t_complex64:
       m_data = make_array<std::complex<float> >(req.nd, req.shape, m_ptr);
       return;
-    case NPY_COMPLEX128:
+    case bob::io::base::array::t_complex128:
       m_data = make_array<std::complex<double> >(req.nd, req.shape, m_ptr);
       return;
-#   ifdef NPY_COMPLEX256
-    case NPY_COMPLEX256:
+    case bob::io::base::array::t_complex256:
       m_data = make_array<std::complex<long double> >(req.nd, req.shape, m_ptr);
       return;
-#   endif
     default:
       break;
   }
diff --git a/bob/io/base/cpp/reorder.cpp b/bob/io/base/cpp/reorder.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cda5ab335a47cb9a05dcf2e14357b91f6311cdfd
--- /dev/null
+++ b/bob/io/base/cpp/reorder.cpp
@@ -0,0 +1,288 @@
+/**
+ * @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/utils.cpp b/bob/io/base/cpp/utils.cpp
similarity index 52%
rename from bob/io/base/utils.cpp
rename to bob/io/base/cpp/utils.cpp
index 53ebd5fb28160f3fcdc1e090345d623b38bdac95..3467b997726137f619d1fb4911d5df8b28caaadc 100644
--- a/bob/io/base/utils.cpp
+++ b/bob/io/base/cpp/utils.cpp
@@ -7,31 +7,24 @@
  * Copyright (C) Idiap Research Institute, Martigny, Switzerland
  */
 
-#define BOB_IO_BASE_MODULE
-#include <bob.io.base/api.h>
-#include <bob.io.base/File.h>
-#include "cpp/CodecRegistry.h"
+#include <bob.io.base/CodecRegistry.h>
+#include <bob.io.base/utils.h>
 
-boost::shared_ptr<bob::io::base::File> BobIoFile_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);
-
-}
-
-boost::shared_ptr<bob::io::base::File> BobIoFile_OpenWithExtension (const char* filename,
+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);
 }
 
-void BobIoFile_Peek (const char* filename, BobIoTypeinfo* info) {
-  BobIoTypeinfo_Copy(info, &BobIoFile_Open(filename, 'r')->type());
+bob::io::base::array::typeinfo bob::io::base::peek (const char* filename) {
+  return open(filename, 'r')->type();
 }
 
-void BobIoFile_PeekAll (const char* filename, BobIoTypeinfo* info) {
-  BobIoTypeinfo_Copy(info, &BobIoFile_Open(filename, 'r')->type_all());
+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
index 3f36c382fc50759d8657ddc43bb17fb7fc1ae45e..58d760c5bf52455de8cddd27715d2ce8ff1a1ca5 100644
--- a/bob/io/base/file.cpp
+++ b/bob/io/base/file.cpp
@@ -8,12 +8,14 @@
 #define BOB_IO_BASE_MODULE
 #include "bobskin.h"
 #include <bob.io.base/api.h>
-#include <bob.io.base/File.h>
 #include <numpy/arrayobject.h>
 #include <bob.blitz/capi.h>
 #include <bob.blitz/cleanup.h>
 #include <stdexcept>
 
+#include <bob.io.base/CodecRegistry.h>
+#include <bob.io.base/utils.h>
+
 #define FILETYPE_NAME "File"
 PyDoc_STRVAR(s_file_str, BOB_EXT_MODULE_PREFIX "." FILETYPE_NAME);
 
@@ -119,10 +121,10 @@ static int PyBobIoFile_Init(PyBobIoFileObject* self, PyObject *args, PyObject* k
 
   try {
     if (pretend_extension) {
-      self->f = BobIoFile_OpenWithExtension(c_filename, mode, pretend_extension);
+      self->f = bob::io::base::open(c_filename, mode, pretend_extension);
     }
     else {
-      self->f = BobIoFile_Open(c_filename, mode);
+      self->f = bob::io::base::open(c_filename, mode);
     }
   }
   catch (std::exception& e) {
@@ -191,6 +193,51 @@ static Py_ssize_t PyBobIoFile_Len (PyBobIoFileObject* self) {
   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
@@ -200,14 +247,15 @@ static PyObject* PyBobIoFile_GetIndex (PyBobIoFileObject* self, Py_ssize_t i) {
     return 0;
   }
 
-  const BobIoTypeinfo& info = self->f->type();
+  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];
 
-  if (info.dtype == NPY_NOTYPE) return 0; ///< failure
+  int type_num = PyBobIo_AsTypenum(info.dtype);
+  if (type_num == NPY_NOTYPE) return 0; ///< failure
 
-  PyObject* retval = PyArray_SimpleNew(info.nd, shape, info.dtype);
+  PyObject* retval = PyArray_SimpleNew(info.nd, shape, type_num);
   if (!retval) return 0;
   auto retval_ = make_safe(retval);
 
@@ -240,17 +288,18 @@ static PyObject* PyBobIoFile_GetSlice (PyBobIoFileObject* self, PySliceObject* s
         self->f->size(), &start, &stop, &step, &slicelength) < 0) return 0;
 
   //creates the return array
-  const BobIoTypeinfo& info = self->f->type();
+  const bob::io::base::array::typeinfo& info = self->f->type();
 
-  if (info.dtype == NPY_NOTYPE) return 0; ///< failure
+  int type_num = PyBobIo_AsTypenum(info.dtype);
+  if (type_num == NPY_NOTYPE) return 0; ///< failure
 
-  if (slicelength <= 0) return PyArray_SimpleNew(0, 0, info.dtype);
+  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, info.dtype);
+  PyObject* retval = PyArray_SimpleNew(info.nd+1, shape, type_num);
   if (!retval) return 0;
   auto retval_ = make_safe(retval);
 
@@ -334,14 +383,15 @@ static PyObject* PyBobIoFile_Read(PyBobIoFileObject* self, PyObject *args, PyObj
 
   // reads the whole file in a single shot
 
-  const BobIoTypeinfo& info = self->f->type_all();
+  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];
 
-  if (info.dtype == NPY_NOTYPE) return 0; ///< failure
+  int type_num = PyBobIo_AsTypenum(info.dtype);
+  if (type_num == NPY_NOTYPE) return 0; ///< failure
 
-  PyObject* retval = PyArray_SimpleNew(info.nd, shape, info.dtype);
+  PyObject* retval = PyArray_SimpleNew(info.nd, shape, type_num);
   if (!retval) return 0;
   auto retval_ = make_safe(retval);
 
@@ -494,12 +544,13 @@ Returns the current position of the newly written array.\n\
 "
 );
 
-PyObject* PyBobIo_TypeinfoAsTuple (const BobIoTypeinfo& ti) {
+PyObject* PyBobIo_TypeInfoAsTuple (const bob::io::base::array::typeinfo& ti) {
 
-  if (ti.dtype == NPY_NOTYPE) return 0;
+  int type_num = PyBobIo_AsTypenum(ti.dtype);
+  if (type_num == NPY_NOTYPE) return 0;
 
   PyObject* retval = Py_BuildValue("NNN",
-      reinterpret_cast<PyObject*>(PyArray_DescrFromType(ti.dtype)),
+      reinterpret_cast<PyObject*>(PyArray_DescrFromType(type_num)),
       PyTuple_New(ti.nd), //shape
       PyTuple_New(ti.nd)  //strides
       );
@@ -525,12 +576,12 @@ static PyObject* PyBobIoFile_Describe(PyBobIoFileObject* self, PyObject *args, P
   PyObject* all = 0;
   if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &all)) return 0;
 
-  const BobIoTypeinfo* info = 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);
+  return PyBobIo_TypeInfoAsTuple(*info);
 }
 
 PyDoc_STRVAR(s_describe_str, "describe");
diff --git a/bob/io/base/hdf5.cpp b/bob/io/base/hdf5.cpp
index 1b56fa64531d6b7a2de44b09bdb6e6673368c1f5..dcb4249cc61a7f6f67c1c0cc32a360ca7b805a25 100644
--- a/bob/io/base/hdf5.cpp
+++ b/bob/io/base/hdf5.cpp
@@ -7,7 +7,6 @@
 
 #define BOB_IO_BASE_MODULE
 #include <bob.io.base/api.h>
-#include <bob.io.base/HDF5File.h>
 
 #include <boost/make_shared.hpp>
 #include <numpy/arrayobject.h>
diff --git a/bob/io/base/cpp/CodecRegistry.h b/bob/io/base/include/bob.io.base/CodecRegistry.h
similarity index 86%
rename from bob/io/base/cpp/CodecRegistry.h
rename to bob/io/base/include/bob.io.base/CodecRegistry.h
index aa9501ef47191e28fe451dda3ff7a56c9c583be0..019bb5770959199f2a27c6df1594770c65dcf1f6 100644
--- a/bob/io/base/cpp/CodecRegistry.h
+++ b/bob/io/base/include/bob.io.base/CodecRegistry.h
@@ -14,7 +14,7 @@
 #include <string>
 #include <boost/shared_ptr.hpp>
 
-#include <bob.io.base/api.h>
+#include <bob.io.base/File.h>
 
 namespace bob { namespace io { namespace base {
 
@@ -47,9 +47,9 @@ namespace bob { namespace io { namespace base {
     public: //object access
 
       void registerExtension(const char* extension, const char* description,
-          BobIoFileFactory factory);
+          file_factory_t factory);
 
-      void deregisterFactory(BobIoFileFactory factory);
+      void deregisterFactory(file_factory_t factory);
       void deregisterExtension(const char* ext);
 
       /**
@@ -58,8 +58,8 @@ namespace bob { namespace io { namespace base {
        */
       const char* getDescription(const char* ext);
 
-      BobIoFileFactory findByExtension(const char* ext);
-      BobIoFileFactory findByFilenameExtension(const char* fn);
+      file_factory_t findByExtension(const char* ext);
+      file_factory_t findByFilenameExtension(const char* fn);
 
       bool isRegistered(const char* ext);
 
@@ -70,7 +70,7 @@ namespace bob { namespace io { namespace base {
       // Not implemented
       CodecRegistry( const CodecRegistry&);
 
-      std::map<std::string, BobIoFileFactory> s_extension2codec;
+      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?
 
diff --git a/bob/io/base/include/bob.io.base/File.h b/bob/io/base/include/bob.io.base/File.h
index 1b71c9301da2d33f7041a9f7c6f73d5a66ddb471..e41bccdd9c4983f2be3526b3d1a24cacab150b87 100644
--- a/bob/io/base/include/bob.io.base/File.h
+++ b/bob/io/base/include/bob.io.base/File.h
@@ -11,8 +11,9 @@
 #ifndef BOB_IO_BASE_FILE_H
 #define BOB_IO_BASE_FILE_H
 
-#include <bob.io.base/blitz_array.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 {
 
@@ -24,7 +25,7 @@ namespace bob { namespace io { namespace base {
 
     public: //abstract API
 
-      virtual ~File() {};
+      virtual ~File();
 
       /**
        * The filename this array codec current points to
@@ -32,16 +33,16 @@ namespace bob { namespace io { namespace base {
       virtual const char* filename() const =0;
 
       /**
-       * The type information of data within this file, if it is supposed to be
-       * read as as a sequence of arrays
+       * The typeinfo of data within this file, if it is supposed to be read as
+       * as a sequence of arrays
        */
-      virtual const BobIoTypeinfo& type() const =0;
+      virtual const bob::io::base::array::typeinfo& type() const =0;
 
       /**
-       * The type information of data within this file, if it is supposed to be
-       * read as a single array.
+       * The typeinfo of data within this file, if it is supposed to be read as
+       * a single array.
        */
-      virtual const BobIoTypeinfo& type_all() const =0;
+      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
@@ -156,6 +157,28 @@ namespace bob { namespace io { namespace base {
 
   };
 
+  /**
+   * @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/HDF5Dataset.h b/bob/io/base/include/bob.io.base/HDF5Dataset.h
index 9059baba2087be3a64504aed157b4edd47c75a77..557241079ca1a289f8ea5d778cb082837ea648a9 100644
--- a/bob/io/base/include/bob.io.base/HDF5Dataset.h
+++ b/bob/io/base/include/bob.io.base/HDF5Dataset.h
@@ -13,7 +13,6 @@
 #include <vector>
 
 #include <boost/shared_ptr.hpp>
-#include <boost/weak_ptr.hpp>
 #include <blitz/array.h>
 #include <hdf5.h>
 
diff --git a/bob/io/base/include/bob.io.base/HDF5File.h b/bob/io/base/include/bob.io.base/HDF5File.h
index 4c80604e74c319bcad99d8e531e37b37098e6b39..31c65944e5088b51af3fe1307e270e466b71052a 100644
--- a/bob/io/base/include/bob.io.base/HDF5File.h
+++ b/bob/io/base/include/bob.io.base/HDF5File.h
@@ -12,9 +12,10 @@
 #ifndef BOB_IO_BASE_HDF5FILE_H
 #define BOB_IO_BASE_HDF5FILE_H
 
-#include <bob.io.base/HDF5Utils.h>
 #include <boost/format.hpp>
 
+#include <bob.io.base/HDF5Utils.h>
+
 namespace bob { namespace io { namespace base {
 
   /**
diff --git a/bob/io/base/include/bob.io.base/HDF5Group.h b/bob/io/base/include/bob.io.base/HDF5Group.h
index 9071403583f561bf5469e1255dc51aeb7ab1f5b3..9dcd7a6e76cccdb40c1e4b98b4efdec63bcc52ef 100644
--- a/bob/io/base/include/bob.io.base/HDF5Group.h
+++ b/bob/io/base/include/bob.io.base/HDF5Group.h
@@ -10,14 +10,14 @@
 #ifndef BOB_IO_BASE_HDF5GROUP_H
 #define BOB_IO_BASE_HDF5GROUP_H
 
-#include <bob.io.base/HDF5Types.h>
-#include <bob.io.base/HDF5Dataset.h>
-#include <bob.io.base/HDF5Attribute.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;
diff --git a/bob/io/base/include/bob.io.base/HDF5Types.h b/bob/io/base/include/bob.io.base/HDF5Types.h
index 01c5cc5e26aa17b0567b6772f725c49ed59cc0c9..d19eab341873aafd33d2d4342fede82f5d7d3c79 100644
--- a/bob/io/base/include/bob.io.base/HDF5Types.h
+++ b/bob/io/base/include/bob.io.base/HDF5Types.h
@@ -10,6 +10,12 @@
 #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)
@@ -23,12 +29,6 @@
 
 #include <bob.io.base/array.h>
 
-#include <vector>
-#include <string>
-#include <boost/shared_ptr.hpp>
-#include <blitz/array.h>
-#include <hdf5.h>
-
 namespace bob { namespace io { namespace base {
 
   /**
@@ -340,14 +340,14 @@ namespace bob { namespace io { namespace base {
       HDF5Type(hdf5type type);
 
       /**
-       * Creates a HDF5Type from an BobIoTypeinfo
+       * Creates a HDF5Type from an bob::io::base::array::typeinfo
        */
-      HDF5Type(const BobIoTypeinfo& ti);
+      HDF5Type(const bob::io::base::array::typeinfo& ti);
 
       /**
        * Creates a HDF5Type from a type enumeration and an explicit shape
        */
-      HDF5Type(int dtype, const HDF5Shape& extents);
+      HDF5Type(bob::io::base::array::ElementType eltype, const HDF5Shape& extents);
 
       /**
        * Creates a HDF5Type from a type enumeration and an explicit shape
@@ -400,7 +400,7 @@ namespace bob { namespace io { namespace base {
       /**
        * Checks if an existing object is compatible with my type
        */
-      bool compatible (const BobIoTypeinfo& value) const;
+      bool compatible (const bob::io::base::array::typeinfo& value) const;
 
       /**
        * Returns the HDF5Shape of this type
@@ -436,12 +436,12 @@ namespace bob { namespace io { namespace base {
        * Returns a mapping between the current type and the supported element
        * types in bob::io::base::array
        */
-      int element_type() const;
+      bob::io::base::array::ElementType element_type() const;
 
       /**
-       * Copies this type information to a stock BobIoTypeinfo
+       * Copies this type information to a stock bob::io::base::array::typeinfo
        */
-      void copy_to (BobIoTypeinfo& ti) const;
+      void copy_to (bob::io::base::array::typeinfo& ti) const;
 
     private: //representation
 
diff --git a/bob/io/base/include/bob.io.base/HDF5Utils.h b/bob/io/base/include/bob.io.base/HDF5Utils.h
index d380dfdd6b09a7bc8727d1b7b477c9820ab43145..670430e2b4ffdf47d16c4953b593b89ba5352058 100644
--- a/bob/io/base/include/bob.io.base/HDF5Utils.h
+++ b/bob/io/base/include/bob.io.base/HDF5Utils.h
@@ -27,13 +27,13 @@
 #ifndef BOB_IO_BASE_HDF5UTILS_H
 #define BOB_IO_BASE_HDF5UTILS_H
 
-#include <bob.io.base/HDF5Group.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 {
 
   /**
diff --git a/bob/io/base/include/bob.io.base/api.h b/bob/io/base/include/bob.io.base/api.h
index 59b1dbb5eb0e403fc9ec78cefffafdeb9878bc7f..001e8d4a5a282c082eb2adc862c0c9e15ff50619 100644
--- a/bob/io/base/include/bob.io.base/api.h
+++ b/bob/io/base/include/bob.io.base/api.h
@@ -13,11 +13,13 @@
 #define BOB_IO_BASE_PREFIX    "bob.io.base"
 #define BOB_IO_BASE_FULL_NAME "bob.io.base._library"
 
-/* Maximum number of dimensions supported at this library */
-#define BOB_BLITZ_MAXDIMS 4
-
 #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>
 
 /*******************
@@ -27,37 +29,12 @@
 /* Enum defining entries in the function table */
 enum _PyBobIo_ENUM{
   PyBobIo_APIVersion_NUM = 0,
-  // C/C++ Type Information
-  BobIoTypeinfo_Init_NUM,
-  BobIoTypeinfo_Copy_NUM,
-  BobIoTypeinfo_Set_NUM,
-  BobIoTypeinfo_SetWithStrides_NUM,
-  BobIoTypeinfo_SignedSet_NUM,
-  BobIoTypeinfo_SignedSetWithStrides_NUM,
-  BobIoTypeinfo_Reset_NUM,
-  BobIoTypeinfo_IsValid_NUM,
-  BobIoTypeinfo_HasValidShape_NUM,
-  BobIoTypeinfo_ResetShape_NUM,
-  BobIoTypeinfo_UpdateStrides_NUM,
-  BobIoTypeinfo_Size_NUM,
-  BobIoTypeinfo_BufferSize_NUM,
-  BobIoTypeinfo_IsCompatible_NUM,
-  BobIoTypeinfo_Str_NUM,
-  // Data reordering
-  BobIoReorder_RowToCol_NUM,
-  BobIoReorder_ColToRow_NUM,
-  BobIoReorder_RowToColComplex_NUM,
-  BobIoReorder_ColToRowComplex_NUM,
   // Bindings for bob.io.base.File
   PyBobIoFile_Type_NUM,
   PyBobIoFileIterator_Type_NUM,
-  // File loading and data type peeking
-  BobIoFile_Open_NUM,
-  BobIoFile_OpenWithExtension_NUM,
-  BobIoFile_Peek_NUM,
-  BobIoFile_PeekAll_NUM,
   // I/O generic bindings
-  PyBobIo_TypeinfoAsTuple_NUM,
+  PyBobIo_AsTypenum_NUM,
+  PyBobIo_TypeInfoAsTuple_NUM,
   PyBobIo_FilenameConverter_NUM,
   // HDF5 bindings
   PyBobIoHDF5File_Type_NUM,
@@ -78,88 +55,11 @@ enum _PyBobIo_ENUM{
 
 #define PyBobIo_APIVersion_TYPE int
 
-/********************
- * Type Information *
- ********************/
-
-typedef struct {
-
-    int dtype; ///< data type
-    size_t nd; ///< number of dimensions
-    size_t shape[BOB_BLITZ_MAXDIMS+1]; ///< length along each dimension
-    size_t stride[BOB_BLITZ_MAXDIMS+1]; ///< strides along each dimension
-
-} BobIoTypeinfo;
-
-
-#define BobIoTypeinfo_Init_RET void
-#define BobIoTypeinfo_Init_PROTO (BobIoTypeinfo*)
-
-#define BobIoTypeinfo_Copy_RET int
-#define BobIoTypeinfo_Copy_PROTO (BobIoTypeinfo*, const BobIoTypeinfo*)
-
-#define BobIoTypeinfo_Set_RET int
-#define BobIoTypeinfo_Set_PROTO (BobIoTypeinfo*, int, size_t, const size_t*)
-
-#define BobIoTypeinfo_SetWithStrides_RET int
-#define BobIoTypeinfo_SetWithStrides_PROTO (BobIoTypeinfo*, int, size_t, const size_t*, const size_t*)
-
-#define BobIoTypeinfo_SignedSet_RET int
-#define BobIoTypeinfo_SignedSet_PROTO (BobIoTypeinfo*, int, Py_ssize_t, const Py_ssize_t*)
-
-#define BobIoTypeinfo_SignedSetWithStrides_RET int
-#define BobIoTypeinfo_SignedSetWithStrides_PROTO (BobIoTypeinfo*, int, Py_ssize_t, const Py_ssize_t*, const Py_ssize_t*)
-
-#define BobIoTypeinfo_Reset_RET void
-#define BobIoTypeinfo_Reset_PROTO (BobIoTypeinfo*)
-
-#define BobIoTypeinfo_IsValid_RET bool
-#define BobIoTypeinfo_IsValid_PROTO (const BobIoTypeinfo*)
-
-#define BobIoTypeinfo_HasValidShape_RET bool
-#define BobIoTypeinfo_HasValidShape_PROTO (const BobIoTypeinfo*)
-
-#define BobIoTypeinfo_ResetShape_RET void
-#define BobIoTypeinfo_ResetShape_PROTO (BobIoTypeinfo*)
-
-#define BobIoTypeinfo_UpdateStrides_RET int
-#define BobIoTypeinfo_UpdateStrides_PROTO (BobIoTypeinfo*)
-
-#define BobIoTypeinfo_Size_RET size_t
-#define BobIoTypeinfo_Size_PROTO (const BobIoTypeinfo*)
-
-#define BobIoTypeinfo_BufferSize_RET size_t
-#define BobIoTypeinfo_BufferSize_PROTO (const BobIoTypeinfo*)
-
-#define BobIoTypeinfo_IsCompatible_RET bool
-#define BobIoTypeinfo_IsCompatible_PROTO (const BobIoTypeinfo*, const BobIoTypeinfo*)
-
-#define BobIoTypeinfo_Str_RET std::string
-#define BobIoTypeinfo_Str_PROTO (const BobIoTypeinfo*)
-
-/********************
- * Array reordering *
- ********************/
-
-#define BobIoReorder_RowToCol_RET int
-#define BobIoReorder_RowToCol_PROTO (const void*, void*, const BobIoTypeinfo*)
-
-#define BobIoReorder_ColToRow_RET int
-#define BobIoReorder_ColToRow_PROTO (const void*, void*, const BobIoTypeinfo*)
-
-#define BobIoReorder_RowToColComplex_RET int
-#define BobIoReorder_RowToColComplex_PROTO (const void*, void*, void*, const BobIoTypeinfo*)
-
-#define BobIoReorder_ColToRowComplex_RET int
-#define BobIoReorder_ColToRowComplex_PROTO (const void*, const void*, void*, const BobIoTypeinfo*)
-
 /**********************************
  * Bindings for bob.io.base.File *
  **********************************/
 
 /* Type definition for PyBobIoFileObject */
-
-namespace bob { namespace io { namespace base { class File; }}}
 typedef struct {
   PyObject_HEAD
 
@@ -181,28 +81,15 @@ typedef struct {
 
 #define PyBobIoFileIterator_Type_TYPE PyTypeObject
 
-/**************************************
- * File loading and data type peeking *
- **************************************/
-
-#define BobIoFile_Open_RET boost::shared_ptr<bob::io::base::File>
-#define BobIoFile_Open_PROTO (const char*, char)
-
-#define BobIoFile_OpenWithExtension_RET boost::shared_ptr<bob::io::base::File>
-#define BobIoFile_OpenWithExtension_PROTO (const char*, char, const char*)
-
-#define BobIoFile_Peek_RET void
-#define BobIoFile_Peek_PROTO (const char*, BobIoTypeinfo*)
-
-#define BobIoFile_PeekAll_RET void
-#define BobIoFile_PeekAll_PROTO (const char*, BobIoTypeinfo*)
-
 /************************
  * I/O generic bindings *
  ************************/
 
-#define PyBobIo_TypeinfoAsTuple_RET PyObject*
-#define PyBobIo_TypeinfoAsTuple_PROTO (const BobIoTypeinfo& ti)
+#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, PyObject** b)
@@ -211,7 +98,6 @@ typedef struct {
  * HDF5 bindings *
  *****************/
 
-namespace bob { namespace io { namespace base { class HDF5File; }}}
 typedef struct {
   PyObject_HEAD
 
@@ -232,30 +118,8 @@ typedef struct {
  * Code Registration and De-registration *
  *****************************************/
 
-/**
- * @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<bob::io::base::File> (*BobIoFileFactory) (const char* filename, char mode);
-
 #define PyBobIoCodec_Register_RET int
-#define PyBobIoCodec_Register_PROTO (const char* extension, const char* description, BobIoFileFactory factory)
+#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)
@@ -276,52 +140,6 @@ typedef boost::shared_ptr<bob::io::base::File> (*BobIoFileFactory) (const char*
 
   extern int PyBobIo_APIVersion;
 
-  /********************
-   * Type Information *
-   ********************/
-
-  BobIoTypeinfo_Init_RET BobIoTypeinfo_Init BobIoTypeinfo_Init_PROTO;
-
-  BobIoTypeinfo_Copy_RET BobIoTypeinfo_Copy BobIoTypeinfo_Copy_PROTO;
-
-  BobIoTypeinfo_Set_RET BobIoTypeinfo_Set BobIoTypeinfo_Set_PROTO;
-
-  BobIoTypeinfo_SetWithStrides_RET BobIoTypeinfo_SetWithStrides BobIoTypeinfo_SetWithStrides_PROTO;
-
-  BobIoTypeinfo_SignedSet_RET BobIoTypeinfo_SignedSet BobIoTypeinfo_SignedSet_PROTO;
-
-  BobIoTypeinfo_SignedSetWithStrides_RET BobIoTypeinfo_SignedSetWithStrides BobIoTypeinfo_SignedSetWithStrides_PROTO;
-
-  BobIoTypeinfo_Reset_RET BobIoTypeinfo_Reset BobIoTypeinfo_Reset_PROTO;
-
-  BobIoTypeinfo_IsValid_RET BobIoTypeinfo_IsValid BobIoTypeinfo_IsValid_PROTO;
-
-  BobIoTypeinfo_HasValidShape_RET BobIoTypeinfo_HasValidShape BobIoTypeinfo_HasValidShape_PROTO;
-
-  BobIoTypeinfo_ResetShape_RET BobIoTypeinfo_ResetShape BobIoTypeinfo_ResetShape_PROTO;
-
-  BobIoTypeinfo_UpdateStrides_RET BobIoTypeinfo_UpdateStrides BobIoTypeinfo_UpdateStrides_PROTO;
-
-  BobIoTypeinfo_Size_RET BobIoTypeinfo_Size BobIoTypeinfo_Size_PROTO;
-
-  BobIoTypeinfo_BufferSize_RET BobIoTypeinfo_BufferSize BobIoTypeinfo_BufferSize_PROTO;
-
-  BobIoTypeinfo_IsCompatible_RET BobIoTypeinfo_IsCompatible BobIoTypeinfo_IsCompatible_PROTO;
-
-  BobIoTypeinfo_Str_RET BobIoTypeinfo_Str BobIoTypeinfo_Str_PROTO;
-
-  /********************
-   * Array reordering *
-   ********************/
-
-  BobIoReorder_RowToCol_RET BobIoReorder_RowToCol BobIoReorder_RowToCol_PROTO;
-
-  BobIoReorder_ColToRow_RET BobIoReorder_ColToRow BobIoReorder_ColToRow_PROTO;
-
-  BobIoReorder_RowToColComplex_RET BobIoReorder_RowToColComplex BobIoReorder_RowToColComplex_PROTO;
-
-  BobIoReorder_ColToRowComplex_RET BobIoReorder_ColToRowComplex BobIoReorder_ColToRowComplex_PROTO;
-
   /**********************************
    * Bindings for bob.io.base.File *
    **********************************/
@@ -329,29 +147,19 @@ typedef boost::shared_ptr<bob::io::base::File> (*BobIoFileFactory) (const char*
   extern PyBobIoFile_Type_TYPE PyBobIoFile_Type;
   extern PyBobIoFileIterator_Type_TYPE PyBobIoFileIterator_Type;
 
-  /**************************************
-   * File loading and data type peeking *
-   **************************************/
-
-  BobIoFile_Open_RET BobIoFile_Open BobIoFile_Open_PROTO;
-
-  BobIoFile_OpenWithExtension_RET BobIoFile_OpenWithExtension BobIoFile_OpenWithExtension_PROTO;
-
-  BobIoFile_Peek_RET BobIoFile_Peek BobIoFile_Peek_PROTO;
-
-  BobIoFile_PeekAll_RET BobIoFile_PeekAll BobIoFile_PeekAll_PROTO;
-
   /************************
    * I/O generic bindings *
    ************************/
 
-  PyBobIo_TypeinfoAsTuple_RET PyBobIo_TypeinfoAsTuple PyBobIo_TypeinfoAsTuple_PROTO;
+  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 *
-   *****************/
+/*****************
+ * HDF5 bindings *
+ *****************/
 
   extern PyBobIoHDF5File_Type_TYPE PyBobIoHDF5File_Type;
 
@@ -359,17 +167,17 @@ typedef boost::shared_ptr<bob::io::base::File> (*BobIoFileFactory) (const char*
 
   PyBobIoHDF5File_Converter_RET PyBobIoHDF5File_Converter PyBobIoHDF5File_Converter_PROTO;
 
-  /*****************************************
-   * Code Registration and De-registration *
-   *****************************************/
+/*****************************************
+ * Code Registration and De-registration *
+ *****************************************/
 
-  PyBobIoCodec_Register_RET PyBobIoCodec_Register PyBobIoCodec_Register_PROTO;
+ PyBobIoCodec_Register_RET PyBobIoCodec_Register PyBobIoCodec_Register_PROTO;
 
-  PyBobIoCodec_Deregister_RET PyBobIoCodec_Deregister PyBobIoCodec_Deregister_PROTO;
+ PyBobIoCodec_Deregister_RET PyBobIoCodec_Deregister PyBobIoCodec_Deregister_PROTO;
 
-  PyBobIoCodec_IsRegistered_RET PyBobIoCodec_IsRegistered PyBobIoCodec_IsRegistered_PROTO;
+ PyBobIoCodec_IsRegistered_RET PyBobIoCodec_IsRegistered PyBobIoCodec_IsRegistered_PROTO;
 
-  PyBobIoCodec_GetDescription_RET PyBobIoCodec_GetDescription PyBobIoCodec_GetDescription_PROTO;
+ PyBobIoCodec_GetDescription_RET PyBobIoCodec_GetDescription PyBobIoCodec_GetDescription_PROTO;
 
 #else
 
@@ -391,52 +199,6 @@ typedef boost::shared_ptr<bob::io::base::File> (*BobIoFileFactory) (const char*
 
 # define PyBobIo_APIVersion (*(PyBobIo_APIVersion_TYPE *)PyBobIo_API[PyBobIo_APIVersion_NUM])
 
-  /********************
-   * Type Information *
-   ********************/
-
-# define BobIoTypeinfo_Init (*(BobIoTypeinfo_Init_RET (*)BobIoTypeinfo_Init_PROTO) PyBobIo_API[BobIoTypeinfo_Init_NUM])
-
-# define BobIoTypeinfo_Copy (*(BobIoTypeinfo_Copy_RET (*)BobIoTypeinfo_Copy_PROTO) PyBobIo_API[BobIoTypeinfo_Copy_NUM])
-
-# define BobIoTypeinfo_Set (*(BobIoTypeinfo_Set_RET (*)BobIoTypeinfo_Set_PROTO) PyBobIo_API[BobIoTypeinfo_Set_NUM])
-
-# define BobIoTypeinfo_SetWithStrides (*(BobIoTypeinfo_SetWithStrides_RET (*)BobIoTypeinfo_SetWithStrides_PROTO) PyBobIo_API[BobIoTypeinfo_SetWithStrides_NUM])
-
-# define BobIoTypeinfo_SignedSet (*(BobIoTypeinfo_SignedSet_RET (*)BobIoTypeinfo_SignedSet_PROTO) PyBobIo_API[BobIoTypeinfo_SignedSet_NUM])
-
-# define BobIoTypeinfo_SignedSetWithStrides (*(BobIoTypeinfo_SignedSetWithStrides_RET (*)BobIoTypeinfo_SignedSetWithStrides_PROTO) PyBobIo_API[BobIoTypeinfo_SignedSetWithStrides_NUM])
-
-# define BobIoTypeinfo_Reset (*(BobIoTypeinfo_Reset_RET (*)BobIoTypeinfo_Reset_PROTO) PyBobIo_API[BobIoTypeinfo_Reset_NUM])
-
-# define BobIoTypeinfo_IsValid (*(BobIoTypeinfo_IsValid_RET (*)BobIoTypeinfo_IsValid_PROTO) PyBobIo_API[BobIoTypeinfo_IsValid_NUM])
-
-# define BobIoTypeinfo_HasValidShape (*(BobIoTypeinfo_HasValidShape_RET (*)BobIoTypeinfo_HasValidShape_PROTO) PyBobIo_API[BobIoTypeinfo_HasValidShape_NUM])
-
-# define BobIoTypeinfo_ResetShape (*(BobIoTypeinfo_ResetShape_RET (*)BobIoTypeinfo_ResetShape_PROTO) PyBobIo_API[BobIoTypeinfo_ResetShape_NUM])
-
-# define BobIoTypeinfo_UpdateStrides (*(BobIoTypeinfo_UpdateStrides_RET (*)BobIoTypeinfo_UpdateStrides_PROTO) PyBobIo_API[BobIoTypeinfo_UpdateStrides_NUM])
-
-# define BobIoTypeinfo_Size (*(BobIoTypeinfo_Size_RET (*)BobIoTypeinfo_Size_PROTO) PyBobIo_API[BobIoTypeinfo_Size_NUM])
-
-# define BobIoTypeinfo_BufferSize (*(BobIoTypeinfo_BufferSize_RET (*)BobIoTypeinfo_BufferSize_PROTO) PyBobIo_API[BobIoTypeinfo_BufferSize_NUM])
-
-# define BobIoTypeinfo_IsCompatible (*(BobIoTypeinfo_IsCompatible_RET (*)BobIoTypeinfo_IsCompatible_PROTO) PyBobIo_API[BobIoTypeinfo_IsCompatible_NUM])
-
-# define BobIoTypeinfo_Str (*(BobIoTypeinfo_Str_RET (*)BobIoTypeinfo_Str_PROTO) PyBobIo_API[BobIoTypeinfo_Str_NUM])
-
-  /********************
-   * Array reordering *
-   ********************/
-
-# define BobIoReorder_RowToCol (*(BobIoReorder_RowToCol_RET (*)BobIoReorder_RowToCol_PROTO) PyBobIo_API[BobIoReorder_RowToCol_NUM])
-
-# define BobIoReorder_ColToRow (*(BobIoReorder_ColToRow_RET (*)BobIoReorder_ColToRow_PROTO) PyBobIo_API[BobIoReorder_ColToRow_NUM])
-
-# define BobIoReorder_RowToColComplex (*(BobIoReorder_RowToColComplex_RET (*)BobIoReorder_RowToColComplex_PROTO) PyBobIo_API[BobIoReorder_RowToColComplex_NUM])
-
-# define BobIoReorder_ColToRowComplex (*(BobIoReorder_ColToRowComplex_RET (*)BobIoReorder_ColToRowComplex_PROTO) PyBobIo_API[BobIoReorder_ColToRowComplex_NUM])
-
   /*****************************
    * Bindings for bob.io.File *
    *****************************/
@@ -444,23 +206,13 @@ typedef boost::shared_ptr<bob::io::base::File> (*BobIoFileFactory) (const char*
 # define PyBobIoFile_Type (*(PyBobIoFile_Type_TYPE *)PyBobIo_API[PyBobIoFile_Type_NUM])
 # define PyBobIoFileIterator_Type (*(PyBobIoFileIterator_Type_TYPE *)PyBobIo_API[PyBobIoFileIterator_Type_NUM])
 
-  /**************************************
-   * File loading and data type peeking *
-   **************************************/
-
-# define BobIoFile_Open (*(BobIoFile_Open_RET (*)BobIoFile_Open_PROTO) PyBobIo_API[BobIoFile_Open_NUM])
-
-# define BobIoFile_OpenWithExtension (*(BobIoFile_OpenWithExtension_RET (*)BobIoFile_OpenWithExtension_PROTO) PyBobIo_API[BobIoFile_OpenWithExtension_NUM])
-
-# define BobIoFile_Peek (*(BobIoFile_Peek_RET (*)BobIoFile_Peek_PROTO) PyBobIo_API[BobIoFile_Peek_NUM])
-
-# define BobIoFile_PeekAll (*(BobIoFile_PeekAll_RET (*)BobIoFile_PeekAll_PROTO) PyBobIo_API[BobIoFile_PeekAll_NUM])
-
   /************************
    * I/O generic bindings *
    ************************/
 
-# define PyBobIo_TypeinfoAsTuple (*(PyBobIo_TypeinfoAsTuple_RET (*)PyBobIo_TypeinfoAsTuple_PROTO) PyBobIo_API[PyBobIo_TypeinfoAsTuple_NUM])
+# 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])
 
diff --git a/bob/io/base/include/bob.io.base/array.h b/bob/io/base/include/bob.io.base/array.h
index 5bbe268ba99c056b9a985887c3bc585593de8045..570c09f05f52fc115cc659f207c1137e080acce0 100644
--- a/bob/io/base/include/bob.io.base/array.h
+++ b/bob/io/base/include/bob.io.base/array.h
@@ -11,15 +11,14 @@
 #ifndef BOB_IO_BASE_ARRAY_INTERFACE_H
 #define BOB_IO_BASE_ARRAY_INTERFACE_H
 
-#include <bob.blitz/cppapi.h>
-#include <bob.io.base/api.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
@@ -30,6 +29,170 @@
  */
 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
@@ -62,12 +225,12 @@ namespace bob { namespace io { namespace base { namespace array {
        * @brief Re-allocates this interface taking into consideration new
        * requirements. The internal memory should be considered uninitialized.
        */
-      virtual void set (const BobIoTypeinfo& req) =0;
+      virtual void set (const typeinfo& req) =0;
 
       /**
        * @brief Type information for this interface.
        */
-      virtual const BobIoTypeinfo& type() const =0;
+      virtual const typeinfo& type() const =0;
 
       /**
        * @brief Borrows a reference from the underlying memory. This means
diff --git a/bob/io/base/include/bob.io.base/array_type.h b/bob/io/base/include/bob.io.base/array_type.h
new file mode 100644
index 0000000000000000000000000000000000000000..89eb1e26df2000beb040f2dc47aced0429029f6e
--- /dev/null
+++ b/bob/io/base/include/bob.io.base/array_type.h
@@ -0,0 +1,162 @@
+/**
+ * @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
index 2ccf320af9fc5aa0657bf18003adbb969c6f8b07..8fdfa77b4d6a1bb181031152255ab4a5fd685153 100644
--- a/bob/io/base/include/bob.io.base/array_utils.h
+++ b/bob/io/base/include/bob.io.base/array_utils.h
@@ -22,9 +22,9 @@
 namespace bob { namespace io { namespace base { namespace array {
 
   /**
-   * @brief Fills in shape and stride starting from a type information object
+   * @brief Fills in shape and stride starting from a typeinfo object
    */
-  template <int N> void set_shape_and_stride(const BobIoTypeinfo& info,
+  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];
@@ -43,19 +43,19 @@ namespace bob { namespace io { namespace base { namespace array {
   template <typename T, int N>
     blitz::Array<T,N> wrap(const interface& buf) {
 
-      const BobIoTypeinfo& type = buf.type();
+      const typeinfo& type = buf.type();
 
       if (!buf.ptr()) throw std::runtime_error("empty buffer");
 
-      if (type.dtype != PyBlitzArrayCxx_CToTypenum<T>()) {
+      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 % PyBlitzArray_TypenumAsString(PyBlitzArrayCxx_CToTypenum<T>()) % N % BobIoTypeinfo_Str(&type);
+        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 % PyBlitzArray_TypenumAsString(PyBlitzArrayCxx_CToTypenum<T>()) % N % BobIoTypeinfo_Str(&type);
+        m % stringize<T>() % N % type.str();
         throw std::runtime_error(m.str());
       }
 
@@ -80,49 +80,45 @@ namespace bob { namespace io { namespace base { namespace array {
   template <typename T, int N>
     blitz::Array<T,N> cast(const interface& buf) {
 
-      const BobIoTypeinfo& type = buf.type();
+      const typeinfo& type = buf.type();
 
       if (type.nd != N) {
         boost::format m("cannot cast blitz::Array<%s,%d> from buffer of type '%s'");
-        m % PyBlitzArray_TypenumAsString(PyBlitzArrayCxx_CToTypenum<T>()) % N % BobIoTypeinfo_Str(&type);
+        m % stringize<T>() % N % type.str();
         throw std::runtime_error(m.str());
       }
 
       switch (type.dtype) {
-        case NPY_BOOL:
+        case bob::io::base::array::t_bool:
           return bob::core::array::cast<T>(wrap<bool,N>(buf));
-        case NPY_INT8:
+        case bob::io::base::array::t_int8:
           return bob::core::array::cast<T>(wrap<int8_t,N>(buf));
-        case NPY_INT16:
+        case bob::io::base::array::t_int16:
           return bob::core::array::cast<T>(wrap<int16_t,N>(buf));
-        case NPY_INT32:
+        case bob::io::base::array::t_int32:
           return bob::core::array::cast<T>(wrap<int32_t,N>(buf));
-        case NPY_INT64:
+        case bob::io::base::array::t_int64:
           return bob::core::array::cast<T>(wrap<int64_t,N>(buf));
-        case NPY_UINT8:
+        case bob::io::base::array::t_uint8:
           return bob::core::array::cast<T>(wrap<uint8_t,N>(buf));
-        case NPY_UINT16:
+        case bob::io::base::array::t_uint16:
           return bob::core::array::cast<T>(wrap<uint16_t,N>(buf));
-        case NPY_UINT32:
+        case bob::io::base::array::t_uint32:
           return bob::core::array::cast<T>(wrap<uint32_t,N>(buf));
-        case NPY_UINT64:
+        case bob::io::base::array::t_uint64:
           return bob::core::array::cast<T>(wrap<uint64_t,N>(buf));
-        case NPY_FLOAT32:
+        case bob::io::base::array::t_float32:
           return bob::core::array::cast<T>(wrap<float,N>(buf));
-        case NPY_FLOAT64:
+        case bob::io::base::array::t_float64:
           return bob::core::array::cast<T>(wrap<double,N>(buf));
-#       ifdef NPY_FLOAT128
-        case NPY_FLOAT128:
+        case bob::io::base::array::t_float128:
           return bob::core::array::cast<T>(wrap<long double,N>(buf));
-#       endif
-        case NPY_COMPLEX64:
+        case bob::io::base::array::t_complex64:
           return bob::core::array::cast<T>(wrap<std::complex<float>,N>(buf));
-        case NPY_COMPLEX128:
+        case bob::io::base::array::t_complex128:
           return bob::core::array::cast<T>(wrap<std::complex<double>,N>(buf));
-#       ifdef NPY_COMPLEX256
-        case NPY_COMPLEX256:
+        case bob::io::base::array::t_complex256:
           return bob::core::array::cast<T>(wrap<std::complex<long double>,N>(buf));
-#       endif
         default:
           break;
       }
diff --git a/bob/io/base/include/bob.io.base/blitz_array.h b/bob/io/base/include/bob.io.base/blitz_array.h
index f7841569c9750733c343c855698e837992fce2bf..9927e0040e8f56f94ecf400327d8ff1648de3ef8 100644
--- a/bob/io/base/include/bob.io.base/blitz_array.h
+++ b/bob/io/base/include/bob.io.base/blitz_array.h
@@ -11,17 +11,18 @@
 #ifndef BOB_IO_BASE_BLITZ_ARRAY_H
 #define BOB_IO_BASE_BLITZ_ARRAY_H
 
-#include <bob.io.base/array.h>
-#include <bob.io.base/array_utils.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 <stdexcept>
-#include <boost/make_shared.hpp>
-#include <boost/format.hpp>
-#include <blitz/array.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 {
 
@@ -55,13 +56,13 @@ namespace bob { namespace io { namespace base { namespace array {
       /**
        * @brief Starts with an uninitialized, pre-allocated array.
        */
-      blitz_array(const BobIoTypeinfo& info);
+      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 BobIoTypeinfo& info);
+      blitz_array(void* data, const typeinfo& info);
 
       /**
        * @brief Destroyes me
@@ -82,7 +83,7 @@ namespace bob { namespace io { namespace base { namespace array {
        * @brief Re-allocates this buffer taking into consideration new
        * requirements. The internal memory should be considered uninitialized.
        */
-      virtual void set (const BobIoTypeinfo& req);
+      virtual void set (const typeinfo& req);
 
       /**
        * @brief Refers to the data of another blitz array.
@@ -90,9 +91,9 @@ namespace bob { namespace io { namespace base { namespace array {
       void set(boost::shared_ptr<blitz_array> other);
 
       /**
-       * @brief type information
+       * @brief Element type
        */
-      virtual const BobIoTypeinfo& type() const { return m_type; }
+      virtual const typeinfo& type() const { return m_type; }
 
       /**
        * @brief Borrows a reference from the underlying memory. This means
@@ -151,20 +152,16 @@ namespace bob { namespace io { namespace base { namespace array {
       template <typename T, int N>
         void set(boost::shared_ptr<blitz::Array<T,N> > data) {
 
-          if (PyBlitzArrayCxx_CToTypenum<T>() == NPY_NOTYPE)
+          if (getElementType<T>() == t_unknown)
             throw std::runtime_error("unsupported element type on blitz::Array<>");
-          if (N > BOB_BLITZ_MAXDIMS)
+          if (N > BOB_MAX_DIM)
             throw std::runtime_error("unsupported number of dimensions on blitz::Array<>");
 
           if (!isCContiguous(*data.get()))
             throw std::runtime_error("cannot buffer'ize non-c contiguous array");
 
-          m_type.dtype = PyBlitzArrayCxx_CToTypenum<T>();
-          m_type.nd = data->ndim();
-          for (size_t k=0; k<m_type.nd; ++k) {
-            m_type.shape[k] = data->shape(k);
-            m_type.stride[k] = data->stride(k);
-          }
+          m_type.set(data);
+
           m_data = data;
           m_ptr = reinterpret_cast<void*>(data->data());
           m_is_blitz = true;
@@ -212,15 +209,15 @@ namespace bob { namespace io { namespace base { namespace array {
 
           if (!m_data) throw std::runtime_error("empty blitz array");
 
-          if (m_type.dtype != PyBlitzArrayCxx_CToTypenum<T>()) {
+          if (m_type.dtype != getElementType<T>()) {
             boost::format m("cannot efficiently retrieve blitz::Array<%s,%d> from buffer of type '%s'");
-            m % PyBlitzArray_TypenumAsString(PyBlitzArrayCxx_CToTypenum<T>()) % N % BobIoTypeinfo_Str(&m_type);
+            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 % PyBlitzArray_TypenumAsString(PyBlitzArrayCxx_CToTypenum<T>()) % N % BobIoTypeinfo_Str(&m_type);
+            m % stringize<T>() % N % m_type.str();
             throw std::runtime_error(m.str());
           }
 
@@ -252,7 +249,7 @@ namespace bob { namespace io { namespace base { namespace array {
 
     private: //representation
 
-      BobIoTypeinfo m_type; ///< type information
+      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
diff --git a/bob/io/base/include/bob.io.base/reorder.h b/bob/io/base/include/bob.io.base/reorder.h
new file mode 100644
index 0000000000000000000000000000000000000000..09ebf50422392cb6da05b255c4d9738f5d71d445
--- /dev/null
+++ b/bob/io/base/include/bob.io.base/reorder.h
@@ -0,0 +1,94 @@
+/**
+ * @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
new file mode 100644
index 0000000000000000000000000000000000000000..c42b1fac659dca6956dd241916aeeb2670c134c8
--- /dev/null
+++ b/bob/io/base/include/bob.io.base/utils.h
@@ -0,0 +1,105 @@
+/**
+ * @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
index 50eaabd47231af8f3f593c7bd28dbc2eaa30174e..f7dfb87c59465b2d49985e641f6a765e16d22e61 100644
--- a/bob/io/base/main.cpp
+++ b/bob/io/base/main.cpp
@@ -13,10 +13,6 @@
 #endif
 #include <bob.blitz/capi.h>
 #include <bob.blitz/cleanup.h>
-#include <bob.core/logging.h>
-
-#include "cpp/CodecRegistry.h"
-#include "plugin.h"
 
 /**
  * Creates an str object, from a C or C++ string. Returns a **new
@@ -124,52 +120,6 @@ static PyObject* create_module (void) {
 
   PyBobIo_API[PyBobIo_APIVersion_NUM] = (void *)&PyBobIo_APIVersion;
 
-  /********************
-   * Type Information *
-   ********************/
-
-  PyBobIo_API[BobIoTypeinfo_Init_NUM] = (void *)&BobIoTypeinfo_Init;
-
-  PyBobIo_API[BobIoTypeinfo_Copy_NUM] = (void *)&BobIoTypeinfo_Copy;
-
-  PyBobIo_API[BobIoTypeinfo_Set_NUM] = (void *)&BobIoTypeinfo_Set;
-
-  PyBobIo_API[BobIoTypeinfo_SetWithStrides_NUM] = (void *)&BobIoTypeinfo_SetWithStrides;
-
-  PyBobIo_API[BobIoTypeinfo_SignedSet_NUM] = (void *)&BobIoTypeinfo_SignedSet;
-
-  PyBobIo_API[BobIoTypeinfo_SignedSetWithStrides_NUM] = (void *)&BobIoTypeinfo_SignedSetWithStrides;
-
-  PyBobIo_API[BobIoTypeinfo_Reset_NUM] = (void *)&BobIoTypeinfo_Reset;
-
-  PyBobIo_API[BobIoTypeinfo_IsValid_NUM] = (void *)&BobIoTypeinfo_IsValid;
-
-  PyBobIo_API[BobIoTypeinfo_HasValidShape_NUM] = (void *)&BobIoTypeinfo_HasValidShape;
-
-  PyBobIo_API[BobIoTypeinfo_ResetShape_NUM] = (void *)&BobIoTypeinfo_ResetShape;
-
-  PyBobIo_API[BobIoTypeinfo_UpdateStrides_NUM] = (void *)&BobIoTypeinfo_UpdateStrides;
-
-  PyBobIo_API[BobIoTypeinfo_Size_NUM] = (void *)&BobIoTypeinfo_Size;
-
-  PyBobIo_API[BobIoTypeinfo_BufferSize_NUM] = (void *)&BobIoTypeinfo_BufferSize;
-
-  PyBobIo_API[BobIoTypeinfo_IsCompatible_NUM] = (void *)&BobIoTypeinfo_IsCompatible;
-
-  PyBobIo_API[BobIoTypeinfo_Str_NUM] = (void *)&BobIoTypeinfo_Str;
-
-  /********************
-   * Array reordering *
-   ********************/
-
-  PyBobIo_API[BobIoReorder_RowToCol_NUM] = (void *)&BobIoReorder_RowToCol;
-
-  PyBobIo_API[BobIoReorder_ColToRow_NUM] = (void *)&BobIoReorder_ColToRow;
-
-  PyBobIo_API[BobIoReorder_RowToColComplex_NUM] = (void *)&BobIoReorder_RowToColComplex;
-
-  PyBobIo_API[BobIoReorder_ColToRowComplex_NUM] = (void *)&BobIoReorder_ColToRowComplex;
-
   /**********************************
    * Bindings for bob.io.base.File *
    **********************************/
@@ -178,23 +128,13 @@ static PyObject* create_module (void) {
 
   PyBobIo_API[PyBobIoFileIterator_Type_NUM] = (void *)&PyBobIoFileIterator_Type;
 
-  /**************************************
-   * File loading and data type peeking *
-   **************************************/
-
-  PyBobIo_API[BobIoFile_Open_NUM] = (void *)&BobIoFile_Open;
-
-  PyBobIo_API[BobIoFile_OpenWithExtension_NUM] = (void *)&BobIoFile_OpenWithExtension;
-
-  PyBobIo_API[BobIoFile_Peek_NUM] = (void *)&BobIoFile_Peek;
-
-  PyBobIo_API[BobIoFile_PeekAll_NUM] = (void *)&BobIoFile_PeekAll;
-
   /************************
    * I/O generic bindings *
    ************************/
 
-  PyBobIo_API[PyBobIo_TypeinfoAsTuple_NUM] = (void *)PyBobIo_TypeinfoAsTuple;
+  PyBobIo_API[PyBobIo_AsTypenum_NUM] = (void *)PyBobIo_AsTypenum;
+
+  PyBobIo_API[PyBobIo_TypeInfoAsTuple_NUM] = (void *)PyBobIo_TypeInfoAsTuple;
 
   PyBobIo_API[PyBobIo_FilenameConverter_NUM] = (void *)PyBobIo_FilenameConverter;
 
@@ -208,9 +148,9 @@ static PyObject* create_module (void) {
 
   PyBobIo_API[PyBobIoHDF5File_Converter_NUM] = (void *)&PyBobIoHDF5File_Converter;
 
-  /*****************************************
-   * Code Registration and De-registration *
-   *****************************************/
+/*****************************************
+ * Code Registration and De-registration *
+ *****************************************/
 
   PyBobIo_API[PyBobIoCodec_Register_NUM] = (void *)&PyBobIoCodec_Register;
 
@@ -237,13 +177,6 @@ static PyObject* create_module (void) {
 
   if (PyModule_AddObject(m, "_C_API", c_api_object) < 0) return 0;
 
-  /* imports dependencies */
-  if (import_bob_core_logging() < 0) {
-    PyErr_Print();
-    PyErr_Format(PyExc_ImportError, "cannot import `%s'", BOB_EXT_MODULE_NAME);
-    return 0;
-  }
-
   /* imports dependencies */
   if (import_bob_blitz() < 0) {
     PyErr_Print();
@@ -251,41 +184,6 @@ static PyObject* create_module (void) {
     return 0;
   }
 
-  /* activates built-in plugins */
-  if (!PyBobIoCodec_Register(".csv", "Comma-Separated Values (built-in)",
-        &make_csv_file)) {
-    PyErr_Print();
-  }
-
-  if (!PyBobIoCodec_Register(".txt", "Comma-Separated Values (built-in)",
-        &make_csv_file)) {
-    PyErr_Print();
-  }
-
-  if (!PyBobIoCodec_Register(".h5", "Hierarchical Data Format v5 (libhdf5)",
-        &make_hdf5_file)) {
-    PyErr_Print();
-  }
-
-  if (!PyBobIoCodec_Register(".hdf5", "Hierarchical Data Format v5 (libhdf5)",
-        &make_hdf5_file)) {
-    PyErr_Print();
-  }
-
-  if (!PyBobIoCodec_Register(".hdf", "Hierarchical Data Format v5 (libhdf5)",
-        &make_hdf5_file)) {
-    PyErr_Print();
-  }
-
-  if (!PyBobIoCodec_Register(".bindata", "Torch3 binary data format (built-in)",
-        &make_torch3_file)) {
-    PyErr_Print();
-  }
-
-  if (!PyBobIoCodec_Register(".tensor", "Torch3vision v2.1 tensor format (built-in)", &make_tensor_file)) {
-    PyErr_Print();
-  }
-
   Py_INCREF(m);
   return m;
 
diff --git a/bob/io/base/plugin.h b/bob/io/base/plugin.h
deleted file mode 100644
index 735ff3761e22cb14e942489ecdfeacfc9778dd1c..0000000000000000000000000000000000000000
--- a/bob/io/base/plugin.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * @author Andre Anjos <andre.anjos@idiap.ch>
- * @date Wed 14 May 14:42:34 2014 CEST
- *
- * @brief Implements the matlab (.mat) array codec using matio
- *
- * Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland
- */
-
-#ifndef BOB_IO_BASE_PLUGIN_H
-#define BOB_IO_BASE_PLUGIN_H
-
-#include <boost/shared_ptr.hpp>
-#include <bob.io.base/File.h>
-
-/**
- * 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.
- */
-boost::shared_ptr<bob::io::base::File> make_csv_file (const char* path, char mode);
-boost::shared_ptr<bob::io::base::File> make_hdf5_file (const char* path, char mode);
-boost::shared_ptr<bob::io::base::File> make_torch3_file (const char* path, char mode);
-boost::shared_ptr<bob::io::base::File> make_tensor_file (const char* path, char mode);
-
-#endif /* BOB_IO_BASE_PLUGIN_H */
diff --git a/bob/io/base/reorder.cpp b/bob/io/base/reorder.cpp
deleted file mode 100644
index b07ac50d60fc1fef210e0cf5d8c39c5588ab6f3e..0000000000000000000000000000000000000000
--- a/bob/io/base/reorder.cpp
+++ /dev/null
@@ -1,317 +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
- */
-
-#define BOB_IO_BASE_MODULE
-#include <bob.io.base/api.h>
-#include <bob.blitz/capi.h>
-#include <cstring> //for memcpy
-
-/**
- * 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
- */
-static void 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;
-
-}
-
-/**
- * Same as above, but for a 3D array organized as [depth][column][row]
- */
-static void 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;
-
-}
-
-/**
- * Same as above, but for a 4D array organized as [time][depth][column][row]
- */
-static 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) {
-
-  row = ( ( i * shape[1] + j ) * shape[2] + k ) * shape[3] + l;
-  col = ( ( l * shape[2] + k ) * shape[1] + j ) * shape[0] + i;
-
-}
-
-int BobIoReorder_RowToCol(const void* src_, void* dst_,
-    const BobIoTypeinfo* info) {
-
-  size_t dsize = PyBlitzArray_TypenumSize(info->dtype);
-
-  //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, BobIoTypeinfo_BufferSize(info));
-      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;
-          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;
-            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;
-              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:
-      PyErr_Format(PyExc_RuntimeError, "can only flip arrays with up to %u dimensions - you passed one with %zu dimensions", BOB_BLITZ_MAXDIMS, info->nd);
-      return 0;
-  }
-
-  return 1;
-}
-
-int BobIoReorder_ColToRow(const void* src_, void* dst_,
-    const BobIoTypeinfo* info) {
-
-  size_t dsize = PyBlitzArray_TypenumSize(info->dtype);
-
-  //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, BobIoTypeinfo_BufferSize(info));
-      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;
-          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;
-            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;
-              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:
-      PyErr_Format(PyExc_RuntimeError, "can only flip arrays with up to %u dimensions - you passed one with %zu dimensions", BOB_BLITZ_MAXDIMS, info->nd);
-      return 0;
-  }
-
-  return 1;
-}
-
-int BobIoReorder_RowToColComplex(const void* src_, void* dst_re_,
-    void* dst_im_, const BobIoTypeinfo* info) {
-
-  size_t dsize = PyBlitzArray_TypenumSize(info->dtype);
-  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;
-          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;
-            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;
-              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:
-      PyErr_Format(PyExc_RuntimeError, "can only flip arrays with up to %u dimensions - you passed one with %zu dimensions", BOB_BLITZ_MAXDIMS, info->nd);
-      return 0;
-  }
-
-  return 1;
-}
-
-int BobIoReorder_ColToRowComplex(const void* src_re_,
-    const void* src_im_, void* dst_, const BobIoTypeinfo* info) {
-
-  size_t dsize = PyBlitzArray_TypenumSize(info->dtype);
-  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;
-          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;
-            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;
-              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:
-      PyErr_Format(PyExc_RuntimeError, "can only flip arrays with up to %u dimensions - you passed one with %zu dimensions", BOB_BLITZ_MAXDIMS, info->nd);
-      return 0;
-  }
-
-  return 1;
-}
diff --git a/bob/io/base/typeinfo.cpp b/bob/io/base/typeinfo.cpp
deleted file mode 100644
index 386843fe3a66d9dd282fff63284351bad6f345a2..0000000000000000000000000000000000000000
--- a/bob/io/base/typeinfo.cpp
+++ /dev/null
@@ -1,251 +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
- */
-
-#define BOB_IO_BASE_MODULE
-#include <bob.blitz/capi.h>
-#include <bob.io.base/api.h>
-#include <boost/format.hpp>
-
-void BobIoTypeinfo_Init(BobIoTypeinfo* self) {
-  BobIoTypeinfo_Reset(self);
-}
-
-int BobIoTypeinfo_Copy (BobIoTypeinfo* self, const BobIoTypeinfo* other) {
-
-  self->dtype = other->dtype;
-
-  if (other->nd > (BOB_BLITZ_MAXDIMS+1)) {
-    PyErr_Format(PyExc_RuntimeError, "unsupported number of dimensions (%" PY_FORMAT_SIZE_T "d) while the maximum is %d", other->nd, BOB_BLITZ_MAXDIMS);
-    return 0;
-  }
-
-  self->nd = other->nd;
-  for (size_t k=0; k<self->nd; ++k) self->shape[k] = other->shape[k];
-
-  return BobIoTypeinfo_UpdateStrides(self);
-
-}
-
-int BobIoTypeinfo_Set (BobIoTypeinfo* self, int dtype, size_t nd,
-    const size_t* shape) {
-
-  self->dtype = dtype;
-
-  if (nd > (BOB_BLITZ_MAXDIMS+1)) {
-    PyErr_Format(PyExc_RuntimeError, "unsupported number of dimensions (%" PY_FORMAT_SIZE_T "d) while the maximum is %d", nd, BOB_BLITZ_MAXDIMS);
-    return 0;
-  }
-
-  self->nd = nd;
-  for (size_t k=0; k<nd; ++k) self->shape[k] = shape[k];
-
-  return BobIoTypeinfo_UpdateStrides(self);
-
-}
-
-int BobIoTypeinfo_SignedSet (BobIoTypeinfo* self, int dtype, Py_ssize_t nd,
-    const Py_ssize_t* shape) {
-
-  self->dtype = dtype;
-
-  if (nd > (BOB_BLITZ_MAXDIMS+1)) {
-    PyErr_Format(PyExc_RuntimeError, "unsupported number of dimensions (%" PY_FORMAT_SIZE_T "d) while the maximum is %d", nd, BOB_BLITZ_MAXDIMS);
-    return 0;
-  }
-
-  self->nd = nd;
-  for (Py_ssize_t k=0; k<nd; ++k) self->shape[k] = shape[k];
-
-  return BobIoTypeinfo_UpdateStrides(self);
-
-}
-
-int BobIoTypeinfo_SetWithStrides (BobIoTypeinfo* self, int dtype,
-    size_t nd, const size_t* shape, const size_t* stride) {
-  self->dtype = dtype;
-
-  if (nd > (BOB_BLITZ_MAXDIMS+1)) {
-    PyErr_Format(PyExc_RuntimeError, "unsupported number of dimensions (%" PY_FORMAT_SIZE_T "d) while the maximum is %d", nd, BOB_BLITZ_MAXDIMS);
-    return 0;
-  }
-
-  self->nd = nd;
-  for (Py_ssize_t k=0; k<nd; ++k) {
-    self->shape[k] = shape[k];
-    self->stride[k] = stride[k];
-  }
-
-  return 1;
-
-}
-
-int BobIoTypeinfo_SignedSetWithStrides (BobIoTypeinfo* self, int dtype,
-    Py_ssize_t nd, const Py_ssize_t* shape, const Py_ssize_t* stride) {
-  self->dtype = dtype;
-
-  if (nd > (BOB_BLITZ_MAXDIMS+1)) {
-    PyErr_Format(PyExc_RuntimeError, "unsupported number of dimensions (%" PY_FORMAT_SIZE_T "d) while the maximum is %d", nd, BOB_BLITZ_MAXDIMS);
-    return 0;
-  }
-
-  self->nd = nd;
-  for (Py_ssize_t k=0; k<nd; ++k) {
-    self->shape[k] = shape[k];
-    self->stride[k] = stride[k];
-  }
-
-  return 1;
-
-}
-
-void BobIoTypeinfo_Reset(BobIoTypeinfo* self) {
-
-  self->dtype = NPY_NOTYPE;
-  self->nd = 0;
-
-}
-
-bool BobIoTypeinfo_IsValid(const BobIoTypeinfo* self) {
-
-  return (self->dtype != NPY_NOTYPE) && (self->nd > 0) && (self->nd <= (BOB_BLITZ_MAXDIMS+1)) && BobIoTypeinfo_HasValidShape(self);
-
-}
-
-int BobIoTypeinfo_UpdateStrides(BobIoTypeinfo* self) {
-
-  auto* stride = self->stride;
-  auto* shape = self->shape;
-
-  switch (self->nd) {
-
-    case 0:
-      return 1;
-
-    case 1:
-      stride[0] = 1;
-      return 1;
-
-    case 2:
-      stride[1] = 1;
-      stride[0] = shape[1];
-      return 1;
-
-    case 3:
-      stride[2] = 1;
-      stride[1] = shape[2];
-      stride[0] = shape[1]*shape[2];
-      return 1;
-
-    case 4:
-      stride[3] = 1;
-      stride[2] = shape[3];
-      stride[1] = shape[2]*shape[3];
-      stride[0] = shape[1]*shape[2]*shape[3];
-      return 1;
-
-    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 1;
-
-    default:
-      break;
-
-  }
-
-  PyErr_Format(PyExc_RuntimeError, "unsupported number of dimensions (%" PY_FORMAT_SIZE_T "d) while the maximum is %d", self->nd, BOB_BLITZ_MAXDIMS);
-  return 0;
-
-}
-
-size_t BobIoTypeinfo_Size(const BobIoTypeinfo* self) {
-
-  size_t retval = 1;
-  for (size_t k=0; k<self->nd; ++k) retval *= self->shape[k];
-  return retval;
-
-}
-
-size_t BobIoTypeinfo_BufferSize(const BobIoTypeinfo* self) {
-
-  return BobIoTypeinfo_Size(self) * PyBlitzArray_TypenumSize(self->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 BobIoTypeinfo_IsCompatible(const BobIoTypeinfo* self,
-    const BobIoTypeinfo* other) {
-
-  return (self->dtype == other->dtype) && (self->nd == other->nd) && same_shape(self->nd, self->shape, other->shape);
-
-}
-
-std::string BobIoTypeinfo_Str(const BobIoTypeinfo* self) {
-
-  boost::format s("dtype: %s (%d); shape: [%s]; size: %d bytes");
-  size_t sz = 0;
-  size_t buf_sz = 0;
-  if (self->dtype != NPY_NOTYPE) {
-    //otherwise it throws
-    sz = PyBlitzArray_TypenumSize(self->dtype);
-    buf_sz = BobIoTypeinfo_BufferSize(self);
-  }
-  s % PyBlitzArray_TypenumAsString(self->dtype) % sz;
-
-  auto* shape = self->shape;
-
-  switch (self->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 BobIoTypeinfo_ResetShape (BobIoTypeinfo* self) {
-  self->shape[0] = 0;
-}
-
-bool BobIoTypeinfo_HasValidShape(const BobIoTypeinfo* self) {
-  return self->shape[0] != 0;
-}
diff --git a/setup.py b/setup.py
index 967e9b5657a2bfe93ba85a7ecc426f09a7232747..d3eac6e1516469f234f98bcff7b8fcf8692bfa41 100644
--- a/setup.py
+++ b/setup.py
@@ -14,6 +14,7 @@ package_dir = os.path.dirname(os.path.realpath(__file__))
 package_dir = os.path.join(package_dir, 'bob', 'io', 'base', 'include')
 include_dirs = [package_dir, bob.core.get_include()]
 
+packages = ['bob-core >= 1.2.2']
 version = '2.0.0a0'
 
 def libhdf5_version(header):
@@ -147,7 +148,6 @@ setup(
     install_requires=[
       'setuptools',
       'bob.blitz',
-      'bob.core',
     ],
 
     namespace_packages=[
@@ -160,46 +160,47 @@ setup(
         [
           "bob/io/base/version.cpp",
           ],
+        packages = packages,
         include_dirs = include_dirs,
         define_macros = define_macros,
         extra_compile_args = extra_compile_args,
         version = version,
-        packages = ['boost'],
         ),
       Extension("bob.io.base._library",
         [
-          "bob/io/base/cpp/blitz_array.cpp",
-          "bob/io/base/cpp/TensorFileHeader.cpp",
-          "bob/io/base/cpp/TensorFile.cpp",
           "bob/io/base/cpp/CodecRegistry.cpp",
+          "bob/io/base/cpp/CSVFile.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/T3File.cpp",
+          "bob/io/base/cpp/TensorArrayFile.cpp",
+          "bob/io/base/cpp/TensorFileHeader.cpp",
+          "bob/io/base/cpp/utils.cpp",
+          "bob/io/base/cpp/TensorFile.cpp",
+          "bob/io/base/cpp/array.cpp",
+          "bob/io/base/cpp/array_type.cpp",
+          "bob/io/base/cpp/blitz_array.cpp",
 
-          "bob/io/base/file.cpp",
-          "bob/io/base/utils.cpp",
-          "bob/io/base/csv.cpp",
-          "bob/io/base/hdf5plugin.cpp",
-          "bob/io/base/torch3.cpp",
-          "bob/io/base/tensor.cpp",
-          "bob/io/base/reorder.cpp",
-          "bob/io/base/typeinfo.cpp",
           "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",
           ],
+        packages = packages,
         include_dirs = include_dirs,
         library_dirs = library_dirs,
         libraries = libraries,
         define_macros = define_macros,
         extra_compile_args = extra_compile_args,
         version = version,
-        packages = ['boost'],
-        boost_modules = ['iostreams', 'filesystem'],
         ),
       ],