| /* |
| * 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 |