diff --git a/gio/src/bufferedinputstream.ccg b/gio/src/bufferedinputstream.ccg
index d3ed7c2..7ca716a 100644
--- a/gio/src/bufferedinputstream.ccg
+++ b/gio/src/bufferedinputstream.ccg
@@ -18,6 +18,7 @@
  */
 
 #include <gio/gio.h>
+#include <giomm/error.h>
 #include "slot_async.h"
 
 namespace Gio
@@ -101,5 +102,74 @@ int BufferedInputStream::read_byte(std::auto_ptr<Glib::Error>& error)
 
 }
 
+// hand-coded virtual function
+
+gssize BufferedInputStream_Class::fill_vfunc_callback(GBufferedInputStream* self, gssize count, GCancellable* cancellable, GError** error)
+{
+  CppObjectType *const obj = dynamic_cast<CppObjectType*>(
+      Glib::ObjectBase::_get_current_wrapper((GObject*)self));
+
+  if(obj && obj->is_derived_())
+  {
+    #ifdef GLIBMM_EXCEPTIONS_ENABLED
+    try // Trap C++ exceptions which would normally be lost because this is a C callback.
+    {
+      // Call the virtual member method, which derived classes might override.
+      return obj->fill_vfunc(count, Glib::wrap(cancellable));
+    }
+    catch(Gio::Error gerror)
+    {
+      gerror.propagate(error);
+      return -1;
+    }
+    catch(...)
+    {
+      Glib::exception_handlers_invoke();
+    }
+    #else
+      std::auto_ptr<Glib::Error> gerror_ptr;
+      gssize ret = obj->fill_vfunc(count, Glib::wrap(cancellable), gerror_ptr);
+      gerror_ptr->propagate(error);
+      return ret;
+    #endif //GLIBMM_EXCEPTIONS_ENABLED
+  }
+  else
+  {
+    BaseClassType *const base = static_cast<BaseClassType*>(
+      g_type_class_peek_parent(G_OBJECT_GET_CLASS(self)) // Get the parent class of the object class (The original underlying C class).
+  );
+
+    // Call the original underlying C function:
+    if(base && base->fill)
+      return (*base->fill)(self, count, cancellable, error);
+  }
+
+  typedef gssize RType;
+  return RType();
+}
+
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+gssize BufferedInputStream::fill_vfunc(gssize count, const Glib::RefPtr<Cancellable>& cancellable)
+#else
+gssize BufferedInputStream::fill_vfunc(gssize count, const Glib::RefPtr<Cancellable>& cancellable, std::auto_ptr<Glib::Error>& error)
+#endif //GLIBMM_EXCEPTIONS_ENABLED
+{
+  BaseClassType *const base = static_cast<BaseClassType*>(
+      g_type_class_peek_parent(G_OBJECT_GET_CLASS(gobject_)) // Get the parent class of the object class (The original underlying C class).
+  );
+
+  if(base && base->fill)
+  {
+    GError *gerror;
+    gssize ret = (*base->fill)(gobj(), count, cancellable->gobj(), &gerror);
+    if (gerror)
+    #ifdef GLIBMM_EXCEPTIONS_ENABLED
+      ::Glib::Error::throw_exception(gerror);
+    #else
+      error = ::Glib::Error::throw_exception(gerror);
+    #endif //GLIBMM_EXCEPTIONS_ENABLED
+    return ret;
+  }
+}
 
 }   // namespace Gio
diff --git a/gio/src/bufferedinputstream.hg b/gio/src/bufferedinputstream.hg
index b7ae1c9..5d7033f 100644
--- a/gio/src/bufferedinputstream.hg
+++ b/gio/src/bufferedinputstream.hg
@@ -110,9 +110,21 @@ public:
   _WRAP_PROPERTY("buffer-size", guint)
 
 protected:
-#m4 _CONVERSION(`GCancellable*', `const Glib::RefPtr<Cancellable>&', `Glib::wrap($3, true)')
-  //_WRAP_VFUNC(gssize fill(gssize count, const Glib::RefPtr<Cancellable>& cancellable, GError** error), "fill")
-
+  #ifdef GLIBMM_EXCEPTIONS_ENABLED
+  virtual gssize fill_vfunc(gssize count, const Glib::RefPtr<Cancellable>& cancellable);
+  #else
+  virtual gssize fill_vfunc(gssize count, const Glib::RefPtr<Cancellable>& cancellable, std::auto_ptr<Glib::Error>& error);
+  #endif
+
+#m4begin
+dnl// Virtual functions need to be hand-coded, because of exception handling requirements.
+dnl
+  _PUSH(SECTION_PCC_CLASS_INIT_VFUNCS)
+    klass->fill = &fill_vfunc_callback;
+  _SECTION(SECTION_PH_VFUNCS)
+    static gssize fill_vfunc_callback(GBufferedInputStream* self, gssize count, GCancellable* cancellable, GError** error);
+  _POP()
+#m4end
 };
 
 } // namespace Gio
diff --git a/gio/src/filterinputstream.ccg b/gio/src/filterinputstream.ccg
index 40517b7..6d2e206 100644
--- a/gio/src/filterinputstream.ccg
+++ b/gio/src/filterinputstream.ccg
@@ -18,3 +18,14 @@
  */
 
 #include <gio/gio.h>
+#include <giomm/filterinputstream.h>
+
+namespace Gio {
+
+FilterInputStream::FilterInputStream(const Glib::RefPtr<InputStream>& base_stream)
+:
+  Glib::ObjectBase(0),
+  Gio::InputStream(Glib::ConstructParams(filterinputstream_class_.init(), "base_stream", const_cast<GInputStream*>(Glib::unwrap(base_stream)), static_cast<char*>(0)))
+{}
+
+} // namespace Gio
diff --git a/gio/src/filterinputstream.hg b/gio/src/filterinputstream.hg
index c975c64..094f17d 100644
--- a/gio/src/filterinputstream.hg
+++ b/gio/src/filterinputstream.hg
@@ -51,6 +51,10 @@ public:
 
   _WRAP_PROPERTY("base-stream", Glib::RefPtr<InputStream>)
   _WRAP_PROPERTY("close-base-stream", bool)
+
+protected:
+  // this needs to be hand-coded because there is no public GFilterInputStream constructor.
+  FilterInputStream(const Glib::RefPtr<InputStream>& base_stream);
 };
 
 } // namespace Gio
diff --git a/gio/src/filteroutputstream.ccg b/gio/src/filteroutputstream.ccg
index 40517b7..c10df64 100644
--- a/gio/src/filteroutputstream.ccg
+++ b/gio/src/filteroutputstream.ccg
@@ -18,3 +18,14 @@
  */
 
 #include <gio/gio.h>
