mirror of
https://github.com/autc04/Retro68.git
synced 2024-12-04 16:50:57 +00:00
467 lines
12 KiB
C
467 lines
12 KiB
C
|
/*
|
||
|
* A C++ I/O streams interface to the zlib gz* functions
|
||
|
*
|
||
|
* by Ludwig Schwardt <schwardt@sun.ac.za>
|
||
|
* original version by Kevin Ruland <kevin@rodin.wustl.edu>
|
||
|
*
|
||
|
* This version is standard-compliant and compatible with gcc 3.x.
|
||
|
*/
|
||
|
|
||
|
#ifndef ZFSTREAM_H
|
||
|
#define ZFSTREAM_H
|
||
|
|
||
|
#include <istream> // not iostream, since we don't need cin/cout
|
||
|
#include <ostream>
|
||
|
#include "zlib.h"
|
||
|
|
||
|
/*****************************************************************************/
|
||
|
|
||
|
/**
|
||
|
* @brief Gzipped file stream buffer class.
|
||
|
*
|
||
|
* This class implements basic_filebuf for gzipped files. It doesn't yet support
|
||
|
* seeking (allowed by zlib but slow/limited), putback and read/write access
|
||
|
* (tricky). Otherwise, it attempts to be a drop-in replacement for the standard
|
||
|
* file streambuf.
|
||
|
*/
|
||
|
class gzfilebuf : public std::streambuf
|
||
|
{
|
||
|
public:
|
||
|
// Default constructor.
|
||
|
gzfilebuf();
|
||
|
|
||
|
// Destructor.
|
||
|
virtual
|
||
|
~gzfilebuf();
|
||
|
|
||
|
/**
|
||
|
* @brief Set compression level and strategy on the fly.
|
||
|
* @param comp_level Compression level (see zlib.h for allowed values)
|
||
|
* @param comp_strategy Compression strategy (see zlib.h for allowed values)
|
||
|
* @return Z_OK on success, Z_STREAM_ERROR otherwise.
|
||
|
*
|
||
|
* Unfortunately, these parameters cannot be modified separately, as the
|
||
|
* previous zfstream version assumed. Since the strategy is seldom changed,
|
||
|
* it can default and setcompression(level) then becomes like the old
|
||
|
* setcompressionlevel(level).
|
||
|
*/
|
||
|
int
|
||
|
setcompression(int comp_level,
|
||
|
int comp_strategy = Z_DEFAULT_STRATEGY);
|
||
|
|
||
|
/**
|
||
|
* @brief Check if file is open.
|
||
|
* @return True if file is open.
|
||
|
*/
|
||
|
bool
|
||
|
is_open() const { return (file != NULL); }
|
||
|
|
||
|
/**
|
||
|
* @brief Open gzipped file.
|
||
|
* @param name File name.
|
||
|
* @param mode Open mode flags.
|
||
|
* @return @c this on success, NULL on failure.
|
||
|
*/
|
||
|
gzfilebuf*
|
||
|
open(const char* name,
|
||
|
std::ios_base::openmode mode);
|
||
|
|
||
|
/**
|
||
|
* @brief Attach to already open gzipped file.
|
||
|
* @param fd File descriptor.
|
||
|
* @param mode Open mode flags.
|
||
|
* @return @c this on success, NULL on failure.
|
||
|
*/
|
||
|
gzfilebuf*
|
||
|
attach(int fd,
|
||
|
std::ios_base::openmode mode);
|
||
|
|
||
|
/**
|
||
|
* @brief Close gzipped file.
|
||
|
* @return @c this on success, NULL on failure.
|
||
|
*/
|
||
|
gzfilebuf*
|
||
|
close();
|
||
|
|
||
|
protected:
|
||
|
/**
|
||
|
* @brief Convert ios open mode int to mode string used by zlib.
|
||
|
* @return True if valid mode flag combination.
|
||
|
*/
|
||
|
bool
|
||
|
open_mode(std::ios_base::openmode mode,
|
||
|
char* c_mode) const;
|
||
|
|
||
|
/**
|
||
|
* @brief Number of characters available in stream buffer.
|
||
|
* @return Number of characters.
|
||
|
*
|
||
|
* This indicates number of characters in get area of stream buffer.
|
||
|
* These characters can be read without accessing the gzipped file.
|
||
|
*/
|
||
|
virtual std::streamsize
|
||
|
showmanyc();
|
||
|
|
||
|
/**
|
||
|
* @brief Fill get area from gzipped file.
|
||
|
* @return First character in get area on success, EOF on error.
|
||
|
*
|
||
|
* This actually reads characters from gzipped file to stream
|
||
|
* buffer. Always buffered.
|
||
|
*/
|
||
|
virtual int_type
|
||
|
underflow();
|
||
|
|
||
|
/**
|
||
|
* @brief Write put area to gzipped file.
|
||
|
* @param c Extra character to add to buffer contents.
|
||
|
* @return Non-EOF on success, EOF on error.
|
||
|
*
|
||
|
* This actually writes characters in stream buffer to
|
||
|
* gzipped file. With unbuffered output this is done one
|
||
|
* character at a time.
|
||
|
*/
|
||
|
virtual int_type
|
||
|
overflow(int_type c = traits_type::eof());
|
||
|
|
||
|
/**
|
||
|
* @brief Installs external stream buffer.
|
||
|
* @param p Pointer to char buffer.
|
||
|
* @param n Size of external buffer.
|
||
|
* @return @c this on success, NULL on failure.
|
||
|
*
|
||
|
* Call setbuf(0,0) to enable unbuffered output.
|
||
|
*/
|
||
|
virtual std::streambuf*
|
||
|
setbuf(char_type* p,
|
||
|
std::streamsize n);
|
||
|
|
||
|
/**
|
||
|
* @brief Flush stream buffer to file.
|
||
|
* @return 0 on success, -1 on error.
|
||
|
*
|
||
|
* This calls underflow(EOF) to do the job.
|
||
|
*/
|
||
|
virtual int
|
||
|
sync();
|
||
|
|
||
|
//
|
||
|
// Some future enhancements
|
||
|
//
|
||
|
// virtual int_type uflow();
|
||
|
// virtual int_type pbackfail(int_type c = traits_type::eof());
|
||
|
// virtual pos_type
|
||
|
// seekoff(off_type off,
|
||
|
// std::ios_base::seekdir way,
|
||
|
// std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out);
|
||
|
// virtual pos_type
|
||
|
// seekpos(pos_type sp,
|
||
|
// std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out);
|
||
|
|
||
|
private:
|
||
|
/**
|
||
|
* @brief Allocate internal buffer.
|
||
|
*
|
||
|
* This function is safe to call multiple times. It will ensure
|
||
|
* that a proper internal buffer exists if it is required. If the
|
||
|
* buffer already exists or is external, the buffer pointers will be
|
||
|
* reset to their original state.
|
||
|
*/
|
||
|
void
|
||
|
enable_buffer();
|
||
|
|
||
|
/**
|
||
|
* @brief Destroy internal buffer.
|
||
|
*
|
||
|
* This function is safe to call multiple times. It will ensure
|
||
|
* that the internal buffer is deallocated if it exists. In any
|
||
|
* case, it will also reset the buffer pointers.
|
||
|
*/
|
||
|
void
|
||
|
disable_buffer();
|
||
|
|
||
|
/**
|
||
|
* Underlying file pointer.
|
||
|
*/
|
||
|
gzFile file;
|
||
|
|
||
|
/**
|
||
|
* Mode in which file was opened.
|
||
|
*/
|
||
|
std::ios_base::openmode io_mode;
|
||
|
|
||
|
/**
|
||
|
* @brief True if this object owns file descriptor.
|
||
|
*
|
||
|
* This makes the class responsible for closing the file
|
||
|
* upon destruction.
|
||
|
*/
|
||
|
bool own_fd;
|
||
|
|
||
|
/**
|
||
|
* @brief Stream buffer.
|
||
|
*
|
||
|
* For simplicity this remains allocated on the free store for the
|
||
|
* entire life span of the gzfilebuf object, unless replaced by setbuf.
|
||
|
*/
|
||
|
char_type* buffer;
|
||
|
|
||
|
/**
|
||
|
* @brief Stream buffer size.
|
||
|
*
|
||
|
* Defaults to system default buffer size (typically 8192 bytes).
|
||
|
* Modified by setbuf.
|
||
|
*/
|
||
|
std::streamsize buffer_size;
|
||
|
|
||
|
/**
|
||
|
* @brief True if this object owns stream buffer.
|
||
|
*
|
||
|
* This makes the class responsible for deleting the buffer
|
||
|
* upon destruction.
|
||
|
*/
|
||
|
bool own_buffer;
|
||
|
};
|
||
|
|
||
|
/*****************************************************************************/
|
||
|
|
||
|
/**
|
||
|
* @brief Gzipped file input stream class.
|
||
|
*
|
||
|
* This class implements ifstream for gzipped files. Seeking and putback
|
||
|
* is not supported yet.
|
||
|
*/
|
||
|
class gzifstream : public std::istream
|
||
|
{
|
||
|
public:
|
||
|
// Default constructor
|
||
|
gzifstream();
|
||
|
|
||
|
/**
|
||
|
* @brief Construct stream on gzipped file to be opened.
|
||
|
* @param name File name.
|
||
|
* @param mode Open mode flags (forced to contain ios::in).
|
||
|
*/
|
||
|
explicit
|
||
|
gzifstream(const char* name,
|
||
|
std::ios_base::openmode mode = std::ios_base::in);
|
||
|
|
||
|
/**
|
||
|
* @brief Construct stream on already open gzipped file.
|
||
|
* @param fd File descriptor.
|
||
|
* @param mode Open mode flags (forced to contain ios::in).
|
||
|
*/
|
||
|
explicit
|
||
|
gzifstream(int fd,
|
||
|
std::ios_base::openmode mode = std::ios_base::in);
|
||
|
|
||
|
/**
|
||
|
* Obtain underlying stream buffer.
|
||
|
*/
|
||
|
gzfilebuf*
|
||
|
rdbuf() const
|
||
|
{ return const_cast<gzfilebuf*>(&sb); }
|
||
|
|
||
|
/**
|
||
|
* @brief Check if file is open.
|
||
|
* @return True if file is open.
|
||
|
*/
|
||
|
bool
|
||
|
is_open() { return sb.is_open(); }
|
||
|
|
||
|
/**
|
||
|
* @brief Open gzipped file.
|
||
|
* @param name File name.
|
||
|
* @param mode Open mode flags (forced to contain ios::in).
|
||
|
*
|
||
|
* Stream will be in state good() if file opens successfully;
|
||
|
* otherwise in state fail(). This differs from the behavior of
|
||
|
* ifstream, which never sets the state to good() and therefore
|
||
|
* won't allow you to reuse the stream for a second file unless
|
||
|
* you manually clear() the state. The choice is a matter of
|
||
|
* convenience.
|
||
|
*/
|
||
|
void
|
||
|
open(const char* name,
|
||
|
std::ios_base::openmode mode = std::ios_base::in);
|
||
|
|
||
|
/**
|
||
|
* @brief Attach to already open gzipped file.
|
||
|
* @param fd File descriptor.
|
||
|
* @param mode Open mode flags (forced to contain ios::in).
|
||
|
*
|
||
|
* Stream will be in state good() if attach succeeded; otherwise
|
||
|
* in state fail().
|
||
|
*/
|
||
|
void
|
||
|
attach(int fd,
|
||
|
std::ios_base::openmode mode = std::ios_base::in);
|
||
|
|
||
|
/**
|
||
|
* @brief Close gzipped file.
|
||
|
*
|
||
|
* Stream will be in state fail() if close failed.
|
||
|
*/
|
||
|
void
|
||
|
close();
|
||
|
|
||
|
private:
|
||
|
/**
|
||
|
* Underlying stream buffer.
|
||
|
*/
|
||
|
gzfilebuf sb;
|
||
|
};
|
||
|
|
||
|
/*****************************************************************************/
|
||
|
|
||
|
/**
|
||
|
* @brief Gzipped file output stream class.
|
||
|
*
|
||
|
* This class implements ofstream for gzipped files. Seeking and putback
|
||
|
* is not supported yet.
|
||
|
*/
|
||
|
class gzofstream : public std::ostream
|
||
|
{
|
||
|
public:
|
||
|
// Default constructor
|
||
|
gzofstream();
|
||
|
|
||
|
/**
|
||
|
* @brief Construct stream on gzipped file to be opened.
|
||
|
* @param name File name.
|
||
|
* @param mode Open mode flags (forced to contain ios::out).
|
||
|
*/
|
||
|
explicit
|
||
|
gzofstream(const char* name,
|
||
|
std::ios_base::openmode mode = std::ios_base::out);
|
||
|
|
||
|
/**
|
||
|
* @brief Construct stream on already open gzipped file.
|
||
|
* @param fd File descriptor.
|
||
|
* @param mode Open mode flags (forced to contain ios::out).
|
||
|
*/
|
||
|
explicit
|
||
|
gzofstream(int fd,
|
||
|
std::ios_base::openmode mode = std::ios_base::out);
|
||
|
|
||
|
/**
|
||
|
* Obtain underlying stream buffer.
|
||
|
*/
|
||
|
gzfilebuf*
|
||
|
rdbuf() const
|
||
|
{ return const_cast<gzfilebuf*>(&sb); }
|
||
|
|
||
|
/**
|
||
|
* @brief Check if file is open.
|
||
|
* @return True if file is open.
|
||
|
*/
|
||
|
bool
|
||
|
is_open() { return sb.is_open(); }
|
||
|
|
||
|
/**
|
||
|
* @brief Open gzipped file.
|
||
|
* @param name File name.
|
||
|
* @param mode Open mode flags (forced to contain ios::out).
|
||
|
*
|
||
|
* Stream will be in state good() if file opens successfully;
|
||
|
* otherwise in state fail(). This differs from the behavior of
|
||
|
* ofstream, which never sets the state to good() and therefore
|
||
|
* won't allow you to reuse the stream for a second file unless
|
||
|
* you manually clear() the state. The choice is a matter of
|
||
|
* convenience.
|
||
|
*/
|
||
|
void
|
||
|
open(const char* name,
|
||
|
std::ios_base::openmode mode = std::ios_base::out);
|
||
|
|
||
|
/**
|
||
|
* @brief Attach to already open gzipped file.
|
||
|
* @param fd File descriptor.
|
||
|
* @param mode Open mode flags (forced to contain ios::out).
|
||
|
*
|
||
|
* Stream will be in state good() if attach succeeded; otherwise
|
||
|
* in state fail().
|
||
|
*/
|
||
|
void
|
||
|
attach(int fd,
|
||
|
std::ios_base::openmode mode = std::ios_base::out);
|
||
|
|
||
|
/**
|
||
|
* @brief Close gzipped file.
|
||
|
*
|
||
|
* Stream will be in state fail() if close failed.
|
||
|
*/
|
||
|
void
|
||
|
close();
|
||
|
|
||
|
private:
|
||
|
/**
|
||
|
* Underlying stream buffer.
|
||
|
*/
|
||
|
gzfilebuf sb;
|
||
|
};
|
||
|
|
||
|
/*****************************************************************************/
|
||
|
|
||
|
/**
|
||
|
* @brief Gzipped file output stream manipulator class.
|
||
|
*
|
||
|
* This class defines a two-argument manipulator for gzofstream. It is used
|
||
|
* as base for the setcompression(int,int) manipulator.
|
||
|
*/
|
||
|
template<typename T1, typename T2>
|
||
|
class gzomanip2
|
||
|
{
|
||
|
public:
|
||
|
// Allows insertor to peek at internals
|
||
|
template <typename Ta, typename Tb>
|
||
|
friend gzofstream&
|
||
|
operator<<(gzofstream&,
|
||
|
const gzomanip2<Ta,Tb>&);
|
||
|
|
||
|
// Constructor
|
||
|
gzomanip2(gzofstream& (*f)(gzofstream&, T1, T2),
|
||
|
T1 v1,
|
||
|
T2 v2);
|
||
|
private:
|
||
|
// Underlying manipulator function
|
||
|
gzofstream&
|
||
|
(*func)(gzofstream&, T1, T2);
|
||
|
|
||
|
// Arguments for manipulator function
|
||
|
T1 val1;
|
||
|
T2 val2;
|
||
|
};
|
||
|
|
||
|
/*****************************************************************************/
|
||
|
|
||
|
// Manipulator function thunks through to stream buffer
|
||
|
inline gzofstream&
|
||
|
setcompression(gzofstream &gzs, int l, int s = Z_DEFAULT_STRATEGY)
|
||
|
{
|
||
|
(gzs.rdbuf())->setcompression(l, s);
|
||
|
return gzs;
|
||
|
}
|
||
|
|
||
|
// Manipulator constructor stores arguments
|
||
|
template<typename T1, typename T2>
|
||
|
inline
|
||
|
gzomanip2<T1,T2>::gzomanip2(gzofstream &(*f)(gzofstream &, T1, T2),
|
||
|
T1 v1,
|
||
|
T2 v2)
|
||
|
: func(f), val1(v1), val2(v2)
|
||
|
{ }
|
||
|
|
||
|
// Insertor applies underlying manipulator function to stream
|
||
|
template<typename T1, typename T2>
|
||
|
inline gzofstream&
|
||
|
operator<<(gzofstream& s, const gzomanip2<T1,T2>& m)
|
||
|
{ return (*m.func)(s, m.val1, m.val2); }
|
||
|
|
||
|
// Insert this onto stream to simplify setting of compression level
|
||
|
inline gzomanip2<int,int>
|
||
|
setcompression(int l, int s = Z_DEFAULT_STRATEGY)
|
||
|
{ return gzomanip2<int,int>(&setcompression, l, s); }
|
||
|
|
||
|
#endif // ZFSTREAM_H
|