Index: /trunk/legacy/std_stream.cc
===================================================================
--- /trunk/legacy/std_stream.cc	(revision 442)
+++ /trunk/legacy/std_stream.cc	(revision 442)
@@ -0,0 +1,62 @@
+// Copyright (C) 2012-2015 ChaosForge Ltd
+// http://chaosforge.org/
+//
+// This file is part of Nova libraries. 
+// For conditions of distribution and use, see copying.txt file in root folder.
+//
+// TODO: support for write operations, see http://www.mr-edd.co.uk/blog/beginners_guide_streambuf
+
+#include "nv/io/std_stream.hh"
+#include "nv/stl/math.hh"
+#include "nv/stl/utility.hh"
+
+using namespace nv;
+
+std_streambuf::std_streambuf( stream* source, bool owner /*= false*/, std::size_t bsize /*= 256*/, std::size_t put_back /*= 8 */ )
+	: m_stream( source )
+	, m_owner( owner )
+	, m_buffer( nv::max(bsize, put_back) + put_back )
+	, m_put_back( nv::max( put_back, std::size_t( 1 ) ) )
+{
+	char *end = &m_buffer.front() + m_buffer.size();
+	setg( end, end, end );
+}
+
+std_streambuf::~std_streambuf()
+{
+	if ( m_owner )
+	{
+		delete m_stream;
+	}
+}
+
+std_streambuf::int_type std_streambuf::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
+		std::copy( egptr() - m_put_back, egptr(), base ); 
+		start += m_put_back;
+	}
+
+	// start is now the start of the buffer, proper.
+	size_t n = m_stream->read( start, 1, m_buffer.size() - static_cast<size_t>(start - base) );
+	if (n == 0)
+	{
+		return traits_type::eof();
+	}
+
+	// Set buffer pointers
+	setg(base, start, start + n);
+
+	return traits_type::to_int_type(*gptr());
+}
Index: /trunk/legacy/std_stream.hh
===================================================================
--- /trunk/legacy/std_stream.hh	(revision 442)
+++ /trunk/legacy/std_stream.hh	(revision 442)
@@ -0,0 +1,54 @@
+// Copyright (C) 2012-2015 ChaosForge Ltd
+// http://chaosforge.org/
+//
+// This file is part of Nova libraries. 
+// For conditions of distribution and use, see copying.txt file in root folder.
+
+/**
+ * @file std_stream.hh
+ * @author Kornel Kisielewicz epyon@chaosforge.org
+ * @brief stream adapter for usage with STL
+ */
+
+#ifndef NV_IO_STD_STREAM_HH
+#define NV_IO_STD_STREAM_HH
+
+#include <nv/common.hh>
+#include <nv/stl/stream.hh>
+#include <streambuf>
+#include <istream>
+#include <vector>
+
+namespace nv
+{
+
+	class std_streambuf : public std::streambuf
+	{
+	public:
+		explicit std_streambuf( stream* source, bool owner = false, std::size_t bsize = 256, std::size_t put_back = 8 );
+		virtual ~std_streambuf();
+	protected:
+		stream*           m_stream;
+		bool              m_owner;
+		std::vector<char> m_buffer;
+		std::size_t       m_put_back;
+	private:
+		std_streambuf( const std_streambuf& );             // dissalow copy
+		std_streambuf *operator =( const std_streambuf& ); // dissalow assign
+		int_type underflow();
+	};
+
+	class std_stream : public std::istream
+	{
+	public:
+		explicit std_stream( stream* source, bool owner = false, std::size_t bsize = 256, std::size_t put_back = 8 )
+			: std::istream( &m_streambuf )
+			, m_streambuf( source, owner, bsize, put_back ) 
+		{}
+	private:
+		std_streambuf m_streambuf;
+	};
+
+} // namespace nv
+
+#endif // NV_IO_STD_STREAM_HH
Index: /trunk/nv/base/capi.hh
===================================================================
--- /trunk/nv/base/capi.hh	(revision 441)
+++ /trunk/nv/base/capi.hh	(revision 442)
@@ -102,4 +102,5 @@
 	inline void* nvmemcpy( void *dest, const void *src, size_t count )
 	{
+		NV_ASSERT( dest && src, "Bad parameter to nvmemcpy!" );
 		if ( dest == src ) return dest;
 		return NV_CAPI_CALL( memcpy )( dest, src, count );
@@ -108,4 +109,5 @@
 	inline void* nvmemmove( void *dest, const void *src, size_t count )
 	{
+		NV_ASSERT( dest && src, "Bad parameter to nvmemmove!" );
 		if ( dest == src ) return dest;
 		return NV_CAPI_CALL( memmove )( dest, src, count );
@@ -114,4 +116,5 @@
 	inline void* nvmemset( void *dest, unsigned char value, size_t count )
 	{
+		NV_ASSERT( dest, "Bad parameter to nvmemset!" );
 		return NV_CAPI_CALL( memset )( dest, static_cast<int>( value ), count );
 	}
@@ -119,4 +122,5 @@
 	inline void* nvmemchr( const void *src, unsigned char value, size_t max_count )
 	{
+		NV_ASSERT( src, "Bad parameter to nvmemchr!" );
 		return NV_CAPI_CALL( memchr )( src, static_cast<int>( value ), max_count );
 	}
@@ -124,4 +128,5 @@
 	inline int nvmemcmp( const void * m1, const void * m2, nv::size_t max_count )
 	{
+		NV_ASSERT( m1 && m2, "Bad parameter to nvmemcmp!" );
 		return NV_CAPI_CALL( memcmp )( m1, m2, max_count );
 	}
@@ -129,4 +134,5 @@
 	inline int nvstrcmp( const char * s1, const char * s2 )
 	{
+		NV_ASSERT( s1 && s2, "Bad parameter to nvstrcmp!" );
 		return NV_CAPI_CALL( strcmp )( s1, s2 );
 	}	
Index: /trunk/nv/gui/gui_element.hh
===================================================================
--- /trunk/nv/gui/gui_element.hh	(revision 441)
+++ /trunk/nv/gui/gui_element.hh	(revision 442)
@@ -19,5 +19,4 @@
 #include <nv/stl/string.hh>
 #include <nv/gui/gui_common.hh>
-#include <list>
 
 namespace nv
Index: /trunk/nv/io/c_stream.hh
===================================================================
--- /trunk/nv/io/c_stream.hh	(revision 441)
+++ /trunk/nv/io/c_stream.hh	(revision 442)
@@ -32,4 +32,5 @@
 		virtual size_t read( void* buffer, size_t size, size_t count );
 		virtual size_t write( const void* buffer, size_t size, size_t count );
+		virtual bool gets( char* buffer, size_t max_count );
 		virtual bool seek( long offset, origin orig );
 		virtual size_t tell();
Index: unk/nv/io/std_stream.hh
===================================================================
--- /trunk/nv/io/std_stream.hh	(revision 441)
+++ 	(revision )
@@ -1,54 +1,0 @@
-// Copyright (C) 2012-2015 ChaosForge Ltd
-// http://chaosforge.org/
-//
-// This file is part of Nova libraries. 
-// For conditions of distribution and use, see copying.txt file in root folder.
-
-/**
- * @file std_stream.hh
- * @author Kornel Kisielewicz epyon@chaosforge.org
- * @brief stream adapter for usage with STL
- */
-
-#ifndef NV_IO_STD_STREAM_HH
-#define NV_IO_STD_STREAM_HH
-
-#include <nv/common.hh>
-#include <nv/stl/stream.hh>
-#include <streambuf>
-#include <istream>
-#include <vector>
-
-namespace nv
-{
-
-	class std_streambuf : public std::streambuf
-	{
-	public:
-		explicit std_streambuf( stream* source, bool owner = false, std::size_t bsize = 256, std::size_t put_back = 8 );
-		virtual ~std_streambuf();
-	protected:
-		stream*           m_stream;
-		bool              m_owner;
-		std::vector<char> m_buffer;
-		std::size_t       m_put_back;
-	private:
-		std_streambuf( const std_streambuf& );             // dissalow copy
-		std_streambuf *operator =( const std_streambuf& ); // dissalow assign
-		int_type underflow();
-	};
-
-	class std_stream : public std::istream
-	{
-	public:
-		explicit std_stream( stream* source, bool owner = false, std::size_t bsize = 256, std::size_t put_back = 8 )
-			: std::istream( &m_streambuf )
-			, m_streambuf( source, owner, bsize, put_back ) 
-		{}
-	private:
-		std_streambuf m_streambuf;
-	};
-
-} // namespace nv
-
-#endif // NV_IO_STD_STREAM_HH
Index: /trunk/nv/stl/algorithm.hh
===================================================================
--- /trunk/nv/stl/algorithm.hh	(revision 441)
+++ /trunk/nv/stl/algorithm.hh	(revision 442)
@@ -63,5 +63,5 @@
 			for ( ForwardIterator it = first2; it != last2; ++it )
 				if ( *first1 == *it )
-					break;
+					return ( first1 );
 		return ( first1 );
 	}
@@ -73,5 +73,5 @@
 			for ( ForwardIterator it = first2; it != last2; ++it )
 				if ( comp_op( *first1, *it ) )
-					break;
+					return ( first1 );
 		return ( first1 );
 	}