+#include <giomm/filteroutputstream.h>
+
+namespace Gio {
+
+FilterOutputStream::FilterOutputStream(const Glib::RefPtr<OutputStream>& base_stream)
+:
+  Glib::ObjectBase(0),
+  Gio::OutputStream(Glib::ConstructParams(filteroutputstream_class_.init(), "base_stream", const_cast<GOutputStream*>(Glib::unwrap(base_stream)), static_cast<char*>(0)))
+{}
+
+} // namespace Gio
diff --git a/gio/src/filteroutputstream.hg b/gio/src/filteroutputstream.hg
index d6137f9..839012f 100644
--- a/gio/src/filteroutputstream.hg
+++ b/gio/src/filteroutputstream.hg
@@ -49,8 +49,12 @@ public:
   _WRAP_METHOD(bool get_close_base_stream() const, g_filter_output_stream_get_close_base_stream)
   _WRAP_METHOD(void set_close_base_stream(bool close_base = true), g_filter_output_stream_set_close_base_stream)
 
-  _WRAP_PROPERTY("base-stream", Glib::RefPtr<InputStream>)
+  _WRAP_PROPERTY("base-stream", Glib::RefPtr<OutputStream>)
   _WRAP_PROPERTY("close-base-stream", bool)
+
+protected:
+  // this needs to be hand-coded because there is no public GFilterOutputStream constructor.
+  FilterOutputStream(const Glib::RefPtr<OutputStream>& base_stream);
 };
 
 } // namespace Gio
diff --git a/gio/src/gio_vfuncs.defs b/gio/src/gio_vfuncs.defs
index d295c10..463d20b 100644
--- a/gio/src/gio_vfuncs.defs
+++ b/gio/src/gio_vfuncs.defs
@@ -474,4 +474,384 @@
  )
 )
 
+; GInputStream
 
+(define-vfunc read_fn
+ (of-object "GInputStream")
+ (return-type "gssize")
+ (parameters
+  '("void*" "buffer")
+  '("gsize" "count")
+  '("GCancellable*" "cancellable")
+  '("GError**" "error")
+ )
+)
+
+(define-vfunc skip
+ (of-object "GInputStream")
+ (return-type "gssize")
+ (parameters
+  '("gsize" "count")
+  '("GCancellable*" "cancellable")
+  '("GError**" "error")
+ )
+)
+
+(define-vfunc close_fn
+ (of-object "GInputStream")
+ (return-type "gboolean")
+ (parameters
+  '("GCancellable*" "cancellable")
+  '("GError**" "error")
+ )
+)
+
+(define-vfunc read_async
+ (of-object "GInputStream")
+ (return-type "void")
+ (parameters
+  '("void*" "buffer")
+  '("gsize" "count")
+  '("int" "io_priority")
+  '("GCancellable*" "cancellable")
+  '("GAsyncReadyCallback" "callback")
+  '("gpointer" "user_data")
+ )
+)
+
+(define-vfunc read_finish
+ (of-object "GInputStream")
+ (return-type "gssize")
+ (parameters
+  '("GAsyncResult*" "result")
+  '("GError**" "error")
+ )
+)
+
+(define-vfunc skip_async
+ (of-object "GInputStream")
+ (return-type "void")
+ (parameters
+  '("gsize" "count")
+  '("int" "io_priority")
+  '("GCancellable*" "cancellable")
+  '("GAsyncReadyCallback" "callback")
+  '("gpointer" "user_data")
+ )
+)
+
+(define-vfunc skip_finish
+ (of-object "GInputStream")
+ (return-type "gssize")
+ (parameters
+  '("GAsyncResult*" "result")
+  '("GError**" "error")
+ )
+)
+
+(define-vfunc close_async
+ (of-object "GInputStream")
+ (return-type "void")
+ (parameters
+  '("int" "io_priority")
+  '("GCancellable*" "cancellable")
+  '("GAsyncReadyCallback" "callback")
+  '("gpointer" "user_data")
+ )
+)
+
+(define-vfunc close_finish
+ (of-object "GInputStream")
+ (return-type "gboolean")
+ (parameters
+  '("GAsyncResult*" "result")
+  '("GError**" "error")
+ )
+)
+
+; GFileInputStream
+
+(define-vfunc tell
+ (of-object "GFileInputStream")
+ (return-type "goffset")
+)
+
+(define-vfunc can_seek
+ (of-object "GFileInputStream")
+ (return-type "gboolean")
+)
+
+(define-vfunc seek
+ (of-object "GFileInputStream")
+ (return-type "gboolean")
+ (parameters
+  '("goffset" "offset")
+  '("GSeekType" "type")
+  '("GCancellable*" "cancellable")
+  '("GError**" "error")
+ )
+)
+
+(define-vfunc query_info
+ (of-object "GFileInputStream")
+ (return-type "GFileInfo*")
+ (parameters
+  '("const-char*" "attributes")
+  '("GCancellable*" "cancellable")
+  '("GError**" "error")
+ )
+)
+
+(define-vfunc query_info_async
+ (of-object "GFileInputStream")
+ (return-type "void")
+ (parameters
+  '("const-char*" "attributes")
+  '("int" "io_priority")
+  '("GCancellable*" "cancellable")
+  '("GAsyncReadyCallback" "callback")
+  '("gpointer" "user_data")
+ )
+)
+
+(define-vfunc query_info_finish
+ (of-object "GFileInputStream")
+ (return-type "GFileInfo*")
+ (parameters
+  '("GAsyncResult*" "res")
+  '("GError**" "error")
+ )
+)
+
+; GBufferedInputStream
+
+(define-vfunc fill
+ (of-object "GBufferedInputStream")
+ (return-type "gssize")
+ (parameters
+  '("gssize" "count")
+  '("GCancellable*" "cancellable")
+  '("GError**" "error")
+ )
+)
+
+(define-vfunc fill_async
+ (of-object "GBufferedInputStream")
+ (return-type "void")
+ (parameters
+  '("gssize" "count")
+  '("int" "io_priority")
+  '("GCancellable*" "cancellable")
+  '("GAsyncReadyCallback" "callback")
+  '("gpointer" "user_data")
+ )
+)
+
+(define-vfunc fill_finish
+ (of-object "GBufferedInputStream")
+ (return-type "gssize")
+ (parameters
+  '("GAsyncResult*" "result")
+  '("GError**" "error")
+ )
+)
+
+; GOutputStream
+
+(define-vfunc write_fn
+ (of-object "GOutputStream")
+ (return-type "gssize")
+ (parameters
+  '("const-void*" "buffer")
+  '("gsize" "count")
+  '("GCancellable*" "cancellable")
+  '("GError**" "error") 
+ )
+)
+
+(define-vfunc splice
+ (of-object "GOutputStream")
+ (return-type "gssize")
+ (parameters
+  '("GInputStream*" "source")
+  '("GOutputStreamSpliceFlags" "flags")
+  '("GCancellable*" "cancellable")
+  '("GError**" "error") 
+ )
+)
+
+(define-vfunc flush
+ (of-object "GOutputStream")
+ (return-type "gboolean")
+ (parameters
+  '("GCancellable*" "cancellable")
+  '("GError**" "error")
+ )
+)
+
+(define-vfunc close_fn
+ (of-object "GOutputStream")
+ (return-type "gboolean")
+ (parameters
+  '("GCancellable*" "cancellable")
+  '("GError**" "error")
+ )
+)
+
+(define-vfunc write_async
+ (of-object "GOutputStream")
+ (return-type "void")
+ (parameters
+  '("const-void*" "buffer")
+  '("gsize" "count")
+  '("int" "io_priority")
+  '("GCancellable*" "cancellable")
+  '("GAsyncReadyCallback" "callback")
+  '("gpointer" "user_data")
+ )
+)
+
+(define-vfunc write_finish
+ (of-object "GOutputStream")
+ (return-type "gssize")
+ (parameters
+  '("GAsyncResult*" "result")
+  '("GError**" "error")
+ )
+)
+
+(define-vfunc splice_async
+ (of-object "GOutputStream")
+ (return-type "void")
+ (parameters
+  '("GInputStream*" "source")
+  '("GOutputStreamSpliceFlags" "flags")
+  '("int" "io_priority")
+  '("GCancellable*" "cancellable")
+  '("GAsyncReadyCallback" "callback")
+  '("gpointer" "user_data")
+ )
+)
+
+(define-vfunc splice_finish
+ (of-object "GOutputStream")
+ (return-type "gssize")
+ (parameters
+  '("GAsyncResult*" "result")
+  '("GError**" "error")
+ )
+)
+
+(define-vfunc flush_async
+ (of-object "GOutputStream")
+ (return-type "void")
+ (parameters
+  '("int" "io_priority")
+  '("GCancellable*" "cancellable")
+  '("GAsyncReadyCallback" "callback")
+  '("gpointer" "user_data")
+ )
+)
+
+(define-vfunc flush_finish
+ (of-object "GOutputStream")
+ (return-type "gboolean")
+ (parameters
+  '("GAsyncResult*" "result")
+  '("GError**" "error")
+ )
+)
+
+(define-vfunc close_async
+ (of-object "GOutputStream")
+ (return-type "void")
+ (parameters
+  '("int" "io_priority")
+  '("GCancellable*" "cancellable")
+  '("GAsyncReadyCallback" "callback")
+  '("gpointer" "user_data")
+ )
+)
+
+(define-vfunc close_finish
+ (of-object "GOutputStream")
+ (return-type "gboolean")
+ (parameters
+  '("GAsyncResult*" "result")
+  '("GError**" "error")
+ )
+)
+
+; GFileOutputStream
+
+(define-vfunc tell
+ (of-object "GFileOutputStream")
+ (return-type "goffset")
+)
+
+(define-vfunc can_seek
+ (of-object "GFileOutputStream")
+ (return-type "gboolean")
+)
+
+(define-vfunc seek
+ (of-object "GFileOutputStream")
+ (return-type "gboolean")
+ (parameters
+  '("goffset" "offset")
+  '("GSeekType" "type")
+  '("GCancellable*" "cancellable")
+  '("GError**" "error")
+ )
+)
+
+(define-vfunc can_truncate
+ (of-object "GFileOutputStream")
+ (return-type "gboolean")
+)
+
+(define-vfunc truncate_fn
+ (of-object "GFileOutputStream")
+ (return-type "gboolean")
+ (parameters
+  '("goffset" "offset")
+  '("GCancellable*" "cancellable")
+  '("GError**" "error")
+ )
+)
+
+(define-vfunc query_info
+ (of-object "GFileOutputStream")
+ (return-type "GFileInfo*")
+ (parameters
+  '("const-char*" "attributes")
+  '("GCancellable*" "cancellable")
+  '("GError**" "error")
+ )
+)
+
+(define-vfunc query_info_async
+ (of-object "GFileOutputStream")
+ (return-type "void")
+ (parameters
+  '("const-char*" "attributes")
+  '("int" "io_priority")
+  '("GCancellable*" "cancellable")
+  '("GAsyncReadyCallback" "callback")
+  '("gpointer" "user_data")
+ )
+)
+
+(define-vfunc query_info_finish
+ (of-object "GFileOutputStream")
+ (return-type "GFileInfo*")
+ (parameters
+  '("GAsyncResult*" "res")
+  '("GError**" "error")
+ )
+)
+
+(define-vfunc get_etag
+ (of-object "GFileOutputStream")
+ (return-type "char*")
+)
diff --git a/gio/src/inputstream.ccg b/gio/src/inputstream.ccg
index 1fba3a5..2a34b99 100644
--- a/gio/src/inputstream.ccg
+++ b/gio/src/inputstream.ccg
@@ -19,6 +19,7 @@
 
 #include <gio/gio.h>
 #include <giomm/asyncresult.h>
