/* Copyright (C) 2001-2006, William Joseph. All Rights Reserved. This file is part of GtkRadiant. GtkRadiant is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. GtkRadiant is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GtkRadiant; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #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; InputStreamType& m_inputStream; byte_type m_buffer[SIZE]; byte_type* m_cur; byte_type* m_end; public: SingleByteInputStream( InputStreamType& inputStream ) : m_inputStream( inputStream ), m_cur( m_buffer + SIZE ), m_end( m_cur ){ } bool readByte( byte_type& b ){ if ( m_cur == m_end ) { if ( m_end != m_buffer + SIZE ) { return false; } m_end = m_buffer + m_inputStream.read( m_buffer, SIZE ); 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