// ============================================================================ // gzstream, C++ iostream classes wrapping the zlib compression library. // Copyright (C) 2001 Deepak Bandyopadhyay, Lutz Kettner // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library 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 // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // ============================================================================ // // File : gzstream.h // Revision : Revision: 1.5 // Revision_date : Date: 2002/04/26 23:30:15 // Author(s) : Deepak Bandyopadhyay, Lutz Kettner // // Matthew Walker made changes to fix a bug with igzstream. Previously, if // a call was made to igzstream with a filename that disn't exist, no error // would be reported. This has been fixed. // // Standard streambuf implementation following Nicolai Josuttis, "The // Standard C++ Library". // ============================================================================ #ifndef GZSTREAM_H #define GZSTREAM_H // standard C++ with new header file names and std:: namespace #include #include #include #ifdef GZSTREAM_NAMESPACE namespace GZSTREAM_NAMESPACE { #endif // ---------------------------------------------------------------------------- // Internal classes to implement gzstream. See below for user classes. // ---------------------------------------------------------------------------- class gzstreambuf : public std::streambuf { private: static const int bufferSize = 47+256; // size of data buff // totals 512 bytes under g++ for igzstream at the end. gzFile file; // file handle for compressed file char buffer[bufferSize]; // data buffer char opened; // open/close state of stream int mode; // I/O mode int flush_buffer(); public: inline gzstreambuf() : opened(0) { setp( buffer, buffer + (bufferSize-1)); setg( buffer + 4, // beginning of putback area buffer + 4, // read position buffer + 4); // end position // ASSERT: both input & output capabilities will not be used together } inline int is_open() { return opened; } inline gzstreambuf* open( const char* name, int open_mode); inline gzstreambuf* close(); inline ~gzstreambuf() { close(); } virtual int overflow( int c = EOF); virtual int underflow(); virtual int sync(); }; class gzstreambase : virtual public std::ios { protected: gzstreambuf buf; public: inline gzstreambase() { init(&buf); } inline gzstreambase( const char* name, int open_mode); inline ~gzstreambase(); inline void open( const char* name, int open_mode); inline void close(); inline gzstreambuf* rdbuf() { return &buf; } }; // ---------------------------------------------------------------------------- // User classes. Use igzstream and ogzstream analogously to ifstream and // ofstream respectively. They read and write files based on the gz* // function interface of the zlib. Files are compatible with gzip compression. // ---------------------------------------------------------------------------- class igzstream : public std::istream, public gzstreambase { public: inline igzstream() : std::istream( &buf) {} inline igzstream( const char* name, int open_mode = std::ios::in) : std::istream( &buf), gzstreambase( name, open_mode) {} inline gzstreambuf* rdbuf() { return gzstreambase::rdbuf(); } inline void open( const char* name, int open_mode = std::ios::in) { gzstreambase::open( name, open_mode); } }; class ogzstream : public std::ostream, public gzstreambase { public: inline ogzstream() : std::ostream( &buf) {} inline ogzstream( const char* name, int mode = std::ios::out) : std::ostream( &buf), gzstreambase( name, mode) {} inline gzstreambuf* rdbuf() { return gzstreambase::rdbuf(); } inline void open( const char* name, int open_mode = std::ios::out) { gzstreambase::open( name, open_mode); } }; inline gzstreambuf* gzstreambuf::open( const char* name, int open_mode) { if ( is_open()) return (gzstreambuf*)0; mode = open_mode; // no append nor read/write mode if ((mode & std::ios::ate) || (mode & std::ios::app) || ((mode & std::ios::in) && (mode & std::ios::out))) return (gzstreambuf*)0; char fmode[10]; char* fmodeptr = fmode; if ( mode & std::ios::in) *fmodeptr++ = 'r'; else if ( mode & std::ios::out) *fmodeptr++ = 'w'; *fmodeptr++ = 'b'; *fmodeptr = '\0'; file = gzopen( name, fmode); if (file == 0) return (gzstreambuf*)0; opened = 1; return this; } inline gzstreambuf * gzstreambuf::close() { if ( is_open()) { sync(); opened = 0; if ( gzclose( file) == Z_OK) return this; } return (gzstreambuf*)0; } inline int gzstreambuf::underflow() { // used for input buffer only if ( gptr() && ( gptr() < egptr())) return * reinterpret_cast( gptr()); if ( ! (mode & std::ios::in) || ! opened) return EOF; // Josuttis' implementation of inbuf int n_putback = gptr() - eback(); if ( n_putback > 4) n_putback = 4; memcpy( buffer + (4 - n_putback), gptr() - n_putback, n_putback); int num = gzread( file, buffer+4, bufferSize-4); if (num <= 0) // ERROR or EOF return EOF; // reset buffer pointers setg( buffer + (4 - n_putback), // beginning of putback area buffer + 4, // read position buffer + 4 + num); // end of buffer // return next character return * reinterpret_cast( gptr()); } inline int gzstreambuf::flush_buffer() { // Separate the writing of the buffer from overflow() and // sync() operation. int w = pptr() - pbase(); if ( gzwrite( file, pbase(), w) != w) return EOF; pbump( -w); return w; } inline int gzstreambuf::overflow( int c) { // used for output buffer only if ( ! ( mode & std::ios::out) || ! opened) return EOF; if (c != EOF) { *pptr() = c; pbump(1); } if ( flush_buffer() == EOF) return EOF; return c; } inline int gzstreambuf::sync() { // Changed to use flush_buffer() instead of overflow( EOF) // which caused improper behavior with std::endl and flush(), // bug reported by Vincent Ricard. if ( pptr() && pptr() > pbase()) { if ( flush_buffer() == EOF) return -1; } return 0; } // -------------------------------------- // class gzstreambase: // -------------------------------------- inline gzstreambase::gzstreambase( const char* name, int mode) { init( &buf); open( name, mode); } inline gzstreambase::~gzstreambase() { buf.close(); } inline void gzstreambase::open( const char* name, int open_mode) { if ( ! buf.open( name, open_mode)) clear( rdstate() | std::ios::badbit); } inline void gzstreambase::close() { if ( buf.is_open()) if ( ! buf.close()) clear( rdstate() | std::ios::badbit); } #ifdef GZSTREAM_NAMESPACE } // namespace GZSTREAM_NAMESPACE #endif #endif // GZSTREAM_H // ============================================================================ // EOF //