diff --git a/bob/io/base/bobskin.cpp b/bob/io/base/bobskin.cpp
index 494bdafc26fe3520f67b7a5f826d8a9982ba3557..12117c18277fe94087da39c0c82644f26a115766 100644
--- a/bob/io/base/bobskin.cpp
+++ b/bob/io/base/bobskin.cpp
@@ -8,126 +8,42 @@
 #include "bobskin.h"
 #include <stdexcept>
 
-bobskin::bobskin(PyObject* array, bob::io::base::array::ElementType eltype) {
+bobskin::bobskin(PyObject* array, int dtype) {
 
   if (!PyArray_CheckExact(array)) {
     PyErr_SetString(PyExc_TypeError, "input object to bobskin constructor is not (exactly) a numpy.ndarray");
     throw std::runtime_error("error is already set");
   }
 
-  m_type.set<npy_intp>(eltype, PyArray_NDIM((PyArrayObject*)array),
-      PyArray_DIMS((PyArrayObject*)array),
-      PyArray_STRIDES((PyArrayObject*)array));
-
-  m_ptr = PyArray_DATA((PyArrayObject*)array);
-
-}
-
-bobskin::bobskin(PyArrayObject* array, bob::io::base::array::ElementType eltype) {
-
-  m_type.set<npy_intp>(eltype, PyArray_NDIM((PyArrayObject*)array),
-      PyArray_DIMS((PyArrayObject*)array),
-      PyArray_STRIDES((PyArrayObject*)array));
+  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_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;
-}
+bobskin::bobskin(PyArrayObject* array, int dtype) {
 
-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);
+  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");
   }
-  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);
-  }
+  m_ptr = PyArray_DATA((PyArrayObject*)array);
 
