Index: trunk/src/io/std_stream.cc
===================================================================
--- trunk/src/io/std_stream.cc	(revision 134)
+++ trunk/src/io/std_stream.cc	(revision 134)
@@ -0,0 +1,61 @@
+// Copyright (C) 2012-2013 ChaosForge / Kornel Kisielewicz
+// http://chaosforge.org/
+//
+// This file is part of NV Libraries.
+// For conditions of distribution and use, see copyright notice in nv.hh
+
+#include "nv/io/std_stream.hh"
+#include <algorithm>
+#include <cstring> // TODO: remove, see below
+
+using namespace nv;
+
+std_stream::std_stream( stream* source, bool owner /*= false*/, std::size_t bsize /*= 256*/, std::size_t put_back /*= 8 */ )
+	: m_stream( source )
+	, m_owner( owner )
+	, m_put_back( std::max( put_back, std::size_t( 1 ) ) )
+	, m_buffer( std::max(bsize, put_back) + put_back )
+{
+	char *end = &m_buffer.front() + m_buffer.size();
+	setg( end, end, end );
+}
+
+std_stream::~std_stream()
+{
+	if ( m_owner )
+	{
+		delete m_stream;
+	}
+}
+
+std_stream::int_type std_stream::underflow()
+{
+	if (gptr() < egptr())
+	{
+		// buffer not exhausted
+		return traits_type::to_int_type(*gptr());
+	}
+
+	char *base = &m_buffer.front();
+	char *start = base;
+
+	if (eback() == base) // true when this isn't the first fill
+	{
+		// Make arrangements for putback characters
+		// TODO: std::copy( egptr() - m_put_back, egptr(), base ); instead?
+		std::memmove(base, egptr() - m_put_back, m_put_back);
+		start += m_put_back;
+	}
+
+	// start is now the start of the buffer, proper.
+	size_t n = m_stream->read( start, 1, m_buffer.size() - (start - base) );
+	if (n == 0)
+	{
+		return traits_type::eof();
+	}
+
+	// Set buffer pointers
+	setg(base, start, start + n);
+
+	return traits_type::to_int_type(*gptr());
+}