+#include <giomm/error.h>
 #include "slot_async.h"
 
 namespace Gio
@@ -199,4 +200,213 @@ InputStream::close_async(const SlotAsyncReady& slot, int io_priority)
 }
 
 
+// Virtual functions - hand coded because of exceptions.
+
+gssize InputStream_Class::read_vfunc_callback(GInputStream* self, void* buffer, gsize count, GCancellable* cancellable, GError** error)
+{
+  CppObjectType *const obj = dynamic_cast<CppObjectType*>(
+      Glib::ObjectBase::_get_current_wrapper((GObject*)self));
+
+  if(obj && obj->is_derived_())
+  {
+    #ifdef GLIBMM_EXCEPTIONS_ENABLED
+    try // Trap C++ exceptions which would normally be lost because this is a C callback.
+    {
+      // Call the virtual member method, which derived classes might override.
+      return obj->read_vfunc(buffer, count, Glib::wrap(cancellable));
+    }
+    catch(Gio::Error gerror)
+    {
+      gerror.propagate(error);
+      return -1;
+    }
+    catch(...)
+    {
+      Glib::exception_handlers_invoke();
+    }
+    #else
+      std::auto_ptr<Glib::Error> gerror_ptr;
+      gssize ret = obj->read_vfunc(buffer, count, Glib::wrap(cancellable), gerror_ptr);
+      gerror_ptr->propagate(error);
+      return ret;
+    #endif //GLIBMM_EXCEPTIONS_ENABLED
+  }
+  else
+  {
+    BaseClassType *const base = static_cast<BaseClassType*>(
+      g_type_class_peek_parent(G_OBJECT_GET_CLASS(self)) // Get the parent class of the object class (The original underlying C class).
+  );
+
+    // Call the original underlying C function:
+    if(base && base->read_fn)
+      return (*base->read_fn)(self, buffer, count, cancellable, error);
+  }
+
+  typedef gssize RType;
+  return RType();
+}
+
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+gssize InputStream::read_vfunc(void* buffer, gsize count, const Glib::RefPtr<Cancellable>& cancellable)
+#else
+gssize InputStream::read_vfunc(void* buffer, gsize count, const Glib::RefPtr<Cancellable>& cancellable, std::auto_ptr<Glib::Error>& error)
+#endif //GLIBMM_EXCEPTIONS_ENABLED
+{
+  BaseClassType *const base = static_cast<BaseClassType*>(
+      g_type_class_peek_parent(G_OBJECT_GET_CLASS(gobject_)) // Get the parent class of the object class (The original underlying C class).
+  );
+
+  if(base && base->read_fn)
+  {
+    GError *gerror;
+    gssize ret = (*base->read_fn)(gobj(), buffer, count, cancellable->gobj(), &gerror);
+    if (gerror)
+    #ifdef GLIBMM_EXCEPTIONS_ENABLED
+      ::Glib::Error::throw_exception(gerror);
+    #else
+      error = ::Glib::Error::throw_exception(gerror);
+    #endif //GLIBMM_EXCEPTIONS_ENABLED
+    return ret;
+  }
+}
+
+gssize InputStream_Class::skip_vfunc_callback(GInputStream* self, gsize count, GCancellable* cancellable, GError** error)
+{
+  CppObjectType *const obj = dynamic_cast<CppObjectType*>(
+      Glib::ObjectBase::_get_current_wrapper((GObject*)self));
+
+  if(obj && obj->is_derived_())
+  {
+    #ifdef GLIBMM_EXCEPTIONS_ENABLED
+    try // Trap C++ exceptions which would normally be lost because this is a C callback.
+    {
+      // Call the virtual member method, which derived classes might override.
+      return obj->skip_vfunc(count, Glib::wrap(cancellable));
+    }
+    catch(Gio::Error gerror)
+    {
+      gerror.propagate(error);
+      return -1;
+    }
+    catch(...)
+    {
+      Glib::exception_handlers_invoke();
+    }
+    #else
+      std::auto_ptr<Glib::Error> gerror_ptr;
+      gssize ret = obj->skip_vfunc(count, Glib::wrap(cancellable), gerror_ptr);
+      gerror_ptr->propagate(error);
+      return ret;
+    #endif //GLIBMM_EXCEPTIONS_ENABLED
+  }
+  else
+  {
+    BaseClassType *const base = static_cast<BaseClassType*>(
+      g_type_class_peek_parent(G_OBJECT_GET_CLASS(self)) // Get the parent class of the object class (The original underlying C class).
+  );
+
+    // Call the original underlying C function:
+    if(base && base->skip)
+      return (*base->skip)(self, count, cancellable, error);
+  }
+
+  typedef gssize RType;
+  return RType();
+}
+
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+gssize InputStream::skip_vfunc(gsize count, const Glib::RefPtr<Cancellable>& cancellable)
+#else
+gssize InputStream::skip_vfunc(gsize count, const Glib::RefPtr<Cancellable>& cancellable, std::auto_ptr<Glib::Error>& error)
+#endif //GLIBMM_EXCEPTIONS_ENABLED
+{
+  BaseClassType *const base = static_cast<BaseClassType*>(
+      g_type_class_peek_parent(G_OBJECT_GET_CLASS(gobject_)) // Get the parent class of the object class (The original underlying C class).
+  );
+
+  if(base && base->skip)
+  {
+    GError *gerror;
+    gssize ret = (*base->skip)(gobj(), count, cancellable->gobj(), &gerror);
+    if (gerror)
+    #ifdef GLIBMM_EXCEPTIONS_ENABLED
+      ::Glib::Error::throw_exception(gerror);
+    #else
+      error = ::Glib::Error::throw_exception(gerror);
+    #endif //GLIBMM_EXCEPTIONS_ENABLED
+    return ret;
+  }
+}
+
+gboolean InputStream_Class::close_vfunc_callback(GInputStream* self, GCancellable* cancellable, GError** error)
+{
+  CppObjectType *const obj = dynamic_cast<CppObjectType*>(
+      Glib::ObjectBase::_get_current_wrapper((GObject*)self));
+
+  if(obj && obj->is_derived_())
+  {
+    #ifdef GLIBMM_EXCEPTIONS_ENABLED
+    try // Trap C++ exceptions which would normally be lost because this is a C callback.
+    {
+      // Call the virtual member method, which derived classes might override.
+      obj->close_vfunc(Glib::wrap(cancellable));
+      return TRUE;
+    }
+    catch(Gio::Error gerror)
+    {
+      gerror.propagate(error);
+      return FALSE;
+    }
+    catch(...)
+    {
+      Glib::exception_handlers_invoke();
+    }
+    #else
+      std::auto_ptr<Glib::Error> gerror_ptr;
+      gboolean ret = obj->close_vfunc(Glib::wrap(cancellable), gerror_ptr) ? TRUE : FALSE;
+      gerror_ptr->propagate(error);
+      return ret;
+    #endif //GLIBMM_EXCEPTIONS_ENABLED
+  }
+  else
+  {
+    BaseClassType *const base = static_cast<BaseClassType*>(
+      g_type_class_peek_parent(G_OBJECT_GET_CLASS(self)) // Get the parent class of the object class (The original underlying C class).
+  );
+
+    // Call the original underlying C function:
+    if(base && base->close_fn)
+      return (*base->close_fn)(self, cancellable, error);
+  }
+
+  typedef gssize RType;
+  return RType();
+}
+
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+void InputStream::close_vfunc(const Glib::RefPtr<Cancellable>& cancellable)
+#else
+bool InputStream::close_vfunc(const Glib::RefPtr<Cancellable>& cancellable, std::auto_ptr<Glib::Error>& error)
+#endif //GLIBMM_EXCEPTIONS_ENABLED
+{
+  BaseClassType *const base = static_cast<BaseClassType*>(
+      g_type_class_peek_parent(G_OBJECT_GET_CLASS(gobject_)) // Get the parent class of the object class (The original underlying C class).
+  );
+
+  if(base && base->close_fn)
+  {
+    GError *gerror;
+    #ifdef GLIBMM_EXCEPTIONS_ENABLED
+    (*base->close_fn)(gobj(), cancellable->gobj(), &gerror);
+    if (gerror)
+      ::Glib::Error::throw_exception(gerror);
+    #else
+    gboolean ret = (*base->close_fn)(gobj(), cancellable->gobj(), &gerror);
+    if (gerror)
+      error = ::Glib::Error::throw_exception(gerror);
+    return ret;
+    #endif //GLIBMM_EXCEPTIONS_ENABLED
+  }
+}
+
 } // namespace Gio