Index: /trunk/nv/stl/stream.hh
===================================================================
--- /trunk/nv/stl/stream.hh	(revision 441)
+++ /trunk/nv/stl/stream.hh	(revision 442)
@@ -34,4 +34,5 @@
 		virtual size_t read( void* buffer, size_t size, size_t count ) = 0;
 		virtual size_t write( const void* buffer, size_t size, size_t count ) = 0;
+		virtual bool gets( char* buffer, size_t max_count ) = 0;
 		virtual bool seek( long offset, origin orig ) = 0;
 		virtual size_t tell() = 0;
Index: /trunk/nv/stl/string/short_string.hh
===================================================================
--- /trunk/nv/stl/string/short_string.hh	(revision 441)
+++ /trunk/nv/stl/string/short_string.hh	(revision 442)
@@ -59,4 +59,5 @@
 		size_t append( const char* data, size_t sz )
 		{
+			if ( !data ) return 0;
 			size_t pos    = size();
 			size_t amount = expand_by( sz );
Index: /trunk/nv/stl/string/string_base.hh
===================================================================
--- /trunk/nv/stl/string/string_base.hh	(revision 441)
+++ /trunk/nv/stl/string/string_base.hh	(revision 442)
@@ -74,4 +74,6 @@
 		// string operations
 		string_view substr( size_type p, size_type n = npos ) const;
+		string_view without_prefix( size_type p ) const;
+		string_view without_suffix( size_type p ) const;
 
 		template < typename H = size_type >
@@ -278,4 +280,21 @@
 		return string_view( this->data() + p, n );
 	}
