1 // ============================================================================ 2 // gzstream, C++ iostream classes wrapping the zlib compression library. 3 // Copyright (C) 2001 Deepak Bandyopadhyay, Lutz Kettner 4 // 5 // This library is free software; you can redistribute it and/or 6 // modify it under the terms of the GNU Lesser General Public 7 // License as published by the Free Software Foundation; either 8 // version 2.1 of the License, or (at your option) any later version. 9 // 10 // This library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 // Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public 16 // License along with this library; if not, write to the Free Software 17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 // ============================================================================ 19 // 20 // File : gzstream.h 21 // Revision : $Revision: 16571 $ 22 // Revision_date : $Date: 2013-10-09 10:33:53 +0200 (Wed, 09 Oct 2013) $ 23 // Author(s) : Deepak Bandyopadhyay, Lutz Kettner 24 // Modernized : Ko vd Sloot (12-01-2017) 25 // Standard streambuf implementation following Nicolai Josuttis, "The 26 // Standard C++ Library". 27 // ============================================================================ 28 29 #ifndef GZSTREAM_H 30 #define GZSTREAM_H 1 31 32 // standard C++ with new header file names and std:: namespace 33 #include <cstring> 34 #include <iostream> 35 #include <fstream> 36 #include <zlib.h> 37 38 #ifdef GZSTREAM_NAMESPACE 39 namespace GZSTREAM_NAMESPACE { 40 #endif 41 42 /// \brief Internal class to implement gzstream. See below for user classes. 43 class gzstreambuf : public std::streambuf { 44 private: 45 gzstreambuf( const gzstreambuf& ); // no copies please 46 gzstreambuf& operator=( const gzstreambuf& ); // no copies please 47 48 static const int bufferSize = 47+256; // size of data buff 49 // totals 512 bytes under g++ for igzstream at the end. 50 51 gzFile file; // file handle for compressed file 52 char buffer[bufferSize]; // data buffer 53 char opened; // open/close state of stream 54 int mode; // I/O mode 55 56 int flush_buffer(); 57 public: gzstreambuf()58 gzstreambuf() : file(0), opened(0), mode(-1) { 59 setp( buffer, buffer + (bufferSize-1)); 60 setg( buffer + 4, // beginning of putback area 61 buffer + 4, // read position 62 buffer + 4); // end position 63 // ASSERT: both input & output capabilities will not be used together 64 } is_open()65 int is_open() { return opened; } 66 gzstreambuf* open( const std::string &name, int open_mode ); 67 gzstreambuf* close(); ~gzstreambuf()68 ~gzstreambuf() { close(); } 69 70 virtual int overflow( int c = EOF); 71 virtual int underflow(); 72 virtual int sync(); 73 }; 74 75 /// \brief Internal class to implement gzstream. See below for user classes. 76 class gzstreambase : virtual public std::ios { 77 protected: 78 gzstreambuf buf; 79 public: gzstreambase()80 gzstreambase() { init(&buf); } 81 gzstreambase( const std::string&, int ); 82 ~gzstreambase(); 83 void open( const std::string&, int ); 84 void close(); rdbuf()85 gzstreambuf* rdbuf() { return &buf; } 86 }; 87 88 /// \brief A stream class to support .gz files 89 /// 90 /// Use igzstream analogously to ifstream. It reads files based on the gz* 91 /// function interface of the zlib. Files are compatible with gzip 92 /// compression. 93 class igzstream : public gzstreambase, public std::istream { 94 public: igzstream()95 igzstream() : std::istream( &buf) {} 96 igzstream( const std::string& name, int open_mode = std::ios::in ) gzstreambase(name,open_mode)97 : gzstreambase( name, open_mode ), std::istream( &buf ) {} rdbuf()98 gzstreambuf* rdbuf() { return gzstreambase::rdbuf(); } 99 void open( const std::string& name, int open_mode = std::ios::in ) { 100 gzstreambase::open( name, open_mode); 101 } 102 }; 103 104 /// \brief A stream class to support .gz files 105 /// 106 /// Use ogzstream analogously to ofstream. It writes files based on the gz* 107 /// function interface of the zlib. Files are compatible with gzip 108 /// compression. 109 class ogzstream : public gzstreambase, public std::ostream { 110 public: ogzstream()111 ogzstream() : std::ostream( &buf) {} 112 ogzstream( const std::string& name, int mode = std::ios::out ) gzstreambase(name,mode)113 : gzstreambase( name, mode ), std::ostream( &buf ) {} rdbuf()114 gzstreambuf* rdbuf() { return gzstreambase::rdbuf(); } 115 void open( const std::string& name, int open_mode = std::ios::out ) { 116 gzstreambase::open( name, open_mode ); 117 } 118 }; 119 open(const std::string & name,int open_mode)120 gzstreambuf* gzstreambuf::open( const std::string& name, int open_mode) { 121 if ( is_open()) 122 return (gzstreambuf*)0; 123 mode = open_mode; 124 // no append nor read/write mode 125 if ((mode & std::ios::ate) || (mode & std::ios::app) 126 || ((mode & std::ios::in) && (mode & std::ios::out))) 127 return (gzstreambuf*)0; 128 std::string fmode; 129 if ( mode & std::ios::in) 130 fmode += 'r'; 131 else if ( mode & std::ios::out) 132 fmode += 'w'; 133 fmode += 'b'; 134 file = gzopen( name.c_str(), fmode.c_str() ); 135 if (file == 0){ 136 return (gzstreambuf*)0; 137 } 138 opened = 1; 139 return this; 140 } 141 close()142 gzstreambuf * gzstreambuf::close() { 143 if ( is_open()) { 144 sync(); 145 opened = 0; 146 if ( gzclose( file) == Z_OK) 147 return this; 148 } 149 return (gzstreambuf*)0; 150 } 151 underflow()152 int gzstreambuf::underflow() { // used for input buffer only 153 if ( gptr() && ( gptr() < egptr())) 154 return * reinterpret_cast<unsigned char *>( gptr()); 155 156 if ( ! (mode & std::ios::in) || ! opened) 157 return EOF; 158 // Josuttis' implementation of inbuf 159 int n_putback = gptr() - eback(); 160 if ( n_putback > 4) 161 n_putback = 4; 162 memcpy( buffer + (4 - n_putback), gptr() - n_putback, n_putback); 163 164 int num = gzread( file, buffer+4, bufferSize-4); 165 if (num <= 0) // ERROR or EOF 166 return EOF; 167 168 // reset buffer pointers 169 setg( buffer + (4 - n_putback), // beginning of putback area 170 buffer + 4, // read position 171 buffer + 4 + num); // end of buffer 172 173 // return next character 174 return * reinterpret_cast<unsigned char *>( gptr()); 175 } 176 flush_buffer()177 int gzstreambuf::flush_buffer() { 178 // Separate the writing of the buffer from overflow() and 179 // sync() operation. 180 int w = pptr() - pbase(); 181 if ( gzwrite( file, pbase(), w) != w) 182 return EOF; 183 pbump( -w); 184 return w; 185 } 186 overflow(int c)187 int gzstreambuf::overflow( int c) { // used for output buffer only 188 if ( ! ( mode & std::ios::out) || ! opened) 189 return EOF; 190 if (c != EOF) { 191 *pptr() = c; 192 pbump(1); 193 } 194 if ( flush_buffer() == EOF) 195 return EOF; 196 return c; 197 } 198 sync()199 int gzstreambuf::sync() { 200 // Changed to use flush_buffer() instead of overflow( EOF) 201 // which caused improper behavior with std::endl and flush(), 202 // bug reported by Vincent Ricard. 203 if ( pptr() && pptr() > pbase()) { 204 if ( flush_buffer() == EOF) 205 return -1; 206 } 207 return 0; 208 } 209 210 // -------------------------------------- 211 // class gzstreambase: 212 // -------------------------------------- 213 gzstreambase(const std::string & name,int mode)214 gzstreambase::gzstreambase( const std::string& name, int mode ) { 215 init( &buf ); 216 open( name, mode ); 217 } 218 ~gzstreambase()219 gzstreambase::~gzstreambase() { 220 buf.close(); 221 } 222 open(const std::string & name,int open_mode)223 void gzstreambase::open( const std::string& name, int open_mode ) { 224 if ( ! buf.open( name, open_mode ) ) 225 clear( rdstate() | std::ios::badbit ); 226 } 227 close()228 void gzstreambase::close() { 229 if ( buf.is_open() ) 230 if ( ! buf.close() ) 231 clear( rdstate() | std::ios::badbit); 232 } 233 234 #ifdef GZSTREAM_NAMESPACE 235 } // namespace GZSTREAM_NAMESPACE 236 #endif 237 238 #endif // GZSTREAM_H 239 // ============================================================================ 240 // EOF // 241