diff --git a/gio/src/inputstream.hg b/gio/src/inputstream.hg
index 2c9a5bd..b29a5e5 100644
--- a/gio/src/inputstream.hg
+++ b/gio/src/inputstream.hg
@@ -329,8 +329,42 @@ public:
                g_input_stream_close_finish,
                errthrow)
 
-  // These are private inside the module (for implementations)
-  _IGNORE(g_input_stream_has_pending, g_input_stream_is_closed, g_input_stream_set_pending, g_input_stream_clear_pending)
+  _WRAP_METHOD(bool is_closed(),
+               g_input_stream_is_closed)
+  _WRAP_METHOD(bool has_pending(),
+               g_input_stream_has_pending)
+
+protected:
+  _CTOR_DEFAULT
+  _WRAP_METHOD(bool set_pending(),
+               g_input_stream_set_pending,
+               errthrow)
+  _WRAP_METHOD(void clear_pending(),
+               g_input_stream_clear_pending)
+
+  #ifdef GLIBMM_EXCEPTIONS_ENABLED
+  virtual gssize read_vfunc(void* buffer, gsize count, const Glib::RefPtr<Cancellable>& cancellable);
+  virtual gssize skip_vfunc(gsize count, const Glib::RefPtr<Cancellable>& cancellable);
+  virtual void close_vfunc(const Glib::RefPtr<Cancellable>& cancellable);
+  #else
+  virtual gssize read_vfunc(void* buffer, gsize count, const Glib::RefPtr<Cancellable>& cancellable, std::auto_ptr<Glib::Error>& error);
+  virtual gssize skip_vfunc(gsize count, const Glib::RefPtr<Cancellable>& cancellable, std::auto_ptr<Glib::Error>& error);
+  virtual bool close_vfunc(const Glib::RefPtr<Cancellable>& cancellable, std::auto_ptr<Glib::Error>& error);
+  #endif
+
+#m4begin
+dnl// Virtual functions need to be hand-coded, because of exception handling requirements.
+dnl
+  _PUSH(SECTION_PCC_CLASS_INIT_VFUNCS)
+    klass->read_fn = &read_vfunc_callback;
+    klass->skip = &skip_vfunc_callback;
+    klass->close_fn = &close_vfunc_callback;
+  _SECTION(SECTION_PH_VFUNCS)
+    static gssize read_vfunc_callback(GInputStream* self, void* buffer, gsize count, GCancellable* cancellable, GError** error);
+    static gssize skip_vfunc_callback(GInputStream* self, gsize count, GCancellable* cancellable, GError** error);
+    static gboolean close_vfunc_callback(GInputStream* self, GCancellable* cancellable, GError** error);
+  _POP()
+#m4end
 };
 
 } // namespace Gio