+
+	template < typename Storage >
+	inline string_view string_base< Storage >::without_prefix( size_type p ) const
+	{
+		string_view result( this->data(), this->size() );
+		result.remove_prefix( p );
+		return result;
+	}
+
+	template < typename Storage >
+	inline string_view string_base< Storage >::without_suffix( size_type p ) const
+	{
+		string_view result( this->data(), this->size() );
+		result.remove_suffix( p );
+		return result;
+	}
+
 
 #define NV_STRING_BASE_CAST_OPERATORS( OPERATOR )\
Index: /trunk/src/formats/nmd_loader.cc
===================================================================
--- /trunk/src/formats/nmd_loader.cc	(revision 441)
+++ /trunk/src/formats/nmd_loader.cc	(revision 442)
@@ -6,5 +6,4 @@
 
 #include "nv/formats/nmd_loader.hh"
-#include "nv/io/std_stream.hh"
 #include "nv/stl/string.hh"
 #include "nv/interface/data_channel_access.hh"
Index: /trunk/src/formats/obj_loader.cc
===================================================================
--- /trunk/src/formats/obj_loader.cc	(revision 441)
+++ /trunk/src/formats/obj_loader.cc	(revision 442)
@@ -6,8 +6,7 @@
 
 #include "nv/formats/obj_loader.hh"
