2010-07-22 10:25:14 +00:00
// This code is in the public domain -- Ignacio Casta<74> o <castano@gmail.com>
2012-04-30 23:02:23 +00:00
//#pragma once
//#ifndef NV_CORE_STDSTREAM_H
//#define NV_CORE_STDSTREAM_H
2010-07-22 10:25:14 +00:00
# include "nvcore.h"
# include "Stream.h"
2011-01-08 04:54:06 +00:00
# include "Array.h"
2010-07-22 10:25:14 +00:00
# include <stdio.h> // fopen
# include <string.h> // memcpy
namespace nv
{
// Portable version of fopen.
inline FILE * fileOpen ( const char * fileName , const char * mode )
{
nvCheck ( fileName ! = NULL ) ;
# if NV_CC_MSVC && _MSC_VER >= 1400
FILE * fp ;
if ( fopen_s ( & fp , fileName , mode ) = = 0 ) {
return fp ;
}
return NULL ;
# else
return fopen ( fileName , mode ) ;
# endif
}
/// Base stdio stream.
class NVCORE_CLASS StdStream : public Stream
{
NV_FORBID_COPY ( StdStream ) ;
public :
/// Ctor.
2014-11-04 17:49:29 +00:00
StdStream ( FILE * fp , bool autoclose ) : m_fp ( fp ) , m_autoclose ( autoclose ) { }
2010-07-22 10:25:14 +00:00
/// Dtor.
virtual ~ StdStream ( )
{
if ( m_fp ! = NULL & & m_autoclose ) {
2010-10-06 02:56:35 +00:00
# if NV_OS_WIN32
2010-07-22 10:25:14 +00:00
_fclose_nolock ( m_fp ) ;
2010-10-06 02:56:35 +00:00
# else
fclose ( m_fp ) ;
# endif
2010-07-22 10:25:14 +00:00
}
}
/** @name Stream implementation. */
//@{
virtual void seek ( uint pos )
{
nvDebugCheck ( m_fp ! = NULL ) ;
2010-10-21 18:47:27 +00:00
nvDebugCheck ( pos < = size ( ) ) ;
2010-10-06 02:56:35 +00:00
# if NV_OS_WIN32
2010-07-22 10:25:14 +00:00
_fseek_nolock ( m_fp , pos , SEEK_SET ) ;
2010-10-06 02:56:35 +00:00
# else
fseek ( m_fp , pos , SEEK_SET ) ;
# endif
2010-07-22 10:25:14 +00:00
}
virtual uint tell ( ) const
{
nvDebugCheck ( m_fp ! = NULL ) ;
2010-10-06 02:56:35 +00:00
# if NV_OS_WIN32
2010-07-22 10:25:14 +00:00
return _ftell_nolock ( m_fp ) ;
2010-10-06 02:56:35 +00:00
# else
2011-09-27 17:48:46 +00:00
return ( uint ) ftell ( m_fp ) ;
2010-10-06 02:56:35 +00:00
# endif
2010-07-22 10:25:14 +00:00
}
virtual uint size ( ) const
{
nvDebugCheck ( m_fp ! = NULL ) ;
2010-10-06 02:56:35 +00:00
# if NV_OS_WIN32
uint pos = _ftell_nolock ( m_fp ) ;
2010-07-22 10:25:14 +00:00
_fseek_nolock ( m_fp , 0 , SEEK_END ) ;
2010-10-06 02:56:35 +00:00
uint end = _ftell_nolock ( m_fp ) ;
2010-07-22 10:25:14 +00:00
_fseek_nolock ( m_fp , pos , SEEK_SET ) ;
2010-10-06 02:56:35 +00:00
# else
2011-09-27 17:48:46 +00:00
uint pos = ( uint ) ftell ( m_fp ) ;
2010-10-06 02:56:35 +00:00
fseek ( m_fp , 0 , SEEK_END ) ;
2011-09-27 17:48:46 +00:00
uint end = ( uint ) ftell ( m_fp ) ;
2012-02-14 16:16:27 +00:00
fseek ( m_fp , pos , SEEK_SET ) ;
2010-10-06 02:56:35 +00:00
# endif
2010-07-22 10:25:14 +00:00
return end ;
}
virtual bool isError ( ) const
{
return m_fp = = NULL | | ferror ( m_fp ) ! = 0 ;
}
virtual void clearError ( )
{
nvDebugCheck ( m_fp ! = NULL ) ;
clearerr ( m_fp ) ;
}
2013-06-07 17:53:55 +00:00
// @@ The original implementation uses feof, which only returns true when we attempt to read *past* the end of the stream.
// That is, if we read the last byte of a file, then isAtEnd would still return false, even though the stream pointer is at the file end. This is not the intent and was inconsistent with the implementation of the MemoryStream, a better
// implementation uses use ftell and fseek to determine our location within the file.
2010-07-22 10:25:14 +00:00
virtual bool isAtEnd ( ) const
{
2014-11-04 17:49:29 +00:00
if ( m_fp = = NULL ) return true ;
//nvDebugCheck(m_fp != NULL);
2013-06-07 17:53:55 +00:00
//return feof( m_fp ) != 0;
# if NV_OS_WIN32
uint pos = _ftell_nolock ( m_fp ) ;
_fseek_nolock ( m_fp , 0 , SEEK_END ) ;
uint end = _ftell_nolock ( m_fp ) ;
_fseek_nolock ( m_fp , pos , SEEK_SET ) ;
# else
uint pos = ( uint ) ftell ( m_fp ) ;
fseek ( m_fp , 0 , SEEK_END ) ;
uint end = ( uint ) ftell ( m_fp ) ;
fseek ( m_fp , pos , SEEK_SET ) ;
# endif
return pos = = end ;
2010-07-22 10:25:14 +00:00
}
/// Always true.
virtual bool isSeekable ( ) const { return true ; }
//@}
protected :
FILE * m_fp ;
bool m_autoclose ;
} ;
/// Standard output stream.
class NVCORE_CLASS StdOutputStream : public StdStream
{
NV_FORBID_COPY ( StdOutputStream ) ;
public :
/// Construct stream by file name.
2014-11-04 17:49:29 +00:00
StdOutputStream ( const char * name ) : StdStream ( fileOpen ( name , " wb " ) , /*autoclose=*/ true ) { }
2010-07-22 10:25:14 +00:00
/// Construct stream by file handle.
2014-11-04 17:49:29 +00:00
StdOutputStream ( FILE * fp , bool autoclose ) : StdStream ( fp , autoclose )
2010-07-22 10:25:14 +00:00
{
}
/** @name Stream implementation. */
//@{
/// Write data.
virtual uint serialize ( void * data , uint len )
{
nvDebugCheck ( data ! = NULL ) ;
nvDebugCheck ( m_fp ! = NULL ) ;
2010-10-06 02:56:35 +00:00
# if NV_OS_WIN32
2010-07-22 10:25:14 +00:00
return ( uint ) _fwrite_nolock ( data , 1 , len , m_fp ) ;
2010-10-06 02:56:35 +00:00
# elif NV_OS_LINUX
return ( uint ) fwrite_unlocked ( data , 1 , len , m_fp ) ;
# elif NV_OS_DARWIN
// @@ No error checking, always returns len.
for ( uint i = 0 ; i < len ; i + + ) {
putc_unlocked ( ( ( char * ) data ) [ i ] , m_fp ) ;
}
return len ;
# else
return ( uint ) fwrite ( data , 1 , len , m_fp ) ;
# endif
2010-07-22 10:25:14 +00:00
}
virtual bool isLoading ( ) const
{
return false ;
}
virtual bool isSaving ( ) const
{
return true ;
}
//@}
} ;
/// Standard input stream.
class NVCORE_CLASS StdInputStream : public StdStream
{
NV_FORBID_COPY ( StdInputStream ) ;
public :
/// Construct stream by file name.
2014-11-04 17:49:29 +00:00
StdInputStream ( const char * name ) : StdStream ( fileOpen ( name , " rb " ) , /*autoclose=*/ true ) { }
2010-07-22 10:25:14 +00:00
/// Construct stream by file handle.
StdInputStream ( FILE * fp , bool autoclose = true ) : StdStream ( fp , autoclose )
{
}
/** @name Stream implementation. */
//@{
/// Read data.
virtual uint serialize ( void * data , uint len )
{
nvDebugCheck ( data ! = NULL ) ;
nvDebugCheck ( m_fp ! = NULL ) ;
2010-10-06 02:56:35 +00:00
# if NV_OS_WIN32
2010-07-22 10:25:14 +00:00
return ( uint ) _fread_nolock ( data , 1 , len , m_fp ) ;
2010-10-06 02:56:35 +00:00
# elif NV_OS_LINUX
return ( uint ) fread_unlocked ( data , 1 , len , m_fp ) ;
# elif NV_OS_DARWIN
// @@ No error checking, always returns len.
for ( uint i = 0 ; i < len ; i + + ) {
( ( char * ) data ) [ i ] = getc_unlocked ( m_fp ) ;
}
return len ;
# else
return ( uint ) fread ( data , 1 , len , m_fp ) ;
# endif
2010-07-22 10:25:14 +00:00
}
virtual bool isLoading ( ) const
{
return true ;
}
virtual bool isSaving ( ) const
{
return false ;
}
//@}
} ;
/// Memory input stream.
class NVCORE_CLASS MemoryInputStream : public Stream
{
NV_FORBID_COPY ( MemoryInputStream ) ;
public :
/// Ctor.
MemoryInputStream ( const uint8 * mem , uint size ) : m_mem ( mem ) , m_ptr ( mem ) , m_size ( size ) { }
/** @name Stream implementation. */
//@{
/// Read data.
virtual uint serialize ( void * data , uint len )
{
nvDebugCheck ( data ! = NULL ) ;
nvDebugCheck ( ! isError ( ) ) ;
uint left = m_size - tell ( ) ;
if ( len > left ) len = left ;
memcpy ( data , m_ptr , len ) ;
m_ptr + = len ;
return len ;
}
virtual void seek ( uint pos )
{
nvDebugCheck ( ! isError ( ) ) ;
m_ptr = m_mem + pos ;
nvDebugCheck ( ! isError ( ) ) ;
}
virtual uint tell ( ) const
{
nvDebugCheck ( m_ptr > = m_mem ) ;
return uint ( m_ptr - m_mem ) ;
}
virtual uint size ( ) const
{
return m_size ;
}
virtual bool isError ( ) const
{
return m_mem = = NULL | | m_ptr > m_mem + m_size | | m_ptr < m_mem ;
}
virtual void clearError ( )
{
// Nothing to do.
}
virtual bool isAtEnd ( ) const
{
return m_ptr = = m_mem + m_size ;
}
/// Always true.
virtual bool isSeekable ( ) const
{
return true ;
}
virtual bool isLoading ( ) const
{
return true ;
}
virtual bool isSaving ( ) const
{
return false ;
}
//@}
2011-04-06 02:41:15 +00:00
const uint8 * ptr ( ) const { return m_ptr ; }
2010-07-22 10:25:14 +00:00
private :
const uint8 * m_mem ;
const uint8 * m_ptr ;
uint m_size ;
} ;
2011-01-08 04:54:06 +00:00
/// Buffer output stream.
class NVCORE_CLASS BufferOutputStream : public Stream
{
NV_FORBID_COPY ( BufferOutputStream ) ;
public :
BufferOutputStream ( Array < uint8 > & buffer ) : m_buffer ( buffer ) { }
virtual uint serialize ( void * data , uint len )
{
nvDebugCheck ( data ! = NULL ) ;
m_buffer . append ( ( uint8 * ) data , len ) ;
return len ;
}
2012-02-14 16:16:27 +00:00
virtual void seek ( uint /*pos*/ ) { /*Not implemented*/ }
2011-01-08 04:54:06 +00:00
virtual uint tell ( ) const { return m_buffer . size ( ) ; }
virtual uint size ( ) const { return m_buffer . size ( ) ; }
virtual bool isError ( ) const { return false ; }
virtual void clearError ( ) { }
virtual bool isAtEnd ( ) const { return true ; }
virtual bool isSeekable ( ) const { return false ; }
virtual bool isLoading ( ) const { return false ; }
virtual bool isSaving ( ) const { return true ; }
private :
Array < uint8 > & m_buffer ;
} ;
2010-07-22 10:25:14 +00:00
/// Protected input stream.
class NVCORE_CLASS ProtectedStream : public Stream
{
NV_FORBID_COPY ( ProtectedStream ) ;
public :
/// Ctor.
ProtectedStream ( Stream & s ) : m_s ( & s ) , m_autodelete ( false )
{
}
/// Ctor.
ProtectedStream ( Stream * s , bool autodelete = true ) :
m_s ( s ) , m_autodelete ( autodelete )
{
nvDebugCheck ( m_s ! = NULL ) ;
}
/// Dtor.
virtual ~ ProtectedStream ( )
{
if ( m_autodelete ) {
delete m_s ;
}
}
/** @name Stream implementation. */
//@{
/// Read data.
virtual uint serialize ( void * data , uint len )
{
nvDebugCheck ( data ! = NULL ) ;
len = m_s - > serialize ( data , len ) ;
if ( m_s - > isError ( ) ) {
2012-04-30 23:02:23 +00:00
throw ;
2010-07-22 10:25:14 +00:00
}
return len ;
}
virtual void seek ( uint pos )
{
m_s - > seek ( pos ) ;
if ( m_s - > isError ( ) ) {
2012-04-30 23:02:23 +00:00
throw ;
2010-07-22 10:25:14 +00:00
}
}
virtual uint tell ( ) const
{
return m_s - > tell ( ) ;
}
virtual uint size ( ) const
{
return m_s - > size ( ) ;
}
virtual bool isError ( ) const
{
return m_s - > isError ( ) ;
}
virtual void clearError ( )
{
m_s - > clearError ( ) ;
}
virtual bool isAtEnd ( ) const
{
return m_s - > isAtEnd ( ) ;
}
virtual bool isSeekable ( ) const
{
return m_s - > isSeekable ( ) ;
}
virtual bool isLoading ( ) const
{
return m_s - > isLoading ( ) ;
}
virtual bool isSaving ( ) const
{
return m_s - > isSaving ( ) ;
}
//@}
private :
Stream * const m_s ;
bool const m_autodelete ;
} ;
} // nv namespace
2012-04-30 23:02:23 +00:00
//#endif // NV_CORE_STDSTREAM_H