diff --git a/gio/src/memoryoutputstream.ccg b/gio/src/memoryoutputstream.ccg
index 40517b7..e59a6c8 100644
--- a/gio/src/memoryoutputstream.ccg
+++ b/gio/src/memoryoutputstream.ccg
@@ -18,3 +18,18 @@
  */
 
 #include <gio/gio.h>
+#include <giomm/memoryoutputstream.h>
+
+namespace Gio {
+
+MemoryOutputStream::MemoryOutputStream()
+:
+  Gio::OutputStream(g_memory_output_stream_new(0, NULL, g_realloc, g_free))
+{}
+
+MemoryOutputStream::MemoryOutputStream(gpointer data, gsize len, GReallocFunc realloc_fn, GDestroyNotify destroy_fn)
+:
+  Gio::OutputStream(g_memory_output_stream_new(data, len, realloc_fn, destroy_fn))
+{}
+
+} // namespace Gio
diff --git a/gio/src/memoryoutputstream.hg b/gio/src/memoryoutputstream.hg
index cf6276e..fbe6e1b 100644
--- a/gio/src/memoryoutputstream.hg
+++ b/gio/src/memoryoutputstream.hg
@@ -43,16 +43,20 @@ class MemoryOutputStream :
 {
   _CLASS_GOBJECT(MemoryOutputStream, GMemoryOutputStream, G_MEMORY_OUTPUT_STREAM, Gio::OutputStream, GOutputStream)
   _IMPLEMENTS_INTERFACE(Seekable)
-protected:
-  // TODO: more C++-like interface using sigc++
-  _WRAP_CTOR(MemoryOutputStream(gpointer data, gsize len, GReallocFunc realloc_fn, GDestroyNotify destroy), g_memory_output_stream_new)
 
 public:
   // TODO: more C++-like interface using sigc++
   _WRAP_CREATE(gpointer data, gsize len, GReallocFunc realloc_fn, GDestroyNotify destroy)
+  _WRAP_CREATE()
   _WRAP_METHOD(gpointer get_data(), g_memory_output_stream_get_data)
   _WRAP_METHOD(gsize get_size() const, g_memory_output_stream_get_size)
   _WRAP_METHOD(gsize get_data_size() const, g_memory_output_stream_get_data_size)
+
+protected:
+  // TODO: more C++-like interface using sigc++
+  // Note: GMemoryOutputStream dosn't use properties for construction parameters, so we need to make a workaround
+  MemoryOutputStream(gpointer data, gsize len, GReallocFunc realloc_fn, GDestroyNotify destroy);
+  MemoryOutputStream(); // default resizable stream
 };
 
 } // namespace Gio
diff --git a/gio/src/outputstream.ccg b/gio/src/outputstream.ccg
index 70c3171..3505793 100644
--- a/gio/src/outputstream.ccg
+++ b/gio/src/outputstream.ccg
@@ -20,6 +20,7 @@
 #include <gio/gio.h>
 #include <glibmm/error.h>
 #include <glibmm/exceptionhandler.h>
+#include <giomm/error.h>
 #include "slot_async.h"
 
 namespace Gio {
@@ -343,4 +344,286 @@ bool OutputStream::close(std::auto_ptr<Glib::Error>& error)
   return retvalue;
 }
 
