#if !defined ( INCLUDED_ARCHIVELIB_H ) #define INCLUDED_ARCHIVELIB_H #include "debugging/debugging.h" #include "iarchive.h" #include "stream/filestream.h" #include "stream/textfilestream.h" #include "memory/allocator.h" #include "string/string.h" /// \brief A single-byte-reader wrapper around an InputStream. /// Optimised for reading one byte at a time. /// Uses a buffer to reduce the number of times the wrapped stream must be read. template class SingleByteInputStream { typedef typename InputStreamType::byte_type byte_type; enum { c_bufferSize = SIZE }; InputStreamType& m_inputStream; byte_type m_buffer[c_bufferSize]; byte_type* m_cur; byte_type* m_end; public: SingleByteInputStream( InputStreamType& inputStream ) : m_inputStream( inputStream ), m_cur( m_buffer + c_bufferSize ), m_end( m_cur ){ } bool readByte( byte_type& b ){ if ( m_cur == m_end ) { if ( m_end != m_buffer + c_bufferSize ) { return false; } m_end = m_buffer + m_inputStream.read( m_buffer, c_bufferSize ); m_cur = m_buffer; if ( m_end == m_buffer ) { return false; } } b = *m_cur++; return true; } }; /// \brief A binary-to-text wrapper around an InputStream. /// Converts CRLF or LFCR line-endings to LF line-endings. template class BinaryToTextInputStream : public TextInputStream { SingleByteInputStream m_inputStream; public: BinaryToTextInputStream( BinaryInputStreamType& inputStream ) : m_inputStream( inputStream ){ } std::size_t read( char* buffer, std::size_t length ){ char* p = buffer; for (;; ) { if ( length != 0 && m_inputStream.readByte( *reinterpret_cast( p ) ) ) { if ( *p != '\r' ) { ++p; --length; } } else { return p - buffer; } } } }; /// \brief An ArchiveFile which is stored uncompressed as part of a larger archive file. class StoredArchiveFile : public ArchiveFile { CopiedString m_name; FileInputStream m_filestream; SubFileInputStream m_substream; FileInputStream::size_type m_size; public: typedef FileInputStream::size_type size_type; typedef FileInputStream::position_type position_type; StoredArchiveFile( const char* name, const char* archiveName, position_type position, size_type stream_size, size_type file_size ) : m_name( name ), m_filestream( archiveName ), m_substream( m_filestream, position, stream_size ), m_size( file_size ){ } static StoredArchiveFile* create( const char* name, const char* archiveName, position_type position, size_type stream_size, size_type file_size ){ return New().scalar( name, archiveName, position, stream_size, file_size ); } void release(){ Delete().scalar( this ); } size_type size() const { return m_size; } const char* getName() const { return m_name.c_str(); } InputStream& getInputStream(){ return m_substream; } }; /// \brief An ArchiveTextFile which is stored uncompressed as part of a larger archive file. class StoredArchiveTextFile : public ArchiveTextFile { CopiedString m_name; FileInputStream m_filestream; SubFileInputStream m_substream; BinaryToTextInputStream m_textStream; public: typedef FileInputStream::size_type size_type; typedef FileInputStream::position_type position_type; StoredArchiveTextFile( const char* name, const char* archiveName, position_type position, size_type stream_size ) : m_name( name ), m_filestream( archiveName ), m_substream( m_filestream, position, stream_size ), m_textStream( m_substream ){ } static StoredArchiveTextFile* create( const char* name, const char* archiveName, position_type position, size_type stream_size ){ return New().scalar( name, archiveName, position, stream_size ); } void release(){ Delete().scalar( this ); } const char* getName() const { return m_name.c_str(); } TextInputStream& getInputStream(){ return m_textStream; } }; /// \brief An ArchiveFile which is stored as a single file on disk. class DirectoryArchiveFile : public ArchiveFile { CopiedString m_name; FileInputStream m_istream; FileInputStream::size_type m_size; public: typedef FileInputStream::size_type size_type; DirectoryArchiveFile( const char* name, const char* filename ) : m_name( name ), m_istream( filename ){ if ( !failed() ) { m_istream.seek( 0, FileInputStream::end ); m_size = m_istream.tell(); m_istream.seek( 0 ); } else { m_size = 0; } } bool failed() const { return m_istream.failed(); } void release(){ delete this; } size_type size() const { return m_size; } const char* getName() const { return m_name.c_str(); } InputStream& getInputStream(){ return m_istream; } }; /// \brief An ArchiveTextFile which is stored as a single file on disk. class DirectoryArchiveTextFile : public ArchiveTextFile { CopiedString m_name; TextFileInputStream m_inputStream; public: DirectoryArchiveTextFile( const char* name, const char* filename ) : m_name( name ), m_inputStream( filename ){ } bool failed() const { return m_inputStream.failed(); } void release(){ delete this; } const char* getName() const { return m_name.c_str(); } TextInputStream& getInputStream(){ return m_inputStream; } }; #endif