You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
466 lines
12 KiB
466 lines
12 KiB
/* |
|
* 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
|
|
|