+gssize OutputStream_Class::write_vfunc_callback(GOutputStream* self, const void* buffer, gsize count, GCancellable* cancellable, GError** error)
+{
+  CppObjectType *const obj = dynamic_cast<CppObjectType*>(
+      Glib::ObjectBase::_get_current_wrapper((GObject*)self));
+
+  if(obj && obj->is_derived_())
+  {
+    #ifdef GLIBMM_EXCEPTIONS_ENABLED
+    try // Trap C++ exceptions which would normally be lost because this is a C callback.
+    {
+      // Call the virtual member method, which derived classes might override.
+      return obj->write_vfunc(buffer, count, Glib::wrap(cancellable));
+    }
+    catch(Gio::Error gerror)
+    {
+      gerror.propagate(error);
+      return -1;
+    }
+    catch(...)
+    {
+      Glib::exception_handlers_invoke();
+    }
+    #else
+      std::auto_ptr<Glib::Error> gerror_ptr;
+      gssize ret = obj->write_vfunc(buffer, count, Glib::wrap(cancellable), gerror_ptr);
+      gerror_ptr->propagate(error);
+      return ret;
+    #endif //GLIBMM_EXCEPTIONS_ENABLED
+  }
+  else
+  {
+    BaseClassType *const base = static_cast<BaseClassType*>(
+      g_type_class_peek_parent(G_OBJECT_GET_CLASS(self)) // Get the parent class of the object class (The original underlying C class).
+  );
+
+    // Call the original underlying C function:
+    if(base && base->write_fn)
+      return (*base->write_fn)(self, buffer, count, cancellable, error);
+  }
+
+  typedef gssize RType;
+  return RType();
+}
+
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+gssize OutputStream::write_vfunc(const void* buffer, gsize count, const Glib::RefPtr<Cancellable>& cancellable)
+#else
+gssize OutputStream::write_vfunc(const void* buffer, gsize count, const Glib::RefPtr<Cancellable>& cancellable, std::auto_ptr<Glib::Error>& error)
+#endif //GLIBMM_EXCEPTIONS_ENABLED
+{
+  BaseClassType *const base = static_cast<BaseClassType*>(
+      g_type_class_peek_parent(G_OBJECT_GET_CLASS(gobject_)) // Get the parent class of the object class (The original underlying C class).
+  );
+
+  if(base && base->write_fn)
+  {
+    GError *gerror;
+    gssize ret = (*base->write_fn)(gobj(), buffer, count, cancellable->gobj(), &gerror);
+    if (gerror)
+    #ifdef GLIBMM_EXCEPTIONS_ENABLED
+      ::Glib::Error::throw_exception(gerror);
+    #else
+      error = ::Glib::Error::throw_exception(gerror);
+    #endif //GLIBMM_EXCEPTIONS_ENABLED
+    return ret;
+  }
+}
+
+// WARNING: the order of arguments in the C version is different!
+
+gssize OutputStream_Class::splice_vfunc_callback(GOutputStream* self, GInputStream* source, GOutputStreamSpliceFlags flags, GCancellable* cancellable, GError** error)
+{
+  CppObjectType *const obj = dynamic_cast<CppObjectType*>(
+      Glib::ObjectBase::_get_current_wrapper((GObject*)self));
+
+  if(obj && obj->is_derived_())
+  {
+    #ifdef GLIBMM_EXCEPTIONS_ENABLED
+    try // Trap C++ exceptions which would normally be lost because this is a C callback.
+    {
+      // Call the virtual member method, which derived classes might override.
+      return obj->splice_vfunc(Glib::wrap(source), Glib::wrap(cancellable), OutputStreamSpliceFlags(flags));
+    }
+    catch(Gio::Error gerror)
+    {
+      gerror.propagate(error);
+      return -1;
+    }
+    catch(...)
+    {
+      Glib::exception_handlers_invoke();
+    }
+    #else
+      std::auto_ptr<Glib::Error> gerror_ptr;
+      gssize ret = obj->splice_vfunc(Glib::wrap(source), Glib::wrap(cancellable), OutputStreamSpliceFlags(flags), gerror_ptr);
+      gerror_ptr->propagate(error);
+      return ret;
+    #endif //GLIBMM_EXCEPTIONS_ENABLED
+  }
+  else
+  {
+    BaseClassType *const base = static_cast<BaseClassType*>(
+      g_type_class_peek_parent(G_OBJECT_GET_CLASS(self)) // Get the parent class of the object class (The original underlying C class).
+  );
+
+    // Call the original underlying C function:
+    // WARNING: the order of arguments in the C version is different
+    if(base && base->splice)
+      return (*base->splice)(self, source, flags, cancellable, error);
+  }
+
+  typedef gssize RType;
+  return RType();
+}
+
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+gssize OutputStream::splice_vfunc(const Glib::RefPtr<InputStream>& source, const Glib::RefPtr<Cancellable>& cancellable, OutputStreamSpliceFlags flags)
+#else
+gssize OutputStream::splice_vfunc(const Glib::RefPtr<InputStream>& source, const Glib::RefPtr<Cancellable>& cancellable, OutputStreamSpliceFlags flags, std::auto_ptr<Glib::Error>& error)
+#endif //GLIBMM_EXCEPTIONS_ENABLED
+{
+  BaseClassType *const base = static_cast<BaseClassType*>(
+      g_type_class_peek_parent(G_OBJECT_GET_CLASS(gobject_)) // Get the parent class of the object class (The original underlying C class).
+  );
+
+  if(base && base->splice)
+  {
+    // WARNING: the order of arguments in the C version is different
+    GError *gerror;
+    gssize ret = (*base->splice)(gobj(), Glib::unwrap(source), static_cast<GOutputStreamSpliceFlags>(flags), cancellable->gobj(), &gerror);
+    if (gerror)
+    #ifdef GLIBMM_EXCEPTIONS_ENABLED
+      ::Glib::Error::throw_exception(gerror);
+    #else
+      error = ::Glib::Error::throw_exception(gerror);
+    #endif //GLIBMM_EXCEPTIONS_ENABLED
+    return ret;
+  }
+}
+
+gboolean OutputStream_Class::flush_vfunc_callback(GOutputStream* self, GCancellable* cancellable, GError** error)
+{
+  CppObjectType *const obj = dynamic_cast<CppObjectType*>(
+      Glib::ObjectBase::_get_current_wrapper((GObject*)self));
+
+  if(obj && obj->is_derived_())
+  {
+    #ifdef GLIBMM_EXCEPTIONS_ENABLED
+    try // Trap C++ exceptions which would normally be lost because this is a C callback.
+    {
+      // Call the virtual member method, which derived classes might override.
+      obj->flush_vfunc(Glib::wrap(cancellable));
+      return TRUE;
+    }
+    catch(Gio::Error gerror)
+    {
+      gerror.propagate(error);
+      return FALSE;
+    }
+    catch(...)
+    {
+      Glib::exception_handlers_invoke();
+    }
+    #else
+      std::auto_ptr<Glib::Error> gerror_ptr;
+      gboolean ret = obj->flush_vfunc(Glib::wrap(cancellable), gerror_ptr) ? TRUE : FALSE;
+      gerror_ptr->propagate(error);
+      return ret;
+    #endif //GLIBMM_EXCEPTIONS_ENABLED
+  }
+  else
+  {
+    BaseClassType *const base = static_cast<BaseClassType*>(
+      g_type_class_peek_parent(G_OBJECT_GET_CLASS(self)) // Get the parent class of the object class (The original underlying C class).
+  );
+
+    // Call the original underlying C function:
+    if(base && base->flush)
+      return (*base->flush)(self, cancellable, error);
+  }
+
+  typedef gboolean RType;
+  return RType();
+}
+
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+void OutputStream::flush_vfunc(const Glib::RefPtr<Cancellable>& cancellable)
+#else
+bool OutputStream::flush_vfunc(const Glib::RefPtr<Cancellable>& cancellable, std::auto_ptr<Glib::Error>& error)
+#endif //GLIBMM_EXCEPTIONS_ENABLED
+{
+  BaseClassType *const base = static_cast<BaseClassType*>(
+      g_type_class_peek_parent(G_OBJECT_GET_CLASS(gobject_)) // Get the parent class of the object class (The original underlying C class).
+  );
+
+  if(base && base->flush)
+  {
+    GError *gerror;
+    #ifdef GLIBMM_EXCEPTIONS_ENABLED
+    (*base->flush)(gobj(), cancellable->gobj(), &gerror);
+    if (gerror)
+      ::Glib::Error::throw_exception(gerror);
+    #else
+    gboolean ret = (*base->flush)(gobj(), cancellable->gobj(), &gerror);
+    if (gerror)
+      error = ::Glib::Error::throw_exception(gerror);
+    return ret;
+    #endif //GLIBMM_EXCEPTIONS_ENABLED
+  }
+}
+
+gboolean OutputStream_Class::close_vfunc_callback(GOutputStream* self, GCancellable* cancellable, GError** error)
+{
+  CppObjectType *const obj = dynamic_cast<CppObjectType*>(
+      Glib::ObjectBase::_get_current_wrapper((GObject*)self));
+
+  if(obj && obj->is_derived_())
+  {
+    #ifdef GLIBMM_EXCEPTIONS_ENABLED
+    try // Trap C++ exceptions which would normally be lost because this is a C callback.
+    {
+      // Call the virtual member method, which derived classes might override.
+      obj->close_vfunc(Glib::wrap(cancellable));
+      return TRUE;
+    }
+    catch(Gio::Error gerror)
+    {
+      gerror.propagate(error);
+      return FALSE;
+    }
+    catch(...)
+    {
+      Glib::exception_handlers_invoke();
+    }
+    #else
+      std::auto_ptr<Glib::Error> gerror_ptr;
+      gboolean ret = obj->close_vfunc(Glib::wrap(cancellable), gerror_ptr) ? TRUE : FALSE;
+      gerror_ptr->propagate(error);
+      return ret;
+    #endif //GLIBMM_EXCEPTIONS_ENABLED
+  }
+  else
+  {
+    BaseClassType *const base = static_cast<BaseClassType*>(
+      g_type_class_peek_parent(G_OBJECT_GET_CLASS(self)) // Get the parent class of the object class (The original underlying C class).
+  );
+
+    // Call the original underlying C function:
+    if(base && base->close_fn)
+      return (*base->close_fn)(self, cancellable, error);
+  }
+
+  typedef gssize RType;
+  return RType();
+}
+
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+void OutputStream::close_vfunc(const Glib::RefPtr<Cancellable>& cancellable)
+#else
+bool OutputStream::close_vfunc(const Glib::RefPtr<Cancellable>& cancellable, std::auto_ptr<Glib::Error>& error)
+#endif //GLIBMM_EXCEPTIONS_ENABLED
+{
+  BaseClassType *const base = static_cast<BaseClassType*>(
+      g_type_class_peek_parent(G_OBJECT_GET_CLASS(gobject_)) // Get the parent class of the object class (The original underlying C class).
+  );
+
+  if(base && base->close_fn)
+  {
+    GError *gerror;
+    #ifdef GLIBMM_EXCEPTIONS_ENABLED
+    (*base->close_fn)(gobj(), cancellable->gobj(), &gerror);
+    if (gerror)
+      ::Glib::Error::throw_exception(gerror);
+    #else
+    gboolean ret = (*base->close_fn)(gobj(), cancellable->gobj(), &gerror);
+    if (gerror)
+      error = ::Glib::Error::throw_exception(gerror);
+    return ret;
+    #endif //GLIBMM_EXCEPTIONS_ENABLED
+  }
+}
+
 } // namespace Gio