-#include "nv/io/std_stream.hh"
 #include "nv/interface/data_channel_access.hh"
 
-#include <sstream>
+#include <cstdio>
 
 using namespace nv;
@@ -50,8 +49,6 @@
 	vector< vec2 > t;
 
-	std::string line;
-	std::string cmd;
-	std::string name;
-	std::string next_name;
+	string32 name;
+	string32 next_name;
 
 	nv::size_t size;
@@ -59,5 +56,5 @@
 
 	obj_reader();
-	bool read_stream( std::istream& stream );
+	bool read_stream( stream& str );
 	virtual nv::size_t add_face( uint32* vi, uint32* ti, uint32* ni, nv::size_t count ) = 0;
 	virtual nv::size_t raw_size() const = 0;
@@ -79,46 +76,45 @@
 }
 
-bool obj_reader::read_stream( std::istream& stream )
-{
-	name = next_name;
+bool obj_reader::read_stream( stream& str )
+{
+	name.assign( next_name );
 	bool added_faces = false;
 	f32 x, y, z;
 	if ( eof ) return false;
-
-	while ( std::getline( stream, line ) )
-	{
-		if ( line.length() < 3 || line[0] == '#' )
-		{
-			continue;
-		}
-
-		std::istringstream ss(line);
-		ss >> cmd;
-
-		if ( cmd == "v" )
-		{
-			ss >> x >> y >> z;
+	char buffer[256];
+	while ( str.gets( buffer, 256 ) )
+	{
+		string_view cline( static_cast<const char*>( buffer ) );
+		cline = nv::trimmed( cline );
+
+		if ( cline.length() < 3 || cline[0] == '#' )
+		{
+			continue;
+		}
+
+		if ( cline.starts_with( "vn " ) )
+		{
+			sscanf( cline.data(), "vn %f %f %f", &x, &y, &z );
+			n.push_back( vec3( x, y, z ) );
+			continue;
+		}
+
+		if ( cline.starts_with( "vt " ) )
+		{
+			sscanf( cline.data(), "vt %f %f", &x, &y );
+			t.push_back( vec2( x, 1.0f - y ) );
+			continue;
+		}
+
+		if ( cline.starts_with( "v " ) )
+		{
+			sscanf( cline.data(), "v %f %f %f", &x, &y, &z );
 			v.push_back( vec3( x, y, z ) );
 			continue;
 		}
 
-		if ( cmd == "vn" )
-		{
-			ss >> x >> y >> z;
-			n.push_back( vec3( x, y, z ) );
-			continue;
-		}
-
-		if ( cmd == "vt" )
-		{
-			ss >> x >> y;
-			t.push_back( vec2( x, 1.0f - y ) );
-			continue;
-		}
-
-		if ( cmd == "f" )
+		if ( cline.starts_with( "f " ) )
 		{
 			added_faces = true;
-			ss >> cmd;
 
 			uint32 vis[8];
@@ -128,19 +124,25 @@
 			uint32 count = 0;
 
-			while ( !ss.fail() )
+			string_view scan( cline );
+			scan.remove_prefix( 2 );
+			size_t pos = 0;
+			while ( pos != string_view::npos )
 			{
-				char ch;
-
-				std::istringstream ss2( cmd );
-				ss2 >> vis[count] >> ch;
-				ss2 >> tis[count] >> ch;
-				if ( ch == '/')
+				scan.remove_prefix( pos );
+				scan = nv::trimmed( scan );
+				if ( sscanf( scan.data(), "%u/%u/%u", &vis[count], &tis[count], &nis[count] ) == 3 )
 				{
 					normals = true;
-					ss2 >> nis[count];
 				}
-
-				ss >> cmd;
+				else if ( !normals && sscanf( scan.data(), "%u/%u", &vis[count], &tis[count] ) == 2 )
+				{
+
+				}
+				else
+				{
+					break;
+				}
 				count++;
+				pos = scan.find_first_of( "\t " );
 			}
 
@@ -149,14 +151,14 @@
 		}
 
-		if ( cmd == "g" )
-		{
-			ss >> next_name;
+		if ( cline.starts_with( "g " ) )
+		{
+			next_name.assign( nv::trimmed( cline.without_prefix( 2 ) ) );
 			if (added_faces) 
 				return true;
-			name = next_name;
-			continue;
-		}
-
-		if ( cmd == "s" )
+			name.assign( next_name );
+			continue;
+		}
+
+		if ( cline.starts_with( "s " ) )
 		{
 			continue;
@@ -317,7 +319,5 @@
 	else
 		reader = new mesh_data_reader_vt();
-	std_stream sstream( &source );
-
-	while ( reader->read_stream( sstream ) )
+	while ( reader->read_stream( source ) )
 	{
 		if ( m_tangents )
@@ -328,5 +328,5 @@
 		data_channel_set* result = data_channel_set_creator::create_set( 1 );
 		data_channel_set_creator raccess( result );
-		raccess.set_name( make_name( reader->name.c_str() ) );
+		raccess.set_name( make_name( reader->name ) );
 		uint8* rdata = raccess.add_channel( m_descriptor, reader->size * 3 ).raw_data();
 
Index: /trunk/src/io/c_stream.cc
===================================================================
--- /trunk/src/io/c_stream.cc	(revision 441)
+++ /trunk/src/io/c_stream.cc	(revision 442)
@@ -47,4 +47,12 @@
 }
 
+bool c_stream::gets( char* buffer, size_t max_count )
+{
+	NV_ASSERT( buffer != nullptr && max_count != 0, "Bad parameter passed to write!" );
+	char* result = ::fgets( buffer, max_count, reinterpret_cast<FILE*>( m_file ) );
+	if ( !result ) return false;
+	return true;
+}
+
 bool c_stream::seek( long offset, origin orig )
 {
Index: unk/src/io/std_stream.cc
===================================================================
--- /trunk/src/io/std_stream.cc	(revision 441)
+++ 	(revision )
@@ -1,62 +1,0 @@
-// Copyright (C) 2012-2015 ChaosForge Ltd
-// http://chaosforge.org/
-//
-// This file is part of Nova libraries. 
-// For conditions of distribution and use, see copying.txt file in root folder.
-//
-// TODO: support for write operations, see http://www.mr-edd.co.uk/blog/beginners_guide_streambuf
-
-#include "nv/io/std_stream.hh"
-#include "nv/stl/math.hh"
-#include "nv/stl/utility.hh"
-
-using namespace nv;
-
-std_streambuf::std_streambuf( stream* source, bool owner /*= false*/, std::size_t bsize /*= 256*/, std::size_t put_back /*= 8 */ )
-	: m_stream( source )
-	, m_owner( owner )
-	, m_buffer( nv::max(bsize, put_back) + put_back )
-	, m_put_back( nv::max( put_back, std::size_t( 1 ) ) )
-{
-	char *end = &m_buffer.front() + m_buffer.size();
-	setg( end, end, end );
-}
-
-std_streambuf::~std_streambuf()
-{
-	if ( m_owner )
-	{
-		delete m_stream;
-	}
-}
-
-std_streambuf::int_type std_streambuf::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
-		std::copy( egptr() - m_put_back, egptr(), base ); 
-		start += m_put_back;
-	}
-
-	// start is now the start of the buffer, proper.
-	size_t n = m_stream->read( start, 1, m_buffer.size() - static_cast<size_t>(start - base) );
-	if (n == 0)
-	{
-		return traits_type::eof();
-	}
-
-	// Set buffer pointers
-	setg(base, start, start + n);
-
-	return traits_type::to_int_type(*gptr());
-}
Index: /trunk/src/stl/string.cc
===================================================================
--- /trunk/src/stl/string.cc	(revision 441)
+++ /trunk/src/stl/string.cc	(revision 442)
@@ -11,6 +11,4 @@
 #include <cstdio>
 #include <cstdlib>
-#include <fstream> // for slurp only
-#include <sstream> // for slurp only
 
 using namespace nv;