-  return bob::io::base::array::t_unknown;
 }
 
 bobskin::bobskin(PyBlitzArrayObject* array) {
-  bob::io::base::array::ElementType eltype = num_to_type(array->type_num);
-  if (eltype == bob::io::base::array::t_unknown) {
+  if (!BobIoTypeinfo_SignedSetWithStrides(&m_type, array->type_num,
+        array->ndim, array->shape, array->stride)) {
     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;
 }
 
@@ -143,8 +59,8 @@ void bobskin::set(boost::shared_ptr<interface>) {
   throw std::runtime_error("error is already set");
 }
 
-void bobskin::set (const bob::io::base::array::typeinfo&) {
-  PyErr_SetString(PyExc_NotImplementedError, "setting C++ bobskin with (const typeinfo&) implemented - DEBUG ME!");
+void bobskin::set (const BobIoTypeinfo&) {
+  PyErr_SetString(PyExc_NotImplementedError, "setting C++ bobskin with (const type-information&) 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 7e69132a01e663b86dcd645f8301f8f6e3e33816..a5035627f13c801162230b2e337b8b2530510937 100644
--- a/bob/io/base/bobskin.h
+++ b/bob/io/base/bobskin.h
@@ -10,13 +10,8 @@
 #define PYTHON_BOB_IO_BOBSKIN_H
 
 #include <Python.h>
-
 #include <bob.io.base/array.h>
-
-extern "C" {
-#include <bob.blitz/capi.h>
-}
-
+#include <bob.blitz/cppapi.h>
 
 /**
  * Wraps a PyArrayObject such that we can access it from bob::io
@@ -28,12 +23,12 @@ class bobskin: public bob::io::base::array::interface {
     /**
      * @brief Builds a new skin from an array like object
      */
-    bobskin(PyObject* array, bob::io::base::array::ElementType eltype);
+    bobskin(PyObject* array, int dtype);
 
     /**
      * @brief Builds a new skin from a numpy array object
      */
-    bobskin(PyArrayObject* array, bob::io::base::array::ElementType eltype);
+    bobskin(PyArrayObject* array, int dtype);
 
     /**
      * @brief Builds a new skin around a blitz array object
@@ -60,12 +55,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 bob::io::base::array::typeinfo& req);
+    virtual void set (const BobIoTypeinfo& req);
 
     /**
      * @brief Type information for this interface.
      */
-    virtual const bob::io::base::array::typeinfo& type() const { return m_type; }
+    virtual const BobIoTypeinfo& type() const { return m_type; }
 
     /**
      * @brief Borrows a reference from the underlying memory. This means
@@ -85,7 +80,7 @@ class bobskin: public bob::io::base::array::interface {
 
   private: //representation
 
-    bob::io::base::array::typeinfo m_type; ///< type information
+    BobIoTypeinfo 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 bfc3eb94de0f9b29371f3d4b9c6a85f45837b441..767fd20c31fb3bf7810a3f74c068c72d8f6e54aa 100644
--- a/bob/io/base/codec.cpp
+++ b/bob/io/base/codec.cpp
@@ -7,8 +7,9 @@
 
 #define BOB_IO_BASE_MODULE
 #include <bob.io.base/api.h>
+#include "cpp/CodecRegistry.h"
 
-int PyBobIoCodec_Register (const char* extension, const char* description, bob::io::base::file_factory_t factory) {
+int PyBobIoCodec_Register (const char* extension, const char* description, BobIoFileFactory factory) {
   boost::shared_ptr<bob::io::base::CodecRegistry> instance =
     bob::io::base::CodecRegistry::instance();
 
diff --git a/bob/io/base/cpp/CodecRegistry.cpp b/bob/io/base/cpp/CodecRegistry.cpp
index 821ecce8b94f7fe7ca0d073309322541ac60e7d1..e3ce5fd5cb13bbc7c758650b86c326c0400d852b 100644
--- a/bob/io/base/cpp/CodecRegistry.cpp
+++ b/bob/io/base/cpp/CodecRegistry.cpp
@@ -9,7 +9,7 @@
 
 #include <bob.core/logging.h>
 
-#include <bob.io.base/CodecRegistry.h>
+#include "CodecRegistry.h"
 
 #include <vector>
 
@@ -32,7 +32,7 @@ const char* bob::io::base::CodecRegistry::getDescription(const char* ext) {
   return it->second.c_str();
 }
 
-void bob::io::base::CodecRegistry::deregisterFactory(bob::io::base::file_factory_t factory) {
+void bob::io::base::CodecRegistry::deregisterFactory(BobIoFileFactory factory) {
 
   std::vector<std::string> to_remove;
   for (auto it = s_extension2codec.begin(); it != s_extension2codec.end(); ++it) {
@@ -47,7 +47,7 @@ void bob::io::base::CodecRegistry::deregisterFactory(bob::io::base::file_factory
 }
 
 void bob::io::base::CodecRegistry::registerExtension(const char* extension,
-    const char* description, bob::io::base::file_factory_t codec) {
+    const char* description, BobIoFileFactory codec) {
 
   auto it = s_extension2codec.find(extension);
 
@@ -72,13 +72,13 @@ bool bob::io::base::CodecRegistry::isRegistered(const char* ext) {
   return (s_extension2codec.find(lower_extension) != s_extension2codec.end());
 }
 
-bob::io::base::file_factory_t bob::io::base::CodecRegistry::findByExtension (const char* ext) {
+BobIoFileFactory bob::io::base::CodecRegistry::findByExtension (const char* ext) {
 
   std::string extension(ext);
   std::string lower_extension = extension;
   std::transform(extension.begin(), extension.end(), lower_extension.begin(), ::tolower);
 
-  std::map<std::string, bob::io::base::file_factory_t >::iterator it =
+  std::map<std::string, BobIoFileFactory>::iterator it =
     s_extension2codec.find(lower_extension);
 
   if (it == s_extension2codec.end()) {
@@ -91,7 +91,7 @@ bob::io::base::file_factory_t bob::io::base::CodecRegistry::findByExtension (con
 
 }
 
-bob::io::base::file_factory_t bob::io::base::CodecRegistry::findByFilenameExtension
+BobIoFileFactory bob::io::base::CodecRegistry::findByFilenameExtension
 (const char* filename) {
 
   return findByExtension(boost::filesystem::path(filename).extension().c_str());
diff --git a/bob/io/base/include/bob.io.base/CodecRegistry.h b/bob/io/base/cpp/CodecRegistry.h
similarity index 86%
rename from bob/io/base/include/bob.io.base/CodecRegistry.h
rename to bob/io/base/cpp/CodecRegistry.h
index 019bb5770959199f2a27c6df1594770c65dcf1f6..aa9501ef47191e28fe451dda3ff7a56c9c583be0 100644
--- a/bob/io/base/include/bob.io.base/CodecRegistry.h
+++ b/bob/io/base/cpp/CodecRegistry.h
@@ -14,7 +14,7 @@
 #include <string>
 #include <boost/shared_ptr.hpp>
 
-#include <bob.io.base/File.h>
+#include <bob.io.base/api.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,
-          file_factory_t factory);
+          BobIoFileFactory factory);
 
-      void deregisterFactory(file_factory_t factory);
+      void deregisterFactory(BobIoFileFactory factory);
       void deregisterExtension(const char* ext);
 
       /**
@@ -58,8 +58,8 @@ namespace bob { namespace io { namespace base {
        */
       const char* getDescription(const char* ext);
 
-      file_factory_t findByExtension(const char* ext);
-      file_factory_t findByFilenameExtension(const char* fn);
+      BobIoFileFactory findByExtension(const char* ext);
+      BobIoFileFactory 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, file_factory_t> s_extension2codec;
+      std::map<std::string, BobIoFileFactory> s_extension2codec;
       std::map<std::string, std::string> s_extension2description;
       bool s_ignore; ///< shall I ignore double-registrations?
 
diff --git a/bob/io/base/cpp/HDF5File.cpp b/bob/io/base/cpp/HDF5File.cpp
index 549069f8ab821df603ef35727d0da07a4a757137..796e31fe7cfcc6692e97dd0e25ee3a72261dba9d 100644
--- a/bob/io/base/cpp/HDF5File.cpp
+++ b/bob/io/base/cpp/HDF5File.cpp
@@ -7,9 +7,8 @@
  * Copyright (C) Idiap Research Institute, Martigny, Switzerland
  */
 
-#include <boost/format.hpp>
-
 #include <bob.io.base/HDF5File.h>
+#include <boost/format.hpp>
 
 static unsigned int getH5Access (bob::io::base::HDF5File::mode_t v) {
   switch(v) {
diff --git a/bob/io/base/cpp/HDF5Types.cpp b/bob/io/base/cpp/HDF5Types.cpp
index 6e79ae14728abd082f7e0977489e4ac1a7a6c898..3f1f07d54744e54a3b106c3b39022b99b96233bb 100644
--- a/bob/io/base/cpp/HDF5Types.cpp
+++ b/bob/io/base/cpp/HDF5Types.cpp
@@ -415,7 +415,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 bob::io::base::array::typeinfo& value) const
+bool bob::io::base::HDF5Type::compatible (const BobIoTypeinfo& value) const
 {
   return *this == HDF5Type(value);
 }
@@ -619,9 +619,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::io::base::array::N_MAX_DIMENSIONS_ARRAY) {\
+        if (N > BOB_BLITZ_MAXDIMS) {\
           boost::format m("you passed an array with %d dimensions, but this HDF5 API only supports arrays with up to %d dimensions"); \
-          m % N % bob::io::base::array::N_MAX_DIMENSIONS_ARRAY; \
+          m % N % BOB_BLITZ_MAXDIMS; \
           throw std::runtime_error(m.str()); \
         } \
       }
@@ -669,53 +669,56 @@ bob::io::base::HDF5Type::HDF5Type(bob::io::base::hdf5type type, const bob::io::b
 {
 }
 
-static bob::io::base::hdf5type array_to_hdf5 (bob::io::base::array::ElementType eltype) {
-  switch(eltype) {
-    case bob::io::base::array::t_unknown:
+static bob::io::base::hdf5type array_to_hdf5 (int dtype) {
+  switch(dtype) {
+    case NPY_NOTYPE:
       return bob::io::base::unsupported;
-    case bob::io::base::array::t_bool:
+    case NPY_BOOL:
       return bob::io::base::b;
-    case bob::io::base::array::t_int8:
+    case NPY_INT8:
       return bob::io::base::i8;
-    case bob::io::base::array::t_int16:
+    case NPY_INT16:
       return bob::io::base::i16;
-    case bob::io::base::array::t_int32:
+    case NPY_INT32:
       return bob::io::base::i32;
-    case bob::io::base::array::t_int64:
+    case NPY_INT64:
       return bob::io::base::i64;
-    case bob::io::base::array::t_uint8:
+    case NPY_UINT8:
       return bob::io::base::u8;
-    case bob::io::base::array::t_uint16:
+    case NPY_UINT16:
       return bob::io::base::u16;
-    case bob::io::base::array::t_uint32:
+    case NPY_UINT32:
       return bob::io::base::u32;
-    case bob::io::base::array::t_uint64:
+    case NPY_UINT64:
       return bob::io::base::u64;
-    case bob::io::base::array::t_float32:
+    case NPY_FLOAT32:
       return bob::io::base::f32;
-    case bob::io::base::array::t_float64:
+    case NPY_FLOAT64:
       return bob::io::base::f64;
-    case bob::io::base::array::t_float128:
+#   ifdef NPY_FLOAT128
+    case NPY_FLOAT128:
       return bob::io::base::f128;
-    case bob::io::base::array::t_complex64:
+#   endif
+    case NPY_COMPLEX64:
       return bob::io::base::c64;
-    case bob::io::base::array::t_complex128:
+    case NPY_COMPLEX128:
       return bob::io::base::c128;
-    case bob::io::base::array::t_complex256:
+#   ifdef NPY_COMPLEX256
+    case NPY_COMPLEX256:
       return bob::io::base::c256;
+#   endif
   }
   throw std::runtime_error("unsupported dtype <=> hdf5 type conversion -- FIXME");
 }
 
-bob::io::base::HDF5Type::HDF5Type(const bob::io::base::array::typeinfo& ti):
+bob::io::base::HDF5Type::HDF5Type(const BobIoTypeinfo& ti):
   m_type(array_to_hdf5(ti.dtype)),
   m_shape(ti.nd, ti.shape)
 {
 }
 
-bob::io::base::HDF5Type::HDF5Type(bob::io::base::array::ElementType eltype,
-    const HDF5Shape& extents):
-  m_type(array_to_hdf5(eltype)),
+bob::io::base::HDF5Type::HDF5Type(int dtype, const HDF5Shape& extents):
+  m_type(array_to_hdf5(dtype)),
   m_shape(extents)
 {
 }
@@ -765,56 +768,63 @@ std::string bob::io::base::HDF5Type::str() const {
   return retval.str();
 }
 
-bob::io::base::array::ElementType bob::io::base::HDF5Type::element_type() const {
+int bob::io::base::HDF5Type::element_type() const {
+
   switch (m_type) {
     case b:
-      return bob::io::base::array::t_bool;
+      return NPY_BOOL;
     case i8:
-      return bob::io::base::array::t_int8;
+      return NPY_INT8;
     case i16:
-      return bob::io::base::array::t_int16;
+      return NPY_INT16;
     case i32:
-      return bob::io::base::array::t_int32;
+      return NPY_INT32;
     case i64:
-      return bob::io::base::array::t_int64;
+      return NPY_INT64;
     case u8:
-      return bob::io::base::array::t_uint8;
+      return NPY_UINT8;
     case u16:
-      return bob::io::base::array::t_uint16;
+      return NPY_UINT16;
     case u32:
-      return bob::io::base::array::t_uint32;
+      return NPY_UINT32;
     case u64:
-      return bob::io::base::array::t_uint64;
+      return NPY_UINT64;
     case f32:
-      return bob::io::base::array::t_float32;
+      return NPY_FLOAT32;
     case f64:
-      return bob::io::base::array::t_float64;
+      return NPY_FLOAT64;
+#   ifdef NPY_FLOAT128
     case f128:
-      return bob::io::base::array::t_float128;
+      return NPY_FLOAT128;
+#   endif
     case c64:
-      return bob::io::base::array::t_complex64;
+      return NPY_COMPLEX64;
     case c128:
-      return bob::io::base::array::t_complex128;
+      return NPY_COMPLEX128;
+#   ifdef NPY_COMPLEX256
     case c256:
-      return bob::io::base::array::t_complex256;
+      return NPY_COMPLEX256;
+#   endif
     case s:
       throw std::runtime_error("Cannot convert HDF5 string type to an element type to be used in blitz::Array's - FIXME: something is wrong in the logic");
     default:
       break;
   }
-  return bob::io::base::array::t_unknown;
+
+  return NPY_NOTYPE;
+
 }
 
-void bob::io::base::HDF5Type::copy_to (bob::io::base::array::typeinfo& ti) const {
+void bob::io::base::HDF5Type::copy_to (BobIoTypeinfo& ti) const {
   ti.dtype = element_type();
   ti.nd = shape().n();
-  if (ti.nd > (BOB_MAX_DIM+1)) {
+  if (ti.nd > (BOB_BLITZ_MAXDIMS+1)) {
     boost::format f("HDF5 type has more (%d) than the allowed maximum number of dimensions (%d)");
-    f % ti.nd % (BOB_MAX_DIM+1);
+    f % ti.nd % (BOB_BLITZ_MAXDIMS+1);
     throw std::runtime_error(f.str());
   }
   for (size_t i=0; i<ti.nd; ++i) ti.shape[i] = shape()[i];
-  ti.update_strides();
+  BobIoTypeinfo_UpdateStrides(&ti);
 }
 
 bob::io::base::HDF5Descriptor::HDF5Descriptor(const HDF5Type& type, size_t size,
diff --git a/bob/io/base/cpp/TensorFile.cpp b/bob/io/base/cpp/TensorFile.cpp
index 66b72160ed861cf97126c4ff4bf4b26fc1f18046..d559ba67f9950de724e714016cb3f9163b424402 100644
--- a/bob/io/base/cpp/TensorFile.cpp
+++ b/bob/io/base/cpp/TensorFile.cpp
@@ -7,11 +7,10 @@
  * 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),
@@ -25,7 +24,7 @@ bob::io::base::TensorFile::TensorFile(const std::string& filename,
     if(m_stream)
     {
       m_header.read(m_stream);
-      m_buffer.reset(new char[m_header.m_type.buffer_size()]);
+      m_buffer.reset(new char[BobIoTypeinfo_BufferSize(&m_header.m_type)]);
       m_header_init = true;
       m_n_arrays_written = m_header.m_n_samples;
 
@@ -40,7 +39,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[m_header.m_type.buffer_size()]);
+      m_buffer.reset(new char[BobIoTypeinfo_BufferSize(&m_header.m_type)]);
       m_header_init = true;
       m_n_arrays_written = m_header.m_n_samples;
       m_stream.seekp(0, std::ios::end);
@@ -53,7 +52,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[m_header.m_type.buffer_size()]);
+      m_buffer.reset(new char[BobIoTypeinfo_BufferSize(&m_header.m_type)]);
       m_header_init = true;
       m_n_arrays_written = m_header.m_n_samples;
 
@@ -71,7 +70,7 @@ bob::io::base::TensorFile::~TensorFile() {
   close();
 }
 
-void bob::io::base::TensorFile::peek(bob::io::base::array::typeinfo& info) const {
+void bob::io::base::TensorFile::peek(BobIoTypeinfo& info) const {
   info = m_header.m_type;
 }
 
@@ -83,7 +82,7 @@ void bob::io::base::TensorFile::close() {
   m_stream.close();
 }
 
-void bob::io::base::TensorFile::initHeader(const bob::io::base::array::typeinfo& info) {
+void bob::io::base::TensorFile::initHeader(const BobIoTypeinfo& 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");
@@ -95,25 +94,25 @@ void bob::io::base::TensorFile::initHeader(const bob::io::base::array::typeinfo&
   m_header.write(m_stream);
 
   // Temporary buffer to help with data transposition...
-  m_buffer.reset(new char[m_header.m_type.buffer_size()]);
+  m_buffer.reset(new char[BobIoTypeinfo_BufferSize(&m_header.m_type)]);
 
   m_header_init = true;
 }
 
 void bob::io::base::TensorFile::write(const bob::io::base::array::interface& data) {
 
-  const bob::io::base::array::typeinfo& info = data.type();
+  const BobIoTypeinfo& info = data.type();
 
   if (!m_header_init) initHeader(info);
   else {
     //checks compatibility with previously written stuff
-    if (!m_header.m_type.is_compatible(info))
+    if (!BobIoTypeinfo_IsCompatible(&m_header.m_type, &info))
       throw std::runtime_error("buffer does not conform to expected type");
   }
 
-  bob::io::base::row_to_col_order(data.ptr(), m_buffer.get(), info);
+  BobIoReorder_RowToCol(data.ptr(), m_buffer.get(), &info);
 
-  m_stream.write(static_cast<const char*>(m_buffer.get()), info.buffer_size());
+  m_stream.write(static_cast<const char*>(m_buffer.get()), BobIoTypeinfo_BufferSize(&info));
 
   // increment m_n_arrays_written and m_current_array
   ++m_current_array;
@@ -125,12 +124,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(!buf.type().is_compatible(m_header.m_type)) buf.set(m_header.m_type);
+  if(!BobIoTypeinfo_IsCompatible(&buf.type(), &m_header.m_type)) buf.set(m_header.m_type);
 
   m_stream.read(reinterpret_cast<char*>(m_buffer.get()),
-      m_header.m_type.buffer_size());
+      BobIoTypeinfo_BufferSize(&m_header.m_type));
 
-  bob::io::base::col_to_row_order(m_buffer.get(), buf.ptr(), m_header.m_type);
+  BobIoReorder_ColToRow(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 35d42bfcea4d9a25084b82c28f008acb0f9f0609..2c342a4a8746c691125108b834b16e4837abaab6 100644
--- a/bob/io/base/cpp/TensorFile.h
+++ b/bob/io/base/cpp/TensorFile.h
@@ -10,12 +10,11 @@
 #ifndef BOB_IO_TENSORFILE_H
 #define BOB_IO_TENSORFILE_H
 
-#include <boost/format.hpp>
-#include <stdexcept>
+#include "TensorFileHeader.h"
 
 #include <bob.io.base/blitz_array.h>
-
-#include "TensorFileHeader.h"
+#include <boost/format.hpp>
+#include <stdexcept>
 
 namespace bob { namespace io { namespace base {
 
@@ -94,9 +93,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 typeinfo
+       * Peeks the file and returns the currently set type information
        */
-      void peek(bob::io::base::array::typeinfo& info) const;
+      void peek(BobIoTypeinfo& info) const;
 
       /**
        * Gets the number of samples/arrays written so far
@@ -130,7 +129,7 @@ namespace bob { namespace io { namespace base {
       /**
        * Initializes the tensor file with the given type and shape.
        */
-      inline void initTensorFile(const bob::io::base::array::typeinfo& info) {
+      inline void initTensorFile(const BobIoTypeinfo& info) {
         initHeader(info);
       }
 
@@ -161,7 +160,7 @@ namespace bob { namespace io { namespace base {
        * Initializes the header of the (output) stream with the given type
        * and shape
        */
-      void initHeader(const bob::io::base::array::typeinfo& info);
+      void initHeader(const BobIoTypeinfo& info);
 
     public:
 
@@ -186,7 +185,7 @@ namespace bob { namespace io { namespace base {
        * multiarrays saved have the same dimensions.
        */
       template <typename T, int D> inline blitz::Array<T,D> read() {
-        bob::io::base::array::typeinfo info;
+        BobIoTypeinfo info;
         peek(info);
         bob::io::base::array::blitz_array buf(info);
         read(buf);
@@ -195,7 +194,7 @@ namespace bob { namespace io { namespace base {
 
       template <typename T, int D> inline blitz::Array<T,D> read(size_t
           index) {
-        bob::io::base::array::typeinfo info;
+        BobIoTypeinfo 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 fb96a13b5d383eebed1c59467185272ded2a2547..8d8dfeefce3fd1cc70c1de1212293f3cd831a53d 100644
--- a/bob/io/base/cpp/TensorFileHeader.cpp
+++ b/bob/io/base/cpp/TensorFileHeader.cpp
@@ -7,9 +7,10 @@
  * Copyright (C) Idiap Research Institute, Martigny, Switzerland
  */
 
-#include <boost/format.hpp>
-
+#define BOB_IO_BASE_MODULE
 #include "TensorFileHeader.h"
+#include <bob.blitz/capi.h>
+#include <boost/format.hpp>
 
 bob::io::base::detail::TensorFileHeader::TensorFileHeader()
   : m_tensor_type(bob::io::base::Char),
@@ -31,28 +32,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;
 
-  int nd;
-  str.read(reinterpret_cast<char*>(&nd), sizeof(int));
+  str.read(reinterpret_cast<char*>(&val), sizeof(int));
+  size_t nd = (size_t)val;
 
-  int shape[BOB_MAX_DIM];
+  size_t shape[BOB_BLITZ_MAXDIMS];
 
-  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;
 
-  m_type.set_shape(nd, shape);
+  BobIoTypeinfo_Set(&m_type, m_type.dtype, nd, shape);
 
   header_ok();
 }
@@ -64,19 +65,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()
@@ -100,7 +101,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 % m_type.str();
+    m % BobIoTypeinfo_Str(&m_type);
     throw std::runtime_error(m.str());
   }
 
@@ -130,43 +131,43 @@ void bob::io::base::detail::TensorFileHeader::update()
 }
 
 
-bob::io::base::TensorType bob::io::base::arrayTypeToTensorType(bob::io::base::array::ElementType eltype)
+bob::io::base::TensorType bob::io::base::arrayTypeToTensorType(int dtype)
 {
-  switch(eltype)
+  switch(dtype)
   {
-    case bob::io::base::array::t_int8:
+    case NPY_INT8:
       return bob::io::base::Char;
-    case bob::io::base::array::t_int16:
+    case NPY_INT16:
       return bob::io::base::Short;
-    case bob::io::base::array::t_int32:
+    case NPY_INT32:
       return bob::io::base::Int;
-    case bob::io::base::array::t_int64:
+    case NPY_INT64:
       return bob::io::base::Long;
-    case bob::io::base::array::t_float32:
+    case NPY_FLOAT32:
       return bob::io::base::Float;
-    case bob::io::base::array::t_float64:
+    case NPY_FLOAT64:
       return bob::io::base::Double;
     default:
       throw std::runtime_error("unsupported data type found while converting array type to tensor type");
   }
 }
 
-bob::io::base::array::ElementType bob::io::base::tensorTypeToArrayType(bob::io::base::TensorType tensortype)
+int bob::io::base::tensorTypeToArrayType(bob::io::base::TensorType tensortype)
 {
   switch(tensortype)
   {
     case bob::io::base::Char:
-      return bob::io::base::array::t_int8;
+      return NPY_INT8;
     case bob::io::base::Short:
-      return bob::io::base::array::t_int16;
+      return NPY_INT16;
     case bob::io::base::Int:
-      return bob::io::base::array::t_int32;
+      return NPY_INT32;
     case bob::io::base::Long:
-      return bob::io::base::array::t_int64;
+      return NPY_INT64;
     case bob::io::base::Float:
-      return bob::io::base::array::t_float32;
+      return NPY_FLOAT32;
     case bob::io::base::Double:
-      return bob::io::base::array::t_float64;
+      return NPY_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 7e852b829997eb2f07914123e88646ccbd1f2fcb..7f3275d038e74d3375dbbee09ffc19fdf362ee56 100644
--- a/bob/io/base/cpp/TensorFileHeader.h
+++ b/bob/io/base/cpp/TensorFileHeader.h
@@ -11,10 +11,9 @@
 #ifndef BOB_IO_BASE_TENSORFILEHEADER_H
 #define BOB_IO_BASE_TENSORFILEHEADER_H
 
-#include <fstream>
+#include <bob.io.base/api.h>
 #include <blitz/array.h>
-
-#include <bob.io.base/array.h>
+#include <fstream>
 
 namespace bob { namespace io { namespace base {
 
@@ -29,8 +28,8 @@ namespace bob { namespace io { namespace base {
     Double
   };
 
-  TensorType arrayTypeToTensorType(bob::io::base::array::ElementType eltype);
-  bob::io::base::array::ElementType tensorTypeToArrayType(bob::io::base::TensorType tensortype);
+  TensorType arrayTypeToTensorType(int dtype);
+  int tensorTypeToArrayType(bob::io::base::TensorType tensortype);
 
   namespace detail {
     /**
@@ -85,7 +84,7 @@ namespace bob { namespace io { namespace base {
 
       //representation
       TensorType m_tensor_type; ///< array element type
-      bob::io::base::array::typeinfo m_type; ///< the type information
+      BobIoTypeinfo 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
deleted file mode 100644
index 2ffc94d77a13adec893f99fa8b052a55c45554ff..0000000000000000000000000000000000000000
--- a/bob/io/base/cpp/array.cpp
+++ /dev/null
@@ -1,134 +0,0 @@
-/**
- * @date Tue Nov 8 15:34:31 2011 +0100
- * @author Andre Anjos <andre.anjos@idiap.ch>
- *
- * @brief Some buffer stuff
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#include <boost/format.hpp>
-#include <bob.io.base/array.h>
-
-bob::io::base::array::typeinfo::typeinfo():
-  dtype(bob::io::base::array::t_unknown),
-  nd(0)
-{
-}
-
-bob::io::base::array::typeinfo::typeinfo(const bob::io::base::array::typeinfo& other):
-  dtype(other.dtype)
-{
-  set_shape(other.nd, other.shape);
-}
-
-bob::io::base::array::typeinfo& bob::io::base::array::typeinfo::operator= (const bob::io::base::array::typeinfo& other) {
-  dtype = other.dtype;
-  set_shape(other.nd, other.shape);
-  return *this;
-}
-
-void bob::io::base::array::typeinfo::reset() {
-  dtype = bob::io::base::array::t_unknown;
-  nd = 0;
-}
-
-bool bob::io::base::array::typeinfo::is_valid() const {
-  return (dtype != bob::io::base::array::t_unknown) && (nd > 0) && (nd <= (BOB_MAX_DIM+1)) && has_valid_shape();
-}
-
-void bob::io::base::array::typeinfo::update_strides() {
-  switch (nd) {
-    case 0:
-      return;
-    case 1:
-      stride[0] = 1;
-      return;
-    case 2:
-      stride[1] = 1;
-      stride[0] = shape[1];
-      return;
-    case 3:
-      stride[2] = 1;
-      stride[1] = shape[2];
-      stride[0] = shape[1]*shape[2];
-      return;
-    case 4:
-      stride[3] = 1;
-      stride[2] = shape[3];
-      stride[1] = shape[2]*shape[3];
-      stride[0] = shape[1]*shape[2]*shape[3];
-      return;
-    case 5:
-      stride[4] = 1;
-      stride[3] = shape[4];
-      stride[2] = shape[3]*shape[4];
-      stride[1] = shape[2]*shape[3]*shape[4];
-      stride[0] = shape[1]*shape[2]*shape[3]*shape[4];
-      return;
-    default:
-      break;
-  }
-  throw std::runtime_error("unsupported number of dimensions");
-}
-
-size_t bob::io::base::array::typeinfo::size() const {
-  size_t retval = 1;
-  for (size_t k=0; k<nd; ++k) retval *= shape[k];
-  return retval;
-}
-
-size_t bob::io::base::array::typeinfo::buffer_size() const {
-  return size()*bob::io::base::array::getElementSize(dtype);
-}
-
-static bool same_shape(size_t nd, const size_t* s1, const size_t* s2) {
-  for (size_t k=0; k<nd; ++k) if (s1[k] != s2[k]) return false;
-  return true;
-}
-
-bool bob::io::base::array::typeinfo::is_compatible(const bob::io::base::array::typeinfo& other) const {
-  return (dtype == other.dtype) && (nd == other.nd) && same_shape(nd, shape, other.shape);
-}
-
-std::string bob::io::base::array::typeinfo::str() const {
-  boost::format s("dtype: %s (%d); shape: [%s]; size: %d bytes");
-  size_t sz = 0;
-  size_t buf_sz = 0;
-  if (dtype != bob::io::base::array::t_unknown) {
-    //otherwise it throws
-    sz = item_size();
-    buf_sz = buffer_size();
-  }
-  s % item_str() % sz;
-  switch (nd) {
-    case 0:
-      s % "";
-      break;
-    case 1:
-      s % (boost::format("%d") % shape[0]).str();
-      break;
-    case 2:
-      s % (boost::format("%d,%d") % shape[0] % shape[1]).str();
-      break;
-    case 3:
-      s % (boost::format("%d,%d,%d") % shape[0] % shape[1] % shape[2]).str();
-      break;
-    case 4:
-      s % (boost::format("%d,%d,%d,%d") % shape[0] % shape[1] % shape[2] % shape[3]).str();
-      break;
-    default:
-      s % ">4 dimensions?";
-      break;
-  }
-  s % buf_sz;
-  return s.str();
-}
-
-void bob::io::base::array::typeinfo::reset_shape() {
-  shape[0] = 0;
-}
-
-bool bob::io::base::array::typeinfo::has_valid_shape() const {
-  return shape[0] != 0;
-}
diff --git a/bob/io/base/cpp/array_type.cpp b/bob/io/base/cpp/array_type.cpp
deleted file mode 100644
index d42368e9175199572724f337ba5623d6a8a76a71..0000000000000000000000000000000000000000
--- a/bob/io/base/cpp/array_type.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/**
- * @date Sat Apr 9 18:10:10 2011 +0200
- * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch>
- *
- * @brief Some type-related array utilities
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#include <bob.io.base/array_type.h>
-#include <boost/format.hpp>
-
-static const char* t_bool_string = "bool";
-static const char* t_int8_string = "int8";
-static const char* t_int16_string = "int16";
-static const char* t_int32_string = "int32";
-static const char* t_int64_string = "int64";
-static const char* t_uint8_string = "uint8";
-static const char* t_uint16_string = "uint16";
-static const char* t_uint32_string = "uint32";
-static const char* t_uint64_string = "uint64";
-static const char* t_float32_string = "float32";
-static const char* t_float64_string = "float64";
-static const char* t_float128_string = "float128";
-static const char* t_complex64_string = "complex64";
-static const char* t_complex128_string = "complex128";
-static const char* t_complex256_string = "complex256";
-static const char* t_unknown_string = "unknown";
-
-size_t bob::io::base::array::getElementSize(ElementType t) {
-  switch(t) {
-    case bob::io::base::array::t_bool:
-      return sizeof(bool);
-    case bob::io::base::array::t_int8:
-      return sizeof(int8_t);
-    case bob::io::base::array::t_int16:
-      return sizeof(int16_t);
-    case bob::io::base::array::t_int32:
-      return sizeof(int32_t);
-    case bob::io::base::array::t_int64:
-      return sizeof(int64_t);
-    case bob::io::base::array::t_uint8:
-      return sizeof(uint8_t);
-    case bob::io::base::array::t_uint16:
-      return sizeof(uint16_t);
-    case bob::io::base::array::t_uint32:
-      return sizeof(uint32_t);
-    case bob::io::base::array::t_uint64:
-      return sizeof(uint64_t);
-    case bob::io::base::array::t_float32:
-      return sizeof(float);
-    case bob::io::base::array::t_float64:
-      return sizeof(double);
-    case bob::io::base::array::t_float128:
-      return sizeof(long double);
-    case bob::io::base::array::t_complex64:
-      return sizeof(std::complex<float>);
-    case bob::io::base::array::t_complex128:
-      return sizeof(std::complex<double>);
-    case bob::io::base::array::t_complex256:
-      return sizeof(std::complex<long double>);
-    default:
-      {
-        boost::format m("unsupported element type (%d)");
-        m % (int)t;
-        throw std::runtime_error(m.str());
-      }
-  }
-}
-
-const char* bob::io::base::array::stringize(ElementType t) {
-  switch(t) {
-    case bob::io::base::array::t_bool:
-      return t_bool_string;
-    case bob::io::base::array::t_int8:
-      return t_int8_string;
-    case bob::io::base::array::t_int16:
-      return t_int16_string;
-    case bob::io::base::array::t_int32:
-      return t_int32_string;
-    case bob::io::base::array::t_int64:
-      return t_int64_string;
-    case bob::io::base::array::t_uint8:
-      return t_uint8_string;
-    case bob::io::base::array::t_uint16:
-      return t_uint16_string;
-    case bob::io::base::array::t_uint32:
-      return t_uint32_string;
-    case bob::io::base::array::t_uint64:
-      return t_uint64_string;
-    case bob::io::base::array::t_float32:
-      return t_float32_string;
-    case bob::io::base::array::t_float64:
-      return t_float64_string;
-    case bob::io::base::array::t_float128:
-      return t_float128_string;
-    case bob::io::base::array::t_complex64:
-      return t_complex64_string;
-    case bob::io::base::array::t_complex128:
-      return t_complex128_string;
-    case bob::io::base::array::t_complex256:
-      return t_complex256_string;
-    default:
-      return t_unknown_string;
-  }
-}
-
-bob::io::base::array::ElementType bob::io::base::array::unstringize(const char* s) {
-  std::string sc(s);
-  if (sc == t_bool_string) return bob::io::base::array::t_bool;
-  if (sc == t_int8_string) return bob::io::base::array::t_int8;
-  if (sc == t_int16_string) return bob::io::base::array::t_int16;
-  if (sc == t_int32_string) return bob::io::base::array::t_int32;
-  if (sc == t_int64_string) return bob::io::base::array::t_int64;
-  if (sc == t_uint8_string) return bob::io::base::array::t_uint8;
-  if (sc == t_uint16_string) return bob::io::base::array::t_uint16;
-  if (sc == t_uint32_string) return bob::io::base::array::t_uint32;
-  if (sc == t_uint64_string) return bob::io::base::array::t_uint64;
-  if (sc == t_float32_string) return bob::io::base::array::t_float32;
-  if (sc == t_float64_string) return bob::io::base::array::t_float64;
-  if (sc == t_float128_string) return bob::io::base::array::t_float128;
-  if (sc == t_complex64_string) return bob::io::base::array::t_complex64;
-  if (sc == t_complex128_string) return bob::io::base::array::t_complex128;
-  if (sc == t_complex256_string) return bob::io::base::array::t_complex256;
-  return bob::io::base::array::t_unknown;
-}
diff --git a/bob/io/base/cpp/blitz_array.cpp b/bob/io/base/cpp/blitz_array.cpp
index 2bc723a71d4b2770207fb24732641e1e67a1948f..0fd283744dbc54caa70ba8dc9c753fd9a282ff3a 100644
--- a/bob/io/base/cpp/blitz_array.cpp
+++ b/bob/io/base/cpp/blitz_array.cpp
@@ -27,21 +27,26 @@ bob::io::base::array::blitz_array::blitz_array(const interface& other) {
   set(other);
 }
 
-bob::io::base::array::blitz_array::blitz_array(const typeinfo& info) {
+bob::io::base::array::blitz_array::blitz_array(const BobIoTypeinfo& info) {
   set(info);
 }
 
-bob::io::base::array::blitz_array::blitz_array(void* data, const typeinfo& info):
-  m_type(info),
+bob::io::base::array::blitz_array::blitz_array(void* data, const BobIoTypeinfo& info):
+  m_type(),
   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) {
-  m_type = other->m_type;
+  if (!BobIoTypeinfo_Copy(&m_type, &other->m_type)) {
+    throw std::runtime_error("error already set");
+  }
   m_ptr = other->m_ptr;
   m_is_blitz = other->m_is_blitz;
   m_data = other->m_data;
@@ -49,11 +54,13 @@ 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(), m_type.buffer_size());
+  memcpy(m_ptr, other.ptr(), BobIoTypeinfo_BufferSize(&m_type));
 }
 
 void bob::io::base::array::blitz_array::set(boost::shared_ptr<interface> other) {
-  m_type = other->type();
+  if (!BobIoTypeinfo_Copy(&m_type, &other->type())) {
+    throw std::runtime_error("error already set");
+  }
   m_ptr = other->ptr();
   m_is_blitz = false;
   m_data = other;
@@ -105,58 +112,66 @@ 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 bob::io::base::array::typeinfo& req) {
-  if (m_type.is_compatible(req)) return; ///< double-check requirement first!
+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");
+  }
 
-  //ok, have to go through reallocation
-  m_type = req;
   m_is_blitz = true;
+
   switch (m_type.dtype) {
-    case bob::io::base::array::t_bool:
+    case NPY_BOOL:
       m_data = make_array<bool>(req.nd, req.shape, m_ptr);
       return;
-    case bob::io::base::array::t_int8:
+    case NPY_INT8:
       m_data = make_array<int8_t>(req.nd, req.shape, m_ptr);
       return;
-    case bob::io::base::array::t_int16:
+    case NPY_INT16:
       m_data = make_array<int16_t>(req.nd, req.shape, m_ptr);
       return;
-    case bob::io::base::array::t_int32:
+    case NPY_INT32:
       m_data = make_array<int32_t>(req.nd, req.shape, m_ptr);
       return;
-    case bob::io::base::array::t_int64:
+    case NPY_INT64:
       m_data = make_array<int64_t>(req.nd, req.shape, m_ptr);
       return;
-    case bob::io::base::array::t_uint8:
+    case NPY_UINT8:
       m_data = make_array<uint8_t>(req.nd, req.shape, m_ptr);
       return;
-    case bob::io::base::array::t_uint16:
+    case NPY_UINT16:
       m_data = make_array<uint16_t>(req.nd, req.shape, m_ptr);
       return;
-    case bob::io::base::array::t_uint32:
+    case NPY_UINT32:
       m_data = make_array<uint32_t>(req.nd, req.shape, m_ptr);
       return;
-    case bob::io::base::array::t_uint64:
+    case NPY_UINT64:
       m_data = make_array<uint64_t>(req.nd, req.shape, m_ptr);
       return;
-    case bob::io::base::array::t_float32:
+    case NPY_FLOAT32:
       m_data = make_array<float>(req.nd, req.shape, m_ptr);
       return;
-    case bob::io::base::array::t_float64:
+    case NPY_FLOAT64:
       m_data = make_array<double>(req.nd, req.shape, m_ptr);
       return;
-    case bob::io::base::array::t_float128:
+#   ifdef NPY_FLOAT128
+    case NPY_FLOAT128:
       m_data = make_array<long double>(req.nd, req.shape, m_ptr);
       return;
-    case bob::io::base::array::t_complex64:
+#   endif
+    case NPY_COMPLEX64:
       m_data = make_array<std::complex<float> >(req.nd, req.shape, m_ptr);
       return;
-    case bob::io::base::array::t_complex128:
+    case NPY_COMPLEX128:
       m_data = make_array<std::complex<double> >(req.nd, req.shape, m_ptr);
       return;
-    case bob::io::base::array::t_complex256:
+#   ifdef NPY_COMPLEX256
+    case NPY_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
deleted file mode 100644
index cda5ab335a47cb9a05dcf2e14357b91f6311cdfd..0000000000000000000000000000000000000000
--- a/bob/io/base/cpp/reorder.cpp
+++ /dev/null
@@ -1,288 +0,0 @@
-/**
- * @date Tue Nov 22 11:24:44 2011 +0100
- * @author Andre Anjos <andre.anjos@idiap.ch>
- *
- * @brief Implementation of row-major/column-major reordering
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#include <boost/format.hpp>
-#include <cstring> //for memcpy
-
-#include <bob.io.base/reorder.h>
-
-void bob::io::base::rc2d(size_t& row, size_t& col, const size_t i, const size_t j,
-    const size_t* shape) {
-  row = (i * shape[1]) + j;
-  col = (j * shape[0]) + i;
-}
-
-void bob::io::base::rc3d(size_t& row, size_t& col, const size_t i, const size_t j,
-    const size_t k, const size_t* shape) {
-  row = ( (i * shape[1]) + j ) * shape[2] + k;
-  col = ( (k * shape[1]) + j ) * shape[0] + i;
-}
-
-void bob::io::base::rc4d(size_t& row, size_t& col, const size_t i, const size_t j,
-    const size_t k, const size_t l, const size_t* shape) {
-  row = ( ( i * shape[1] + j ) * shape[2] + k ) * shape[3] + l;
-  col = ( ( l * shape[2] + k ) * shape[1] + j ) * shape[0] + i;
-}
-
-void bob::io::base::row_to_col_order(const void* src_, void* dst_,
-    const bob::io::base::array::typeinfo& info) {
-
-  size_t dsize = info.item_size();
-
-  //cast to byte type so we can manipulate the pointers...
-  const uint8_t* src = static_cast<const uint8_t*>(src_);
-  uint8_t* dst = static_cast<uint8_t*>(dst_);
-
-  switch(info.nd) {
-
-    case 1:
-      std::memcpy(dst, src, info.buffer_size());
-      break;
-
-    case 2:
-      for (size_t i=0; i<info.shape[0]; ++i)
-        for (size_t j=0; j<info.shape[1]; ++j) {
-          size_t row_major, col_major;
-          bob::io::base::rc2d(row_major, col_major, i, j, info.shape);
-          row_major *= dsize;
-          col_major *= dsize;
-          std::memcpy(&dst[col_major], &src[row_major], dsize);
-        }
-      break;
-
-    case 3:
-      for (size_t i=0; i<info.shape[0]; ++i)
-        for (size_t j=0; j<info.shape[1]; ++j)
-          for (size_t k=0; k<info.shape[2]; ++k) {
-            size_t row_major, col_major;
-            bob::io::base::rc3d(row_major, col_major, i, j, k, info.shape);
-            row_major *= dsize;
-            col_major *= dsize;
-            std::memcpy(&dst[col_major], &src[row_major], dsize);
-          }
-      break;
-
-    case 4:
-      for (size_t i=0; i<info.shape[0]; ++i)
-        for (size_t j=0; j<info.shape[1]; ++j)
-          for (size_t k=0; k<info.shape[2]; ++k)
-            for (size_t l=0; l<info.shape[3]; ++l) {
-              size_t row_major, col_major;
-              bob::io::base::rc4d(row_major, col_major, i, j, k, l, info.shape);
-              row_major *= dsize;
-              col_major *= dsize;
-              std::memcpy(&dst[col_major], &src[row_major], dsize);
-            }
-      break;
-
-    default:
-      {
-        boost::format m("row_to_col_order() can only flip arrays with up to %u dimensions - you passed one with %u dimensions");
-        m % BOB_MAX_DIM % info.nd;
-        throw std::runtime_error(m.str());
-      }
-  }
-}
-
-void bob::io::base::col_to_row_order(const void* src_, void* dst_,
-    const bob::io::base::array::typeinfo& info) {
-
-  size_t dsize = info.item_size();
-
-  //cast to byte type so we can manipulate the pointers...
-  const uint8_t* src = static_cast<const uint8_t*>(src_);
-  uint8_t* dst = static_cast<uint8_t*>(dst_);
-
-  switch(info.nd) {
-
-    case 1:
-      std::memcpy(dst, src, info.buffer_size());
-      break;
-
-    case 2:
-      for (size_t i=0; i<info.shape[0]; ++i)
-        for (size_t j=0; j<info.shape[1]; ++j) {
-          size_t row_major, col_major;
-          bob::io::base::rc2d(row_major, col_major, i, j, info.shape);
-          row_major *= dsize;
-          col_major *= dsize;
-          std::memcpy(&dst[row_major], &src[col_major], dsize);
-        }
-      break;
-
-    case 3:
-      for (size_t i=0; i<info.shape[0]; ++i)
-        for (size_t j=0; j<info.shape[1]; ++j)
-          for (size_t k=0; k<info.shape[2]; ++k) {
-            size_t row_major, col_major;
-            bob::io::base::rc3d(row_major, col_major, i, j, k, info.shape);
-            row_major *= dsize;
-            col_major *= dsize;
-            std::memcpy(&dst[row_major], &src[col_major], dsize);
-          }
-      break;
-
-    case 4:
-      for (size_t i=0; i<info.shape[0]; ++i)
-        for (size_t j=0; j<info.shape[1]; ++j)
-          for (size_t k=0; k<info.shape[2]; ++k)
-            for (size_t l=0; l<info.shape[3]; ++l) {
-              size_t row_major, col_major;
-              bob::io::base::rc4d(row_major, col_major, i, j, k, l, info.shape);
-              row_major *= dsize;
-              col_major *= dsize;
-              std::memcpy(&dst[row_major], &src[col_major], dsize);
-            }
-      break;
-
-    default:
-      {
-        boost::format m("col_to_row_order() can only flip arrays with up to %u dimensions - you passed one with %u dimensions");
-        m % BOB_MAX_DIM % info.nd;
-        throw std::runtime_error(m.str());
-      }
-  }
-}
-
-void bob::io::base::row_to_col_order_complex(const void* src_, void* dst_re_,
-    void* dst_im_, const bob::io::base::array::typeinfo& info) {
-
-  size_t dsize = info.item_size();
-  size_t dsize2 = dsize/2; ///< size of each complex component (real, imaginary)
-
-  //cast to byte type so we can manipulate the pointers...
-  const uint8_t* src = static_cast<const uint8_t*>(src_);
-  uint8_t* dst_re = static_cast<uint8_t*>(dst_re_);
-  uint8_t* dst_im = static_cast<uint8_t*>(dst_im_);
-
-  switch(info.nd) {
-
-    case 1:
-      for (size_t i=0; i<info.shape[0]; ++i) {
-        std::memcpy(&dst_re[dsize2*i], &src[dsize*i]       , dsize2);
-        std::memcpy(&dst_im[dsize2*i], &src[dsize*i]+dsize2, dsize2);
-      }
-      break;
-
-    case 2:
-      for (size_t i=0; i<info.shape[0]; ++i)
-        for (size_t j=0; j<info.shape[1]; ++j) {
-          size_t row_major, col_major;
-          bob::io::base::rc2d(row_major, col_major, i, j, info.shape);
-          row_major *= dsize;
-          col_major *= dsize2;
-          std::memcpy(&dst_re[col_major], &src[row_major]       , dsize2);
-          std::memcpy(&dst_im[col_major], &src[row_major]+dsize2, dsize2);
-        }
-      break;
-
-    case 3:
-      for (size_t i=0; i<info.shape[0]; ++i)
-        for (size_t j=0; j<info.shape[1]; ++j)
-          for (size_t k=0; k<info.shape[2]; ++k) {
-            size_t row_major, col_major;
-            bob::io::base::rc3d(row_major, col_major, i, j, k, info.shape);
-            row_major *= dsize;
-            col_major *= dsize2;
-            std::memcpy(&dst_re[col_major], &src[row_major]       , dsize2);
-            std::memcpy(&dst_im[col_major], &src[row_major]+dsize2, dsize2);
-          }
-      break;
-
-    case 4:
-      for (size_t i=0; i<info.shape[0]; ++i)
-        for (size_t j=0; j<info.shape[1]; ++j)
-          for (size_t k=0; k<info.shape[2]; ++k)
-            for (size_t l=0; l<info.shape[3]; ++l) {
-              size_t row_major, col_major;
-              bob::io::base::rc4d(row_major, col_major, i, j, k, l, info.shape);
-              row_major *= dsize;
-              col_major *= dsize2;
-              std::memcpy(&dst_re[col_major], &src[row_major]       , dsize2);
-              std::memcpy(&dst_im[col_major], &src[row_major]+dsize2, dsize2);
-            }
-      break;
-
-    default:
-      {
-        boost::format m("row_to_col_order_complex() can only flip arrays with up to %u dimensions - you passed one with %u dimensions");
-        m % BOB_MAX_DIM % info.nd;
-        throw std::runtime_error(m.str());
-      }
-  }
-}
-
-void bob::io::base::col_to_row_order_complex(const void* src_re_, const void* src_im_,
-    void* dst_, const bob::io::base::array::typeinfo& info) {
-
-  size_t dsize = info.item_size();
-  size_t dsize2 = dsize/2; ///< size of each complex component (real, imaginary)
-
-  //cast to byte type so we can manipulate the pointers...
-  const uint8_t* src_re = static_cast<const uint8_t*>(src_re_);
-  const uint8_t* src_im = static_cast<const uint8_t*>(src_im_);
-  uint8_t* dst = static_cast<uint8_t*>(dst_);
-
-  switch(info.nd) {
-
-    case 1:
-      for (size_t i=0; i<info.shape[0]; ++i) {
-        std::memcpy(&dst[dsize*i]       , &src_re[dsize2*i], dsize2);
-        std::memcpy(&dst[dsize*i]+dsize2, &src_im[dsize2*i], dsize2);
-      }
-      break;
-
-    case 2:
-      for (size_t i=0; i<info.shape[0]; ++i)
-        for (size_t j=0; j<info.shape[1]; ++j) {
-          size_t row_major, col_major;
-          bob::io::base::rc2d(row_major, col_major, i, j, info.shape);
-          row_major *= dsize;
-          col_major *= dsize2;
-          std::memcpy(&dst[row_major],        &src_re[col_major], dsize2);
-          std::memcpy(&dst[row_major]+dsize2, &src_im[col_major], dsize2);
-        }
-      break;
-
-    case 3:
-      for (size_t i=0; i<info.shape[0]; ++i)
-        for (size_t j=0; j<info.shape[1]; ++j)
-          for (size_t k=0; k<info.shape[2]; ++k) {
-            size_t row_major, col_major;
-            bob::io::base::rc3d(row_major, col_major, i, j, k, info.shape);
-            row_major *= dsize;
-            col_major *= dsize2;
-            std::memcpy(&dst[row_major]       , &src_re[col_major], dsize2);
-            std::memcpy(&dst[row_major]+dsize2, &src_im[col_major], dsize2);
-          }
-      break;
-
-    case 4:
-      for (size_t i=0; i<info.shape[0]; ++i)
-        for (size_t j=0; j<info.shape[1]; ++j)
-          for (size_t k=0; k<info.shape[2]; ++k)
-            for (size_t l=0; l<info.shape[3]; ++l) {
-              size_t row_major, col_major;
-              bob::io::base::rc4d(row_major, col_major, i, j, k, l, info.shape);
-              row_major *= dsize;
-              col_major *= dsize2;
-              std::memcpy(&dst[row_major]       , &src_re[col_major], dsize2);
-              std::memcpy(&dst[row_major]+dsize2, &src_im[col_major], dsize2);
-            }
-      break;
-
-    default:
-      {
-        boost::format m("col_to_row_order_complex() can only flip arrays with up to %u dimensions - you passed one with %u dimensions");
-        m % BOB_MAX_DIM % info.nd;
-        throw std::runtime_error(m.str());
-      }
-  }
-}
-
diff --git a/bob/io/base/cpp/CSVFile.cpp b/bob/io/base/csv.cpp
similarity index 73%
rename from bob/io/base/cpp/CSVFile.cpp
rename to bob/io/base/csv.cpp
index 1200523a09b74eee343a14686b39ba76995cc058..7932ad833caf34c50bae4a46549421e35a8f9598 100644
--- a/bob/io/base/cpp/CSVFile.cpp
+++ b/bob/io/base/csv.cpp
@@ -8,6 +8,10 @@
  * 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>
@@ -20,8 +24,6 @@
 #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 {
@@ -62,16 +64,16 @@ class CSVFile: public bob::io::base::File {
         return;
       }
 
-      m_arrayset_type.dtype = bob::io::base::array::t_float64;
+      m_arrayset_type.dtype = NPY_FLOAT64;
       m_arrayset_type.nd = 1;
       m_arrayset_type.shape[0] = entries;
-      m_arrayset_type.update_strides();
+      BobIoTypeinfo_UpdateStrides(&m_arrayset_type);
 
       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;
-      m_array_type.update_strides();
+      BobIoTypeinfo_UpdateStrides(&m_array_type);
     }
 
     CSVFile(const char* path, char mode):
@@ -116,11 +118,11 @@ class CSVFile: public bob::io::base::File {
       return m_filename.c_str();
     }
 
-    virtual const bob::io::base::array::typeinfo& type() const {
+    virtual const BobIoTypeinfo& type() const {
       return m_arrayset_type;
     }
 
-    virtual const bob::io::base::array::typeinfo& type_all() const {
+    virtual const BobIoTypeinfo& type_all() const {
       return m_array_type;
     }
 
@@ -136,7 +138,7 @@ class CSVFile: public bob::io::base::File {
       if (m_newfile)
         throw std::runtime_error("uninitialized CSV file cannot be read");
 
-      if (!buffer.type().is_compatible(m_array_type)) buffer.set(m_array_type);
+      if (!BobIoTypeinfo_IsCompatible(&buffer.type(), &m_array_type)) buffer.set(m_array_type);
 
       //read contents
       std::string line;
@@ -156,7 +158,7 @@ class CSVFile: public bob::io::base::File {
       if (m_newfile)
         throw std::runtime_error("uninitialized CSV file cannot be read");
 
-      if (!buffer.type().is_compatible(m_arrayset_type))
+      if (!BobIoTypeinfo_IsCompatible(&buffer.type(), &m_arrayset_type))
         buffer.set(m_arrayset_type);
 
       if (index >= m_pos.size()) {
@@ -184,12 +186,12 @@ class CSVFile: public bob::io::base::File {
 
     virtual size_t append (const bob::io::base::array::interface& buffer) {
 
-      const bob::io::base::array::typeinfo& type = buffer.type();
+      const BobIoTypeinfo& type = buffer.type();
 
       if (m_newfile) {
-        if (type.nd != 1 || type.dtype != bob::io::base::array::t_float64) {
+        if (type.nd != 1 || type.dtype != NPY_FLOAT64) {
           boost::format m("cannot append %s to file '%s' - CSV files only accept 1D double precision float arrays");
-          m % type.str() % m_filename;
+          m % BobIoTypeinfo_Str(&type) % m_filename;
           throw std::runtime_error(m.str());
         }
         m_pos.clear();
@@ -201,9 +203,9 @@ class CSVFile: public bob::io::base::File {
       else {
 
         //check compatibility
-        if (!m_arrayset_type.is_compatible(buffer.type())) {
+        if (!BobIoTypeinfo_IsCompatible(&m_arrayset_type, &buffer.type())) {
           boost::format m("CSV file '%s' only accepts arrays of type %s");
-          m % m_filename % m_arrayset_type.str();
+          m % m_filename % BobIoTypeinfo_Str(&m_arrayset_type);
           throw std::runtime_error(m.str());
         }
 
@@ -215,19 +217,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();
-      m_array_type.update_strides();
+      BobIoTypeinfo_UpdateStrides(&m_array_type);
       return (m_pos.size()-1);
 
     }
 
     virtual void write (const bob::io::base::array::interface& buffer) {
 
-      const bob::io::base::array::typeinfo& type = buffer.type();
+      const BobIoTypeinfo& type = buffer.type();
 
       if (m_newfile) {
-        if (type.nd != 2 || type.dtype != bob::io::base::array::t_float64) {
+        if (type.nd != 2 || type.dtype != NPY_FLOAT64) {
           boost::format m("cannot write %s to file '%s' - CSV files only accept a single 2D double precision float array as input");
-          m % type.str() % m_filename;
+          m % BobIoTypeinfo_Str(&type) % m_filename;
           throw std::runtime_error(m.str());
         }
         const double* p = static_cast<const double*>(buffer.ptr());
@@ -241,7 +243,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];
-        m_arrayset_type.update_strides();
+        BobIoTypeinfo_UpdateStrides(&m_arrayset_type);
         m_array_type = type;
         m_newfile = false;
         return;
@@ -256,8 +258,8 @@ class CSVFile: public bob::io::base::File {
     std::fstream m_file;
     std::string m_filename;
     bool m_newfile;
-    bob::io::base::array::typeinfo m_array_type;
-    bob::io::base::array::typeinfo m_arrayset_type;
+    BobIoTypeinfo m_array_type;
+    BobIoTypeinfo m_arrayset_type;
     std::vector<std::streampos> m_pos; ///< dictionary of line starts
 
     static std::string s_codecname;
@@ -267,48 +269,10 @@ class CSVFile: public bob::io::base::File {
 std::string CSVFile::s_codecname = "bob.csv";
 
 /**
- * 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.
+ * Registration method: use an unique name. Copy the definition to "plugin.h"
+ * and then call it on "main.cpp" to register the codec.
  */
-static boost::shared_ptr<bob::io::base::File> make_file (const char* path, char mode) {
+boost::shared_ptr<bob::io::base::File>
+  make_csv_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/file.cpp b/bob/io/base/file.cpp
index 58d760c5bf52455de8cddd27715d2ce8ff1a1ca5..321bcadb0c15e6c46ec92061c5c1976e715c0577 100644
--- a/bob/io/base/file.cpp
+++ b/bob/io/base/file.cpp
@@ -13,9 +13,6 @@
 #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);
 
@@ -121,10 +118,10 @@ static int PyBobIoFile_Init(PyBobIoFileObject* self, PyObject *args, PyObject* k
 
   try {
     if (pretend_extension) {
-      self->f = bob::io::base::open(c_filename, mode, pretend_extension);
+      self->f = BobIo_OpenWithExtension(c_filename, mode, pretend_extension);
     }
     else {
-      self->f = bob::io::base::open(c_filename, mode);
+      self->f = BobIo_Open(c_filename, mode);
     }
   }
   catch (std::exception& e) {
@@ -193,51 +190,6 @@ 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
@@ -247,15 +199,14 @@ static PyObject* PyBobIoFile_GetIndex (PyBobIoFileObject* self, Py_ssize_t i) {
     return 0;
   }
 
-  const bob::io::base::array::typeinfo& info = self->f->type();
+  const BobIoTypeinfo& info = self->f->type();
 
   npy_intp shape[NPY_MAXDIMS];
   for (size_t k=0; k<info.nd; ++k) shape[k] = info.shape[k];
 
-  int type_num = PyBobIo_AsTypenum(info.dtype);
-  if (type_num == NPY_NOTYPE) return 0; ///< failure
+  if (info.dtype == NPY_NOTYPE) return 0; ///< failure
 
-  PyObject* retval = PyArray_SimpleNew(info.nd, shape, type_num);
+  PyObject* retval = PyArray_SimpleNew(info.nd, shape, info.dtype);
   if (!retval) return 0;
   auto retval_ = make_safe(retval);
 
@@ -288,18 +239,17 @@ static PyObject* PyBobIoFile_GetSlice (PyBobIoFileObject* self, PySliceObject* s
         self->f->size(), &start, &stop, &step, &slicelength) < 0) return 0;
 
   //creates the return array
-  const bob::io::base::array::typeinfo& info = self->f->type();
+  const BobIoTypeinfo& info = self->f->type();
 
-  int type_num = PyBobIo_AsTypenum(info.dtype);
-  if (type_num == NPY_NOTYPE) return 0; ///< failure
+  if (info.dtype == NPY_NOTYPE) return 0; ///< failure
 
-  if (slicelength <= 0) return PyArray_SimpleNew(0, 0, type_num);
+  if (slicelength <= 0) return PyArray_SimpleNew(0, 0, info.dtype);
 
   npy_intp shape[NPY_MAXDIMS];
   shape[0] = slicelength;
   for (size_t k=0; k<info.nd; ++k) shape[k+1] = info.shape[k];
 
-  PyObject* retval = PyArray_SimpleNew(info.nd+1, shape, type_num);
+  PyObject* retval = PyArray_SimpleNew(info.nd+1, shape, info.dtype);
   if (!retval) return 0;
   auto retval_ = make_safe(retval);
 
@@ -383,15 +333,14 @@ static PyObject* PyBobIoFile_Read(PyBobIoFileObject* self, PyObject *args, PyObj
 
   // reads the whole file in a single shot
 
-  const bob::io::base::array::typeinfo& info = self->f->type_all();
+  const BobIoTypeinfo& info = self->f->type_all();
 
   npy_intp shape[NPY_MAXDIMS];
   for (size_t k=0; k<info.nd; ++k) shape[k] = info.shape[k];
 
-  int type_num = PyBobIo_AsTypenum(info.dtype);
-  if (type_num == NPY_NOTYPE) return 0; ///< failure
+  if (info.dtype == NPY_NOTYPE) return 0; ///< failure
 
-  PyObject* retval = PyArray_SimpleNew(info.nd, shape, type_num);
+  PyObject* retval = PyArray_SimpleNew(info.nd, shape, info.dtype);
   if (!retval) return 0;
   auto retval_ = make_safe(retval);
 
@@ -544,13 +493,12 @@ Returns the current position of the newly written array.\n\
 "
 );
 
-PyObject* PyBobIo_TypeInfoAsTuple (const bob::io::base::array::typeinfo& ti) {
+PyObject* PyBobIo_TypeInfoAsTuple (const BobIoTypeinfo& ti) {
 
-  int type_num = PyBobIo_AsTypenum(ti.dtype);
-  if (type_num == NPY_NOTYPE) return 0;
+  if (ti.dtype == NPY_NOTYPE) return 0;
 
   PyObject* retval = Py_BuildValue("NNN",
-      reinterpret_cast<PyObject*>(PyArray_DescrFromType(type_num)),
+      reinterpret_cast<PyObject*>(PyArray_DescrFromType(ti.dtype)),
       PyTuple_New(ti.nd), //shape
       PyTuple_New(ti.nd)  //strides
       );
@@ -576,7 +524,7 @@ static PyObject* PyBobIoFile_Describe(PyBobIoFileObject* self, PyObject *args, P
   PyObject* all = 0;
   if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &all)) return 0;
 
-  const bob::io::base::array::typeinfo* info = 0;
+  const BobIoTypeinfo* info = 0;
   if (all && PyObject_IsTrue(all)) info = &self->f->type_all();
   else info = &self->f->type();
 
diff --git a/bob/io/base/hdf5.cpp b/bob/io/base/hdf5.cpp
index dcb4249cc61a7f6f67c1c0cc32a360ca7b805a25..1b56fa64531d6b7a2de44b09bdb6e6673368c1f5 100644
--- a/bob/io/base/hdf5.cpp
+++ b/bob/io/base/hdf5.cpp
@@ -7,6 +7,7 @@
 
 #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/HDF5ArrayFile.cpp b/bob/io/base/hdf5plugin.cpp
similarity index 70%
rename from bob/io/base/cpp/HDF5ArrayFile.cpp
rename to bob/io/base/hdf5plugin.cpp
index 8a9aa97f888fa38ea24ea37e85d74c883ed646b3..5982adfe6317f4e66546d0203a12d1a2f832ca08 100644
--- a/bob/io/base/cpp/HDF5ArrayFile.cpp
+++ b/bob/io/base/hdf5plugin.cpp
@@ -7,13 +7,15 @@
  * 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
  */
@@ -65,11 +67,11 @@ class HDF5ArrayFile: public bob::io::base::File {
       return m_filename.c_str();
     }
 
-    virtual const bob::io::base::array::typeinfo& type_all () const {
+    virtual const BobIoTypeinfo& type_all () const {
       return m_type_array;
     }
 
-    virtual const bob::io::base::array::typeinfo& type () const {
+    virtual const BobIoTypeinfo& type () const {
       return m_type_arrayset;
     }
 
@@ -89,7 +91,7 @@ class HDF5ArrayFile: public bob::io::base::File {
         throw std::runtime_error(f.str());
       }
 
-      if(!buffer.type().is_compatible(m_type_array)) buffer.set(m_type_array);
+      if(!BobIoTypeinfo_IsCompatible(&buffer.type(), &m_type_array)) buffer.set(m_type_array);
 
       m_file.read_buffer(m_path, 0, buffer.type(), buffer.ptr());
     }
@@ -102,7 +104,7 @@ class HDF5ArrayFile: public bob::io::base::File {
         throw std::runtime_error(f.str());
       }
 
-      if(!buffer.type().is_compatible(m_type_arrayset)) buffer.set(m_type_arrayset);
+      if(!BobIoTypeinfo_IsCompatible(&buffer.type(), &m_type_arrayset)) buffer.set(m_type_arrayset);
 
       m_file.read_buffer(m_path, index, buffer.type(), buffer.ptr());
     }
@@ -152,8 +154,8 @@ class HDF5ArrayFile: public bob::io::base::File {
 
     bob::io::base::HDF5File m_file;
     std::string  m_filename;
-    bob::io::base::array::typeinfo m_type_array;    ///< type for reading all data at once
-    bob::io::base::array::typeinfo m_type_arrayset; ///< type for reading data by sub-arrays
+    BobIoTypeinfo m_type_array;    ///< type for reading all data at once
+    BobIoTypeinfo 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
@@ -165,32 +167,11 @@ class HDF5ArrayFile: public bob::io::base::File {
 std::string HDF5ArrayFile::s_codecname = "bob.hdf5";
 
 /**
- * From this point onwards we have the registration procedure. If you are
- * looking at this file for a coding example, just follow the procedure bellow,
- * minus local modifications you may need to apply.
- */
-
-/**
- * This defines the factory method F that can create codecs of this type.
- *
- * Here are the meanings of the mode flag that should be respected by your
- * factory implementation:
- *
- * 'r': opens for reading only - no modifications can occur; it is an
- *      error to open a file that does not exist for read-only operations.
- * 'w': opens for reading and writing, but truncates the file if it
- *      exists; it is not an error to open files that do not exist with
- *      this flag.
- * 'a': opens for reading and writing - any type of modification can
- *      occur. If the file does not exist, this flag is effectively like
- *      'w'.
- *
- * Returns a newly allocated File object that can read and write data to the
- * file using a specific backend.
- *
- * @note: This method can be static.
+ * Registration method: use an unique name. Copy the definition to "plugin.h"
+ * and then call it on "main.cpp" to register the codec.
  */
-static boost::shared_ptr<bob::io::base::File> make_file (const char* path, char mode) {
+boost::shared_ptr<bob::io::base::File>
+  make_hdf5_file (const char* path, char mode) {
 
   bob::io::base::HDF5File::mode_t h5mode;
   if (mode == 'r') h5mode = bob::io::base::HDF5File::in;
@@ -201,22 +182,3 @@ static boost::shared_ptr<bob::io::base::File> make_file (const char* path, char
   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/include/bob.io.base/File.h b/bob/io/base/include/bob.io.base/File.h
index bd58ff59145603073da7603501e63b338e9a33d5..1b71c9301da2d33f7041a9f7c6f73d5a66ddb471 100644
--- a/bob/io/base/include/bob.io.base/File.h
+++ b/bob/io/base/include/bob.io.base/File.h
@@ -11,9 +11,8 @@
 #ifndef BOB_IO_BASE_FILE_H
 #define BOB_IO_BASE_FILE_H
 
-#include <boost/shared_ptr.hpp>
-#include <bob.io.base/array.h>
 #include <bob.io.base/blitz_array.h>
+#include <boost/shared_ptr.hpp>
 
 namespace bob { namespace io { namespace base {
 
@@ -33,16 +32,16 @@ namespace bob { namespace io { namespace base {
       virtual const char* filename() const =0;
 
       /**
-       * The typeinfo of data within this file, if it is supposed to be read as
-       * as a sequence of arrays
+       * The type information of data within this file, if it is supposed to be
+       * read as as a sequence of arrays
        */
-      virtual const bob::io::base::array::typeinfo& type() const =0;
+      virtual const BobIoTypeinfo& type() const =0;
 
       /**
-       * The typeinfo of data within this file, if it is supposed to be read as
-       * a single array.
+       * The type information of data within this file, if it is supposed to be
+       * read as a single array.
        */
-      virtual const bob::io::base::array::typeinfo& type_all() const =0;
+      virtual const BobIoTypeinfo& type_all() const =0;
 
       /**
        * The number of arrays available in this file, if it is supposed to be
@@ -157,28 +156,6 @@ 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/HDF5File.h b/bob/io/base/include/bob.io.base/HDF5File.h
index 31c65944e5088b51af3fe1307e270e466b71052a..4c80604e74c319bcad99d8e531e37b37098e6b39 100644
--- a/bob/io/base/include/bob.io.base/HDF5File.h
+++ b/bob/io/base/include/bob.io.base/HDF5File.h
@@ -12,9 +12,8 @@
 #ifndef BOB_IO_BASE_HDF5FILE_H
 #define BOB_IO_BASE_HDF5FILE_H
 
-#include <boost/format.hpp>
-
 #include <bob.io.base/HDF5Utils.h>
+#include <boost/format.hpp>
 
 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 9dcd7a6e76cccdb40c1e4b98b4efdec63bcc52ef..9071403583f561bf5469e1255dc51aeb7ab1f5b3 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 <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>
 
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <hdf5.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 d19eab341873aafd33d2d4342fede82f5d7d3c79..81e1b6b574c4c79b297f0f13b128241caed2c97c 100644
--- a/bob/io/base/include/bob.io.base/HDF5Types.h
+++ b/bob/io/base/include/bob.io.base/HDF5Types.h
@@ -340,14 +340,14 @@ namespace bob { namespace io { namespace base {
       HDF5Type(hdf5type type);
 
       /**
-       * Creates a HDF5Type from an bob::io::base::array::typeinfo
+       * Creates a HDF5Type from an BobIoTypeinfo
        */
-      HDF5Type(const bob::io::base::array::typeinfo& ti);
+      HDF5Type(const BobIoTypeinfo& ti);
 
       /**
        * Creates a HDF5Type from a type enumeration and an explicit shape
        */
-      HDF5Type(bob::io::base::array::ElementType eltype, const HDF5Shape& extents);
+      HDF5Type(int dtype, 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 bob::io::base::array::typeinfo& value) const;
+      bool compatible (const BobIoTypeinfo& 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
        */
-      bob::io::base::array::ElementType element_type() const;
+      int element_type() const;
 
       /**
-       * Copies this type information to a stock bob::io::base::array::typeinfo
+       * Copies this type information to a stock BobIoTypeinfo
        */
-      void copy_to (bob::io::base::array::typeinfo& ti) const;
+      void copy_to (BobIoTypeinfo& 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 670430e2b4ffdf47d16c4953b593b89ba5352058..d380dfdd6b09a7bc8727d1b7b477c9820ab43145 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 001e8d4a5a282c082eb2adc862c0c9e15ff50619..9f6551b7c3832a1b6d863ca5b75df955e7c01c62 100644
--- a/bob/io/base/include/bob.io.base/api.h
+++ b/bob/io/base/include/bob.io.base/api.h
@@ -13,13 +13,11 @@
 #define BOB_IO_BASE_PREFIX    "bob.io.base"
 #define BOB_IO_BASE_FULL_NAME "bob.io.base._library"
 
-#include <Python.h>
+/* 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>
 
 /*******************
@@ -29,12 +27,37 @@
 /* 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_AsTypenum_NUM,
-  PyBobIo_TypeInfoAsTuple_NUM,
+  PyBobIo_TypeinfoAsTuple_NUM,
   PyBobIo_FilenameConverter_NUM,
   // HDF5 bindings
   PyBobIoHDF5File_Type_NUM,
@@ -55,11 +78,88 @@ 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*, const BobIoTypeinfo*)
+
+#define BobIoReorder_ColToRowComplex_RET int
+#define BobIoReorder_ColToRowComplex_PROTO (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
 
@@ -81,15 +181,28 @@ 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_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_TypeinfoAsTuple_RET PyObject*
+#define PyBobIo_TypeinfoAsTuple_PROTO (const BobIoTypeinfo& ti)
 
 #define PyBobIo_FilenameConverter_RET int
 #define PyBobIo_FilenameConverter_PROTO (PyObject* o, PyObject** b)
@@ -98,6 +211,7 @@ typedef struct {
  * HDF5 bindings *
  *****************/
 
+namespace bob { namespace io { namespace base { class HDF5File; }}}
 typedef struct {
   PyObject_HEAD
 
@@ -118,8 +232,30 @@ 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, bob::io::base::file_factory_t factory)
+#define PyBobIoCodec_Register_PROTO (const char* extension, const char* description, BobIoFileFactory factory)
 
 #define PyBobIoCodec_Deregister_RET int
 #define PyBobIoCodec_Deregister_PROTO (const char* extension)
@@ -140,6 +276,52 @@ typedef struct {
 
   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 *
    **********************************/
@@ -147,19 +329,29 @@ typedef struct {
   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_AsTypenum_RET PyBobIo_AsTypenum PyBobIo_AsTypenum_PROTO;
-
-  PyBobIo_TypeInfoAsTuple_RET PyBobIo_TypeInfoAsTuple PyBobIo_TypeInfoAsTuple_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;
 
@@ -167,17 +359,17 @@ typedef struct {
 
   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
 
@@ -199,6 +391,52 @@ typedef struct {
 
 # 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 *
    *****************************/
@@ -206,13 +444,23 @@ typedef struct {
 # 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_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_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 570c09f05f52fc115cc659f207c1137e080acce0..5bbe268ba99c056b9a985887c3bc585593de8045 100644
--- a/bob/io/base/include/bob.io.base/array.h
+++ b/bob/io/base/include/bob.io.base/array.h
@@ -11,14 +11,15 @@
 #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
@@ -29,170 +30,6 @@
  */
 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
@@ -225,12 +62,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 typeinfo& req) =0;
+      virtual void set (const BobIoTypeinfo& req) =0;
 
       /**
        * @brief Type information for this interface.
        */
-      virtual const typeinfo& type() const =0;
+      virtual const BobIoTypeinfo& 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
deleted file mode 100644
index 89eb1e26df2000beb040f2dc47aced0429029f6e..0000000000000000000000000000000000000000
--- a/bob/io/base/include/bob.io.base/array_type.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/**
- * @date Sat Apr 9 18:10:10 2011 +0200
- * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch>
- *
- * @brief This file contains information about the supported arrays
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#ifndef BOB_IO_BASE_ARRAY_TYPE_H
-#define BOB_IO_BASE_ARRAY_TYPE_H
-
-#include <stdint.h>
-#include <cstdlib>
-#include <complex>
-
-/**
- * @ingroup IO_ARRAY
- * @brief This macro defines the maximum number of dimensions supported by bob.
- * A variable in the bob.io.array namespace is created from this macro
- * receiving the same value. Use that variable on your programs, or this macro
- * on your preprocessor code.
- */
-#define BOB_MAX_DIM 4
-
-namespace bob { namespace io { namespace base { namespace array {
-
-  /**
-   * @brief Enumeration of the supported type for multidimensional arrays
-   * @warning float128 and complex256 are defined but currently not
-   * supported
-   */
-  typedef enum ElementType {
-    t_unknown=0,
-    t_bool=1,
-    t_int8=2,
-    t_int16=3,
-    t_int32=4,
-    t_int64=5,
-    t_uint8=6,
-    t_uint16=7,
-    t_uint32=8,
-    t_uint64=9,
-    t_float32=10,
-    t_float64=11,
-    t_float128=12,
-    t_complex64=13,
-    t_complex128=14,
-    t_complex256=15
-  } ElementType;
-
-  /**
-   * @brief Maximum number of supported dimensions for multidimensional
-   * arrays.
-   */
-  const size_t N_MAX_DIMENSIONS_ARRAY = BOB_MAX_DIM;
-
-  /**
-   * @brief These are some type to element type conversions
-   */
-  template<typename T> ElementType getElementType() {
-    return t_unknown;
-  }
-
-  /**
-   * @brief Some specializations that convert type to element type.
-   */
-  template<> inline ElementType getElementType<bool>() { return t_bool; }
-  template<> inline ElementType getElementType<int8_t>() { return t_int8; }
-  template<> inline ElementType getElementType<int16_t>()
-  { return t_int16; }
-  template<> inline ElementType getElementType<int32_t>()
-  { return t_int32; }
-  template<> inline ElementType getElementType<int64_t>()
-  { return t_int64; }
-  template<> inline ElementType getElementType<uint8_t>()
-  { return t_uint8; }
-  template<> inline ElementType getElementType<uint16_t>()
-  { return t_uint16; }
-  template<> inline ElementType getElementType<uint32_t>()
-  { return t_uint32; }
-  template<> inline ElementType getElementType<uint64_t>()
-  { return t_uint64; }
-  template<> inline ElementType getElementType<float>()
-  { return t_float32; }
-  template<> inline ElementType getElementType<double>()
-  { return t_float64; }
-  template<> inline ElementType getElementType<long double>()
-  { return t_float128; }
-  template<> inline ElementType getElementType<std::complex<float> >()
-  { return t_complex64; }
-  template<> inline ElementType getElementType<std::complex<double> >()
-  { return t_complex128; }
-  template<> inline ElementType getElementType<std::complex<long double> >()
-  { return t_complex256; }
-
-  /**
-   * @brief These are some type to element size conversions
-   */
-  template<typename T> size_t getElementSize() {
-    return 0;
-  }
-
-  /**
-   * @brief Some specializations that convert the types we handle properly
-   */
-  template<> inline size_t getElementSize<bool>() { return sizeof(bool); }
-  template<> inline size_t getElementSize<int8_t>()
-  { return sizeof(int8_t); }
-  template<> inline size_t getElementSize<int16_t>()
-  { return sizeof(int16_t); }
-  template<> inline size_t getElementSize<int32_t>()
-  { return sizeof(int32_t); }
-  template<> inline size_t getElementSize<int64_t>()
-  { return sizeof(int64_t); }
-  template<> inline size_t getElementSize<uint8_t>()
-  { return sizeof(uint8_t); }
-  template<> inline size_t getElementSize<uint16_t>()
-  { return sizeof(uint16_t); }
-  template<> inline size_t getElementSize<uint32_t>()
-  { return sizeof(uint32_t); }
-  template<> inline size_t getElementSize<uint64_t>()
-  { return sizeof(uint64_t); }
-  template<> inline size_t getElementSize<float>()
-  { return sizeof(float); }
-  template<> inline size_t getElementSize<double>()
-  { return sizeof(double); }
-  template<> inline size_t getElementSize<long double>()
-  { return sizeof(long double); }
-  template<> inline size_t getElementSize<std::complex<float> >()
-  { return sizeof(std::complex<float>); }
-  template<> inline size_t getElementSize<std::complex<double> >()
-  { return sizeof(std::complex<double>); }
-  template<> inline size_t getElementSize<std::complex<long double> >()
-  { return sizeof(std::complex<long double>); }
-
-  /**
-   * @brief Returns the type size given the enumeration
-   */
-  size_t getElementSize(ElementType t);
-
-  /**
-   * @brief Gets a string representation of an element type value
-   */
-  const char* stringize(ElementType t);
-
-  /**
-   * @brief Equivalent to call stringize() on the result of
-   * getElementType<T>().
-   */
-  template<typename T> const char* stringize() {
-    return stringize(getElementType<T>());
-  }
-
-  /**
-   * @brief Returns the ElementType given the string representation
-   */
-  ElementType unstringize(const char* name);
-
-}}}}
-
-#endif /* BOB_IO_BASE_ARRAY_TYPE_H */
diff --git a/bob/io/base/include/bob.io.base/array_utils.h b/bob/io/base/include/bob.io.base/array_utils.h
index 8fdfa77b4d6a1bb181031152255ab4a5fd685153..2ccf320af9fc5aa0657bf18003adbb969c6f8b07 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 typeinfo object
+   * @brief Fills in shape and stride starting from a type information object
    */
-  template <int N> void set_shape_and_stride(const typeinfo& info,
+  template <int N> void set_shape_and_stride(const BobIoTypeinfo& 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 typeinfo& type = buf.type();
+      const BobIoTypeinfo& type = buf.type();
 
       if (!buf.ptr()) throw std::runtime_error("empty buffer");
 
-      if (type.dtype != bob::io::base::array::getElementType<T>()) {
+      if (type.dtype != PyBlitzArrayCxx_CToTypenum<T>()) {
         boost::format m("cannot efficiently retrieve blitz::Array<%s,%d> from buffer of type '%s'");
-        m % stringize<T>() % N % type.str();
+        m % PyBlitzArray_TypenumAsString(PyBlitzArrayCxx_CToTypenum<T>()) % N % BobIoTypeinfo_Str(&type);
         throw std::runtime_error(m.str());
       }
 
       if (type.nd != N) {
         boost::format m("cannot retrieve blitz::Array<%s,%d> from buffer of type '%s'");
-        m % stringize<T>() % N % type.str();
+        m % PyBlitzArray_TypenumAsString(PyBlitzArrayCxx_CToTypenum<T>()) % N % BobIoTypeinfo_Str(&type);
         throw std::runtime_error(m.str());
       }
 
@@ -80,45 +80,49 @@ namespace bob { namespace io { namespace base { namespace array {
   template <typename T, int N>
     blitz::Array<T,N> cast(const interface& buf) {
 
-      const typeinfo& type = buf.type();
+      const BobIoTypeinfo& type = buf.type();
 
       if (type.nd != N) {
         boost::format m("cannot cast blitz::Array<%s,%d> from buffer of type '%s'");
-        m % stringize<T>() % N % type.str();
+        m % PyBlitzArray_TypenumAsString(PyBlitzArrayCxx_CToTypenum<T>()) % N % BobIoTypeinfo_Str(&type);
         throw std::runtime_error(m.str());
       }
 
       switch (type.dtype) {
-        case bob::io::base::array::t_bool:
+        case NPY_BOOL:
           return bob::core::array::cast<T>(wrap<bool,N>(buf));
-        case bob::io::base::array::t_int8:
+        case NPY_INT8:
           return bob::core::array::cast<T>(wrap<int8_t,N>(buf));
-        case bob::io::base::array::t_int16:
+        case NPY_INT16:
           return bob::core::array::cast<T>(wrap<int16_t,N>(buf));
-        case bob::io::base::array::t_int32:
+        case NPY_INT32:
           return bob::core::array::cast<T>(wrap<int32_t,N>(buf));
-        case bob::io::base::array::t_int64:
+        case NPY_INT64:
           return bob::core::array::cast<T>(wrap<int64_t,N>(buf));
-        case bob::io::base::array::t_uint8:
+        case NPY_UINT8:
           return bob::core::array::cast<T>(wrap<uint8_t,N>(buf));
-        case bob::io::base::array::t_uint16:
+        case NPY_UINT16:
           return bob::core::array::cast<T>(wrap<uint16_t,N>(buf));
-        case bob::io::base::array::t_uint32:
+        case NPY_UINT32:
           return bob::core::array::cast<T>(wrap<uint32_t,N>(buf));
-        case bob::io::base::array::t_uint64:
+        case NPY_UINT64:
           return bob::core::array::cast<T>(wrap<uint64_t,N>(buf));
-        case bob::io::base::array::t_float32:
+        case NPY_FLOAT32:
           return bob::core::array::cast<T>(wrap<float,N>(buf));
-        case bob::io::base::array::t_float64:
+        case NPY_FLOAT64:
           return bob::core::array::cast<T>(wrap<double,N>(buf));
-        case bob::io::base::array::t_float128:
+#       ifdef NPY_FLOAT128
+        case NPY_FLOAT128:
           return bob::core::array::cast<T>(wrap<long double,N>(buf));
-        case bob::io::base::array::t_complex64:
+#       endif
+        case NPY_COMPLEX64:
           return bob::core::array::cast<T>(wrap<std::complex<float>,N>(buf));
-        case bob::io::base::array::t_complex128:
+        case NPY_COMPLEX128:
           return bob::core::array::cast<T>(wrap<std::complex<double>,N>(buf));
-        case bob::io::base::array::t_complex256:
+#       ifdef NPY_COMPLEX256
+        case NPY_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 9927e0040e8f56f94ecf400327d8ff1648de3ef8..052c30d3d32d29e0870c4ca505d80cd7d75b2fbb 100644
--- a/bob/io/base/include/bob.io.base/blitz_array.h
+++ b/bob/io/base/include/bob.io.base/blitz_array.h
@@ -22,7 +22,6 @@
 
 #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 {
 
@@ -56,13 +55,13 @@ namespace bob { namespace io { namespace base { namespace array {
       /**
        * @brief Starts with an uninitialized, pre-allocated array.
        */
-      blitz_array(const typeinfo& info);
+      blitz_array(const BobIoTypeinfo& info);
 
       /**
        * @brief Borrows the given pointer - if you use this constructor, you
        * must make sure the pointed data outlives this object.
        */
-      blitz_array(void* data, const typeinfo& info);
+      blitz_array(void* data, const BobIoTypeinfo& info);
 
       /**
        * @brief Destroyes me
@@ -83,7 +82,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 typeinfo& req);
+      virtual void set (const BobIoTypeinfo& req);
 
       /**
        * @brief Refers to the data of another blitz array.
@@ -91,9 +90,9 @@ namespace bob { namespace io { namespace base { namespace array {
       void set(boost::shared_ptr<blitz_array> other);
 
       /**
-       * @brief Element type
+       * @brief type information
        */
-      virtual const typeinfo& type() const { return m_type; }
+      virtual const BobIoTypeinfo& type() const { return m_type; }
 
       /**
        * @brief Borrows a reference from the underlying memory. This means
@@ -152,16 +151,20 @@ namespace bob { namespace io { namespace base { namespace array {
       template <typename T, int N>
         void set(boost::shared_ptr<blitz::Array<T,N> > data) {
 
-          if (getElementType<T>() == t_unknown)
+          if (PyBlitzArrayCxx_CToTypenum<T>() == NPY_NOTYPE)
             throw std::runtime_error("unsupported element type on blitz::Array<>");
-          if (N > BOB_MAX_DIM)
+          if (N > BOB_BLITZ_MAXDIMS)
             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.set(data);
-
+          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_data = data;
           m_ptr = reinterpret_cast<void*>(data->data());
           m_is_blitz = true;
@@ -209,15 +212,15 @@ namespace bob { namespace io { namespace base { namespace array {
 
           if (!m_data) throw std::runtime_error("empty blitz array");
 
-          if (m_type.dtype != getElementType<T>()) {
+          if (m_type.dtype != PyBlitzArrayCxx_CToTypenum<T>()) {
             boost::format m("cannot efficiently retrieve blitz::Array<%s,%d> from buffer of type '%s'");
-            m % stringize<T>() % N % m_type.str();
+            m % PyBlitzArray_TypenumAsString(PyBlitzArrayCxx_CToTypenum<T>()) % N % BobIoTypeinfo_Str(&m_type);
             throw std::runtime_error(m.str());
           }
 
           if (m_type.nd != N) {
             boost::format m("cannot retrieve blitz::Array<%s,%d> from buffer of type '%s'");
-            m % stringize<T>() % N % m_type.str();
+            m % PyBlitzArray_TypenumAsString(PyBlitzArrayCxx_CToTypenum<T>()) % N % BobIoTypeinfo_Str(&m_type);
             throw std::runtime_error(m.str());
           }
 
@@ -249,7 +252,7 @@ namespace bob { namespace io { namespace base { namespace array {
 
     private: //representation
 
-      typeinfo m_type; ///< type information
+      BobIoTypeinfo 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
deleted file mode 100644
index 09ebf50422392cb6da05b255c4d9738f5d71d445..0000000000000000000000000000000000000000
--- a/bob/io/base/include/bob.io.base/reorder.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/**
- * @date Tue Nov 22 11:24:44 2011 +0100
- * @author Andre Anjos <andre.anjos@idiap.ch>
- *
- * @brief Row-major to column-major reordering and vice-versa
- *
- * Copyright (C) Idiap Research Institute, Martigny, Switzerland
- */
-
-#ifndef BOB_IO_BASE_REORDER_H
-#define BOB_IO_BASE_REORDER_H
-
-#include <stdint.h>
-
-#include <bob.io.base/array.h>
-
-namespace bob { namespace io { namespace base {
-
-  /**
-   * Returns, on the first argument, the linear indexes by calculating the
-   * linear positions relative to both row-major and column-major order
-   * matrixes given a certain index accessing a position in the matrix and the
-   * matrix shape
-   *
-   * @param row The resulting row-major linear index.
-   *            (row,col) is a 2-tuple with the results: row-major and
-   *            column-major linear indexes
-   * @param col The resulting column-major linear index. (see above)
-   * @param i   Index of the column.
-   *            (i,j) a 2-tuple with the indexes as would be accessed
-   *            [col][row]; this is the same as accessing the matrix like
-   *            on directions [y][x]
-   * @param j   Index of the row. (see above)
-   * @param shape a 2-tuple with the matrix shape like [col][row]; this is the
-   *        same as thinking about the extends of the matrix like on directions
-   *        [y][x]
-   *
-   * Detailed arithmetics with graphics and explanations can be found here:
-   * http://webster.cs.ucr.edu/AoA/Windows/HTML/Arraysa2.html
-   */
-  void rc2d(size_t& row, size_t& col, const size_t i, const size_t j,
-      const size_t* shape);
-
-  /**
-   * Same as above, but for a 3D array organized as [depth][column][row]
-   */
-  void rc3d(size_t& row, size_t& col, const size_t i, const size_t j,
-      const size_t k, const size_t* shape);
-
-  /**
-   * Same as above, but for a 4D array organized as [time][depth][column][row]
-   */
-  void rc4d(size_t& row, size_t& col, const size_t i, const size_t j,
-      const size_t k, const size_t l, const size_t* shape);
-
-  /**
-   * Converts the data from row-major order (C-Style) to column major order
-   * (Fortran style). Input parameters are the src data in row-major order, the
-   * destination (pre-allocated) array of the same size and the type
-   * information.
-   */
-  void row_to_col_order(const void* src_, void* dst_, const
-      bob::io::base::array::typeinfo& info);
-
-  /**
-   * Converts the data from column-major order (Fortran-Style) to row major
-   * order (C style), which is required by bob. Input parameters are the src
-   * data in column-major order, the destination (pre-allocated) array of the
-   * same size and the type information.
-   */
-  void col_to_row_order(const void* src_, void* dst_,
-      const bob::io::base::array::typeinfo& info);
-
-  /**
-   * Converts the data from row-major order (C-Style) to column major order
-   * (Fortran style). Input parameters are the src data in row-major order, the
-   * destination (pre-allocated) array of the same size and the type
-   * information.
-   */
-  void row_to_col_order_complex(const void* src_, void* dst_re_,
-      void* dst_im_, const bob::io::base::array::typeinfo& info);
-
-  /**
-   * Converts the data from column-major order (Fortran-Style) to row major
-   * order (C style), which is required by bob. Input parameters are the src
-   * data in column-major order, the destination (pre-allocated) array of the
-   * same size and the type information.
-   */
-  void col_to_row_order_complex(const void* src_re_, const void* src_im_,
-      void* dst_, const bob::io::base::array::typeinfo& info);
-
-}}}
-
-#endif /* BOB_IO_BASE_REORDER_H */
diff --git a/bob/io/base/include/bob.io.base/utils.h b/bob/io/base/include/bob.io.base/utils.h
index c42b1fac659dca6956dd241916aeeb2670c134c8..04931e06c833e9e4e61f4ac55870ab8578b19af8 100644
--- a/bob/io/base/include/bob.io.base/utils.h
+++ b/bob/io/base/include/bob.io.base/utils.h
@@ -8,9 +8,8 @@
 #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>
+#include <boost/shared_ptr.hpp>
 
 namespace bob { namespace io { namespace base {
 
@@ -42,22 +41,22 @@ namespace bob { namespace io { namespace base {
       const char* pretend_extension);
 
   /**
-   * Peeks the file and returns the typeinfo for reading individual frames (or
-   * samples) from the file.
+   * Peeks the file and returns the type information 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);
+  BobIoTypeinfo peek (const char* filename);
 
   /**
-   * Peeks the file and returns the typeinfo for reading the whole contents in
-   * a single shot.
+   * Peeks the file and returns the type information 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);
+  BobIoTypeinfo peek_all (const char* filename);
 
   /**
    * Opens for reading and load all contents
diff --git a/bob/io/base/main.cpp b/bob/io/base/main.cpp
index 27f18a04cc2a277afcb911639643edd53b68ae2b..50eaabd47231af8f3f593c7bd28dbc2eaa30174e 100644
--- a/bob/io/base/main.cpp
+++ b/bob/io/base/main.cpp
@@ -15,6 +15,9 @@
 #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
  * reference**.
@@ -121,6 +124,52 @@ 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 *
    **********************************/
@@ -129,13 +178,23 @@ 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_AsTypenum_NUM] = (void *)PyBobIo_AsTypenum;
-
-  PyBobIo_API[PyBobIo_TypeInfoAsTuple_NUM] = (void *)PyBobIo_TypeInfoAsTuple;
+  PyBobIo_API[PyBobIo_TypeinfoAsTuple_NUM] = (void *)PyBobIo_TypeinfoAsTuple;
 
   PyBobIo_API[PyBobIo_FilenameConverter_NUM] = (void *)PyBobIo_FilenameConverter;
 
@@ -149,9 +208,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;
 
@@ -192,6 +251,41 @@ 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
new file mode 100644
index 0000000000000000000000000000000000000000..735ff3761e22cb14e942489ecdfeacfc9778dd1c
--- /dev/null
+++ b/bob/io/base/plugin.h
@@ -0,0 +1,39 @@
+/**
+ * @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
new file mode 100644
index 0000000000000000000000000000000000000000..b07ac50d60fc1fef210e0cf5d8c39c5588ab6f3e
--- /dev/null
+++ b/bob/io/base/reorder.cpp
@@ -0,0 +1,317 @@
+/**
+ * @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/cpp/TensorArrayFile.cpp b/bob/io/base/tensor.cpp
similarity index 56%
rename from bob/io/base/cpp/TensorArrayFile.cpp
rename to bob/io/base/tensor.cpp
index d0cb72d82c948519126ac0e4dcfe237197d017b4..8d51dbcb77dc8723b150e8f28fb3c0433124f3f5 100644
--- a/bob/io/base/cpp/TensorArrayFile.cpp
+++ b/bob/io/base/tensor.cpp
@@ -7,8 +7,11 @@
  * Copyright (C) Idiap Research Institute, Martigny, Switzerland
  */
 
-#include "TensorFile.h"
-#include <bob.io.base/CodecRegistry.h>
+#define BOB_IO_BASE_MODULE
+#include <bob.io.base/api.h>
+#include <bob.io.base/File.h>
+
+#include "cpp/TensorFile.h"
 
 class TensorArrayFile: public bob::io::base::File {
 
@@ -26,11 +29,11 @@ class TensorArrayFile: public bob::io::base::File {
       return m_filename.c_str();
     }
 
-    virtual const bob::io::base::array::typeinfo& type_all () const {
+    virtual const BobIoTypeinfo& type_all () const {
       return m_type;
     }
 
-    virtual const bob::io::base::array::typeinfo& type () const {
+    virtual const BobIoTypeinfo& type () const {
       return m_type;
     }
 
@@ -80,7 +83,7 @@ class TensorArrayFile: public bob::io::base::File {
   private: //representation
 
     bob::io::base::TensorFile m_file;
-    bob::io::base::array::typeinfo m_type;
+    BobIoTypeinfo m_type;
     std::string m_filename;
 
     static std::string s_codecname;
@@ -90,32 +93,11 @@ class TensorArrayFile: public bob::io::base::File {
 std::string TensorArrayFile::s_codecname = "bob.tensor";
 
 /**
- * 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.
+ * Registration method: use an unique name. Copy the definition to "plugin.h"
+ * and then call it on "main.cpp" to register the codec.
  */
-
-/**
- * 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) {
+boost::shared_ptr<bob::io::base::File>
+  make_tensor_file (const char* path, char mode) {
 
   bob::io::base::TensorFile::openmode _mode;
   if (mode == 'r') _mode = bob::io::base::TensorFile::in;
@@ -126,19 +108,3 @@ static boost::shared_ptr<bob::io::base::File> make_file (const char* path, char
   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/T3File.cpp b/bob/io/base/torch3.cpp
similarity index 68%
rename from bob/io/base/cpp/T3File.cpp
rename to bob/io/base/torch3.cpp
index 8380a62fd912aa370f06f7e307c6fe614559eb81..5910da8f64d44fc00ef19a5d16449a7cdbc1c2b0 100644
--- a/bob/io/base/cpp/T3File.cpp
+++ b/bob/io/base/torch3.cpp
@@ -18,6 +18,11 @@
  * 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>
@@ -30,9 +35,6 @@
 
 #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);
@@ -69,12 +71,12 @@ class T3File: public bob::io::base::File {
 
           // are those floats or doubles?
           if (fsize == (nsamples*framesize*sizeof(float))) {
-            m_type_array.dtype = bob::io::base::array::t_float32;
-            m_type_arrayset.dtype = bob::io::base::array::t_float32;
+            m_type_array.dtype = NPY_FLOAT32;
+            m_type_arrayset.dtype = NPY_FLOAT32;
           }
           else if (fsize == (nsamples*framesize*sizeof(double))) {
-            m_type_array.dtype = bob::io::base::array::t_float64;
-            m_type_arrayset.dtype = bob::io::base::array::t_float64;
+            m_type_array.dtype = NPY_FLOAT64;
+            m_type_arrayset.dtype = NPY_FLOAT64;
           }
           else {
             boost::format s("Cannot read file '%s', mode = '%c': fsize (%d) != %d*%d*sizeof(float32) nor *sizeof(float64)");
@@ -83,8 +85,8 @@ class T3File: public bob::io::base::File {
           }
 
           size_t shape[2] = {nsamples, framesize};
-          m_type_array.set_shape<size_t>(2, &shape[0]);
-          m_type_arrayset.set_shape<size_t>(1, &shape[1]);
+          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_newfile = false;
 
         }
@@ -96,11 +98,11 @@ class T3File: public bob::io::base::File {
       return m_filename.c_str();
     }
 
-    virtual const bob::io::base::array::typeinfo& type_all () const {
+    virtual const BobIoTypeinfo& type_all () const {
       return m_type_array;
     }
 
-    virtual const bob::io::base::array::typeinfo& type () const {
+    virtual const BobIoTypeinfo& type () const {
       return m_type_arrayset;
     }
 
@@ -120,14 +122,14 @@ class T3File: public bob::io::base::File {
         throw std::runtime_error(f.str());
       }
 
-      if (!buffer.type().is_compatible(m_type_array)) buffer.set(m_type_array);
+      if (!BobIoTypeinfo_IsCompatible(&buffer.type(), &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()), buffer.type().buffer_size());
+      ifile.read(static_cast<char*>(buffer.ptr()), BobIoTypeinfo_BufferSize(&buffer.type()));
 
     }
 
@@ -139,26 +141,26 @@ class T3File: public bob::io::base::File {
         throw std::runtime_error(f.str());
       }
 
-      const bob::io::base::array::typeinfo& type = buffer.type();
+      const BobIoTypeinfo& type = buffer.type();
 
-      if (!buffer.type().is_compatible(m_type_arrayset)) buffer.set(m_type_arrayset);
+      if (!BobIoTypeinfo_IsCompatible(&buffer.type(), &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*type.buffer_size()), std::ios::beg);
-      ifile.read(static_cast<char*>(buffer.ptr()), type.buffer_size());
+      ifile.seekg(8 + (index*BobIoTypeinfo_BufferSize(&type)), std::ios::beg);
+      ifile.read(static_cast<char*>(buffer.ptr()), BobIoTypeinfo_BufferSize(&type));
 
     }
 
     virtual size_t append (const bob::io::base::array::interface& buffer) {
 
-      const bob::io::base::array::typeinfo& info = buffer.type();
+      const BobIoTypeinfo& info = buffer.type();
 
-      if (!m_newfile && !info.is_compatible(m_type_arrayset)) {
+      if (!m_newfile && !BobIoTypeinfo_IsCompatible(&info, &m_type_arrayset)) {
         boost::format f("input buffer of type %s cannot be appended to already initialized torch3vision binary file of type %s");
-        f % info.str() % m_type_arrayset.str();
+        f % BobIoTypeinfo_Str(&info) % BobIoTypeinfo_Str(&m_type_arrayset);
         throw std::runtime_error(f.str());
       }
 
@@ -168,15 +170,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 % info.str();
+          m % BobIoTypeinfo_Str(&info);
           throw std::runtime_error(m.str());
         }
 
         //can only save float32 or float64, otherwise, throw.
-        if ((info.dtype != bob::io::base::array::t_float32) &&
-            (info.dtype != bob::io::base::array::t_float64)) {
+        if ((info.dtype != NPY_FLOAT32) &&
+            (info.dtype != NPY_FLOAT64)) {
           boost::format f("cannot have T3 bindata files with type %s - only float32 or float64");
-          f % bob::io::base::array::stringize(info.dtype);
+          f % PyBlitzArray_TypenumAsString(info.dtype);
           throw std::runtime_error(f.str());
         }
 
@@ -205,13 +207,13 @@ class T3File: public bob::io::base::File {
         throw std::runtime_error(f.str());
       }
 
-      ofile.write(static_cast<const char*>(buffer.ptr()), info.buffer_size());
+      ofile.write(static_cast<const char*>(buffer.ptr()), BobIoTypeinfo_BufferSize(&info));
       ofile.close();
 
       //setup new type information
       ++m_length;
       size_t shape[2] = {m_length, info.shape[0]};
-      m_type_array.set_shape<size_t>(2, &shape[0]);
+      BobIoTypeinfo_Set(&m_type_array, m_type_array.dtype, 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);
@@ -230,7 +232,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 bob::io::base::array::typeinfo& info = buffer.type();
+      const BobIoTypeinfo& info = buffer.type();
 
       if (info.nd == 1) {//just do a normal append
         append(buffer);
@@ -239,10 +241,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());
-        bob::io::base::array::typeinfo slice_info(info.dtype, static_cast<size_t>(1),
-            &info.shape[1]);
+        BobIoTypeinfo slice_info;
+        BobIoTypeinfo_Set(&slice_info, info.dtype, 1, &info.shape[1]);
         for (size_t k=0; k<info.shape[0]; ++k) {
-          const void* slice_ptr=static_cast<const void*>(ptr+k*slice_info.buffer_size());
+          const void* slice_ptr=static_cast<const void*>(ptr+k*BobIoTypeinfo_BufferSize(&slice_info));
           bob::io::base::array::blitz_array slice(const_cast<void*>(slice_ptr), slice_info);
           append(slice);
         }
@@ -251,7 +253,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 % info.str();
+        f % BobIoTypeinfo_Str(&info);
         throw std::runtime_error(f.str());
       }
 
@@ -261,8 +263,8 @@ class T3File: public bob::io::base::File {
 
     std::string m_filename;
     bool m_newfile;
-    bob::io::base::array::typeinfo m_type_array;
-    bob::io::base::array::typeinfo m_type_arrayset;
+    BobIoTypeinfo m_type_array;
+    BobIoTypeinfo m_type_arrayset;
     size_t m_length;
 
     static std::string s_codecname;
@@ -272,47 +274,10 @@ class T3File: public bob::io::base::File {
 std::string T3File::s_codecname = "torch3.binary";
 
 /**
- * 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.
+ * Registration method: use an unique name. Copy the definition to "plugin.h"
+ * and then call it on "main.cpp" to register the codec.
  */
-static boost::shared_ptr<bob::io::base::File> make_file (const char* path, char mode) {
+boost::shared_ptr<bob::io::base::File>
+  make_torch3_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/typeinfo.cpp b/bob/io/base/typeinfo.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ff275c93009efb88809143309c388a6c4d8f1a66
--- /dev/null
+++ b/bob/io/base/typeinfo.cpp
@@ -0,0 +1,251 @@
+/**
+ * @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,
+    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;
+
+}
+
+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/bob/io/base/cpp/utils.cpp b/bob/io/base/utils.cpp
similarity index 53%
rename from bob/io/base/cpp/utils.cpp
rename to bob/io/base/utils.cpp
index 3467b997726137f619d1fb4911d5df8b28caaadc..17a7fde340709f8606ba25006d27646eee676b20 100644
--- a/bob/io/base/cpp/utils.cpp
+++ b/bob/io/base/utils.cpp
@@ -7,24 +7,30 @@
  * Copyright (C) Idiap Research Institute, Martigny, Switzerland
  */
 
-#include <bob.io.base/CodecRegistry.h>
-#include <bob.io.base/utils.h>
+#define BOB_IO_BASE_MODULE
+#include <bob.io.base/api.h>
+#include "cpp/CodecRegistry.h"
 
-boost::shared_ptr<bob::io::base::File> bob::io::base::open (const char* filename,
+boost::shared_ptr<bob::io::base::File> BobIoFile_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::File> BobIoFile_OpenWithExtension
+  (const char* filename, char mode) {
+
   boost::shared_ptr<bob::io::base::CodecRegistry> instance = bob::io::base::CodecRegistry::instance();
   return instance->findByFilenameExtension(filename)(filename, mode);
+
 }
 
-bob::io::base::array::typeinfo bob::io::base::peek (const char* filename) {
-  return open(filename, 'r')->type();
+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_all (const char* filename) {
-  return open(filename, 'r')->type_all();
+void BobIoFile_PeekAll (const char* filename, BobIoTypeinfo* info) {
+  BobIoTypeinfo_Copy(info, BobIoFile_Open(filename, 'r')->type_all());
 }
diff --git a/setup.py b/setup.py
index df02be063fadde2a1e340764143f893caed65037..5d2078a0f912f4a8dd7491b8ab20ba080ac64294 100644
--- a/setup.py
+++ b/setup.py
@@ -168,25 +168,25 @@ setup(
         ),
       Extension("bob.io.base._library",
         [
+          "bob/io/base/utils.cpp",
+          "bob/io/base/cpp/TensorFileHeader.cpp",
+          "bob/io/base/cpp/TensorFile.cpp",
+          "bob/io/base/cpp/blitz_array.cpp",
+
           "bob/io/base/cpp/CodecRegistry.cpp",
-          "bob/io/base/cpp/CSVFile.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/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",