diff --git a/gio/src/outputstream.hg b/gio/src/outputstream.hg
index 00699fa..73cdc63 100644
--- a/gio/src/outputstream.hg
+++ b/gio/src/outputstream.hg
@@ -24,6 +24,7 @@
 
 _DEFS(giomm,gio)
 _PINCLUDE(glibmm/private/object_p.h)
+_PINCLUDE(gio/gio.h) // for GOutputStreamSpliceFlags
 
 namespace Gio
 {
@@ -447,9 +448,46 @@ public:
                g_output_stream_close_finish,
                errthrow)
 
-  // These are private inside the module (for implementations)
-  _IGNORE(g_output_stream_has_pending, g_output_stream_is_closed, g_output_stream_set_pending, g_output_stream_clear_pending)
+  _WRAP_METHOD(bool is_closed(),
+               g_output_stream_is_closed)
+  _WRAP_METHOD(bool has_pending(),
+               g_output_stream_has_pending)
 
+protected:
+  _CTOR_DEFAULT
+  _WRAP_METHOD(bool set_pending(),
+               g_output_stream_set_pending,
+               errthrow)
+  _WRAP_METHOD(void clear_pending(),
+               g_output_stream_clear_pending)
+
+  #ifdef GLIBMM_EXCEPTIONS_ENABLED
+  virtual gssize write_vfunc(const void* buffer, gsize count, const Glib::RefPtr<Cancellable>& cancellable);
+  virtual gssize splice_vfunc(const Glib::RefPtr<InputStream>& source, const Glib::RefPtr<Cancellable>& cancellable, OutputStreamSpliceFlags flags);
+  virtual void flush_vfunc(const Glib::RefPtr<Cancellable>& cancellable);
+  virtual void close_vfunc(const Glib::RefPtr<Cancellable>& cancellable);
+  #else
+  virtual gssize write_vfunc(const void* buffer, gsize count, const Glib::RefPtr<Cancellable>& cancellable, std::auto_ptr<Glib::Error>& error);
+  virtual gssize splice_vfunc(const Glib::RefPtr<InputStream>& source, const Glib::RefPtr<Cancellable>& cancellable, OutputStreamSpliceFlags flags, std::auto_ptr<Glib::Error>& error);
+  virtual bool flush_vfunc(const Glib::RefPtr<Cancellable>& cancellable, std::auto_ptr<Glib::Error>& error);
+  virtual bool close_vfunc(const Glib::RefPtr<Cancellable>& cancellable, std::auto_ptr<Glib::Error>& error);
+  #endif
+
+#m4begin
+dnl// Virtual functions need to be hand-coded, because of exception handling requirements.
+dnl
+  _PUSH(SECTION_PCC_CLASS_INIT_VFUNCS)
+    klass->write_fn = &write_vfunc_callback;
+    klass->splice = &splice_vfunc_callback;
+    klass->flush = &flush_vfunc_callback;
+    klass->close_fn = &close_vfunc_callback;
+  _SECTION(SECTION_PH_VFUNCS)
+    static gssize write_vfunc_callback(GOutputStream* self, const void* buffer, gsize count, GCancellable* cancellable, GError** error);
+    static gssize splice_vfunc_callback(GOutputStream* self, GInputStream *source, GOutputStreamSpliceFlags flags, GCancellable* cancellable, GError** error);
+    static gboolean flush_vfunc_callback(GOutputStream* self, GCancellable* cancellable, GError** error);
+    static gboolean close_vfunc_callback(GOutputStream* self, GCancellable* cancellable, GError** error);
+  _POP()
+#m4end
 };
 
 } // namespace Gio
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 6be2346..aff310a 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -20,6 +20,7 @@ AUTOMAKE_OPTIONS = subdir-objects
 check_PROGRAMS =			\
 	giomm_ioerror/test		\
 	giomm_simple/test		\
+    giomm_stream_vfuncs/test	\
 	glibmm_date/test		\
 	glibmm_nodetree/test		\
 	glibmm_ustring_compose/test	\
@@ -39,10 +40,12 @@ local_libgiomm  = $(top_builddir)/gio/giomm/libgiomm-$(GIOMM_API_VERSION).la
 LDADD = $(GLIBMM_LIBS) $(local_libglibmm)
 giomm_ldadd = $(GIOMM_LIBS) $(local_libglibmm) $(local_libgiomm)
 
-giomm_ioerror_test_SOURCES = giomm_ioerror/main.cc
-giomm_ioerror_test_LDADD   = $(giomm_ldadd)
-giomm_simple_test_SOURCES  = giomm_simple/main.cc
-giomm_simple_test_LDADD    = $(giomm_ldadd)
+giomm_ioerror_test_SOURCES  = giomm_ioerror/main.cc
+giomm_ioerror_test_LDADD    = $(giomm_ldadd)
+giomm_simple_test_SOURCES   = giomm_simple/main.cc
+giomm_simple_test_LDADD     = $(giomm_ldadd)
+giomm_stream_vfuncs_test_SOURCES = giomm_stream_vfuncs/main.cc
+giomm_stream_vfuncs_test_LDADD   = $(giomm_ldadd)
 
 glibmm_date_test_SOURCES            = glibmm_date/main.cc
 glibmm_nodetree_test_SOURCES        = glibmm_nodetree/main.cc
diff --git a/tests/giomm_stream_vfuncs/main.cc b/tests/giomm_stream_vfuncs/main.cc
new file mode 100644
index 0000000..175c952
--- /dev/null
+++ b/tests/giomm_stream_vfuncs/main.cc
@@ -0,0 +1,142 @@
+#include <glib.h>
+#include <giomm.h>
+#include <iostream>
+#include <string.h>
+
+// for now this test only does anything when exceptions are enabled,
+// because I am too lazy to write the no-exceptions version.
+#ifdef GLIBMM_EXCEPTIONS_ENABLED
+
+// A simple custom stream that base64 encodes data.
+// Do not copy it to your code, because it's very slow.
+class Base64OutputStream : public Gio::FilterOutputStream
+{
+public:
+  unsigned get_column_width() const { return column_width; }
+  void set_column_width(unsigned cw) { column_width = cw; }
+  static Glib::RefPtr<Base64OutputStream> create(const Glib::RefPtr<OutputStream>& base_stream)
+  {
+    return Glib::RefPtr<Base64OutputStream>(new Base64OutputStream(base_stream));
+  }
+protected:
+  Base64OutputStream(const Glib::RefPtr<Gio::OutputStream>& base_stream)
+    : Gio::FilterOutputStream(base_stream), column(0), bit_count(0), bit_buffer(0), column_width(72) {}
+  virtual gssize write_vfunc(const void* buffer, gsize count, const Glib::RefPtr<Gio::Cancellable>& cancellable)
+  {
+    char const *byte = (char const *) buffer;
+    for (unsigned i = 0; i < count; ++i, ++byte)
+    {
+      // kindergarten implementation, because the object is not performance :)
+      bit_buffer <<= 8;
+      bit_buffer |= (*byte & 0xff);
+      bit_count += 8;
+
+      if (bit_count == 24) {
+        clear_pending(); // TODO why is this necessary to avoid an outstanding op. exception?
+        flush(cancellable);
+        set_pending();
+        bit_count = 0;
+      }
+
+      if (cancellable && cancellable->is_cancelled()) throw Gio::Error(Gio::Error::CANCELLED, "Operation cancelled");
+    }
+    return count;
+  }
+
+  virtual void flush_vfunc(const Glib::RefPtr<Gio::Cancellable>& cancellable)
+  {
+    if (bit_count != 24) return;
+    char to_write[5];
+    gsize len = 4;
+    
+    for (unsigned i=0; i<4; ++i)
+    {
+      unsigned index = (bit_buffer & (0x3f<<(i*6))) >> (i*6);
+      to_write[3-i] = base64_encode_str[index];
+    }
+    column += 4;
+    // Yes, I know this is completely wrong.
+    if (column >= column_width) {
+      column = 0;
+      to_write[4] = '\n';
+      ++len;
+    }
+
+    get_base_stream()->write(&to_write, len, cancellable);
+    
+    bit_count = 0;
+    bit_buffer = 0;
+  }
+  virtual void close_vfunc(const Glib::RefPtr<Gio::Cancellable>& cancellable)
+  {
+    char to_write[5] = "====";
+    //get any last bytes (1 or 2) out of the buffer
+    switch (bit_count)
+    {
+    case 16:
+      bit_buffer <<= 2;  //pad to make 18 bits
+      to_write[0] = base64_encode_str[(bit_buffer & (0x3f << 12)) >> 12];
+      to_write[1] = base64_encode_str[(bit_buffer & (0x3f << 6)) >> 6];
+      to_write[2] = base64_encode_str[bit_buffer & 0x3f];
+
+    case 8:
+      bit_buffer <<= 4; //pad to make 12 bits
+      to_write[0] = base64_encode_str[(bit_buffer & (0x3f << 6)) >> 6];
+      to_write[1] = base64_encode_str[bit_buffer & 0x3f];
+    }
+
+    if (bit_count > 0) {
+      get_base_stream()->write(&to_write, 5, cancellable);
+    } else {
+      // null terminate output
+      get_base_stream()->write("", 1, cancellable);
+    }
+    if (get_close_base_stream()) get_base_stream()->close(cancellable);
+  }
+
+private:
+  static char const *const base64_encode_str;
+  unsigned column;
+  unsigned bit_count;
+  unsigned bit_buffer;
+  unsigned column_width;
+};
+
+char const *const Base64OutputStream::base64_encode_str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+int main(int, char**)
+{
+  Glib::init();
+  Gio::init();
+
+  try {
+  char result[256];
+  Glib::RefPtr<Gio::MemoryOutputStream> memory_chunk = Gio::MemoryOutputStream::create(result, 256, NULL, NULL);
+  Glib::RefPtr<Base64OutputStream> base64 = Base64OutputStream::create(memory_chunk);
+
+  std::string data = "Custom GIO streams are cool!";
+
+  base64->set_close_base_stream(true);
+  base64->write(data);
+  base64->close();
+
+  std::cout << "Original data:       " << data << std::endl;
+  std::cout << "base64-encoded data: " << result << std::endl;
+  std::cout << "base64 should be:    " << "Q3VzdG9tIEdJTyBzdHJlYW1zIGFyZSBjb29sIQ==" << std::endl;
+  } catch (Gio::Error e) {
+  std::cout << "Gio error: " << e.what() << std::endl;
+  }
+
+  return 0;
+}
+
+#else
+
+int main()
+{
+  std::cout << "Exceptions not enabled - nothing done" << std::endl;
+  return 0;
+}
+
+#endif
+
