1aaf4ece6Schristos /* 2aaf4ece6Schristos * A C++ I/O streams interface to the zlib gz* functions 3aaf4ece6Schristos * 4aaf4ece6Schristos * by Ludwig Schwardt <schwardt@sun.ac.za> 5aaf4ece6Schristos * original version by Kevin Ruland <kevin@rodin.wustl.edu> 6aaf4ece6Schristos * 7aaf4ece6Schristos * This version is standard-compliant and compatible with gcc 3.x. 8aaf4ece6Schristos */ 9aaf4ece6Schristos 10aaf4ece6Schristos #ifndef ZFSTREAM_H 11aaf4ece6Schristos #define ZFSTREAM_H 12aaf4ece6Schristos 13aaf4ece6Schristos #include <istream> // not iostream, since we don't need cin/cout 14aaf4ece6Schristos #include <ostream> 15aaf4ece6Schristos #include "zlib.h" 16aaf4ece6Schristos 17aaf4ece6Schristos /*****************************************************************************/ 18aaf4ece6Schristos 19aaf4ece6Schristos /** 20aaf4ece6Schristos * @brief Gzipped file stream buffer class. 21aaf4ece6Schristos * 22aaf4ece6Schristos * This class implements basic_filebuf for gzipped files. It doesn't yet support 23aaf4ece6Schristos * seeking (allowed by zlib but slow/limited), putback and read/write access 24aaf4ece6Schristos * (tricky). Otherwise, it attempts to be a drop-in replacement for the standard 25aaf4ece6Schristos * file streambuf. 26aaf4ece6Schristos */ 27aaf4ece6Schristos class gzfilebuf : public std::streambuf 28aaf4ece6Schristos { 29aaf4ece6Schristos public: 30aaf4ece6Schristos // Default constructor. 31aaf4ece6Schristos gzfilebuf(); 32aaf4ece6Schristos 33aaf4ece6Schristos // Destructor. 34aaf4ece6Schristos virtual 35aaf4ece6Schristos ~gzfilebuf(); 36aaf4ece6Schristos 37aaf4ece6Schristos /** 38aaf4ece6Schristos * @brief Set compression level and strategy on the fly. 39aaf4ece6Schristos * @param comp_level Compression level (see zlib.h for allowed values) 40aaf4ece6Schristos * @param comp_strategy Compression strategy (see zlib.h for allowed values) 41aaf4ece6Schristos * @return Z_OK on success, Z_STREAM_ERROR otherwise. 42aaf4ece6Schristos * 43aaf4ece6Schristos * Unfortunately, these parameters cannot be modified separately, as the 44aaf4ece6Schristos * previous zfstream version assumed. Since the strategy is seldom changed, 45aaf4ece6Schristos * it can default and setcompression(level) then becomes like the old 46aaf4ece6Schristos * setcompressionlevel(level). 47aaf4ece6Schristos */ 48aaf4ece6Schristos int 49aaf4ece6Schristos setcompression(int comp_level, 50aaf4ece6Schristos int comp_strategy = Z_DEFAULT_STRATEGY); 51aaf4ece6Schristos 52aaf4ece6Schristos /** 53aaf4ece6Schristos * @brief Check if file is open. 54aaf4ece6Schristos * @return True if file is open. 55aaf4ece6Schristos */ 56aaf4ece6Schristos bool 57aaf4ece6Schristos is_open() const { return (file != NULL); } 58aaf4ece6Schristos 59aaf4ece6Schristos /** 60aaf4ece6Schristos * @brief Open gzipped file. 61aaf4ece6Schristos * @param name File name. 62aaf4ece6Schristos * @param mode Open mode flags. 63aaf4ece6Schristos * @return @c this on success, NULL on failure. 64aaf4ece6Schristos */ 65aaf4ece6Schristos gzfilebuf* 66aaf4ece6Schristos open(const char* name, 67aaf4ece6Schristos std::ios_base::openmode mode); 68aaf4ece6Schristos 69aaf4ece6Schristos /** 70aaf4ece6Schristos * @brief Attach to already open gzipped file. 71aaf4ece6Schristos * @param fd File descriptor. 72aaf4ece6Schristos * @param mode Open mode flags. 73aaf4ece6Schristos * @return @c this on success, NULL on failure. 74aaf4ece6Schristos */ 75aaf4ece6Schristos gzfilebuf* 76aaf4ece6Schristos attach(int fd, 77aaf4ece6Schristos std::ios_base::openmode mode); 78aaf4ece6Schristos 79aaf4ece6Schristos /** 80aaf4ece6Schristos * @brief Close gzipped file. 81aaf4ece6Schristos * @return @c this on success, NULL on failure. 82aaf4ece6Schristos */ 83aaf4ece6Schristos gzfilebuf* 84aaf4ece6Schristos close(); 85aaf4ece6Schristos 86aaf4ece6Schristos protected: 87aaf4ece6Schristos /** 88aaf4ece6Schristos * @brief Convert ios open mode int to mode string used by zlib. 89aaf4ece6Schristos * @return True if valid mode flag combination. 90aaf4ece6Schristos */ 91aaf4ece6Schristos bool 92aaf4ece6Schristos open_mode(std::ios_base::openmode mode, 93aaf4ece6Schristos char* c_mode) const; 94aaf4ece6Schristos 95aaf4ece6Schristos /** 96aaf4ece6Schristos * @brief Number of characters available in stream buffer. 97aaf4ece6Schristos * @return Number of characters. 98aaf4ece6Schristos * 99aaf4ece6Schristos * This indicates number of characters in get area of stream buffer. 100aaf4ece6Schristos * These characters can be read without accessing the gzipped file. 101aaf4ece6Schristos */ 102aaf4ece6Schristos virtual std::streamsize 103aaf4ece6Schristos showmanyc(); 104aaf4ece6Schristos 105aaf4ece6Schristos /** 106aaf4ece6Schristos * @brief Fill get area from gzipped file. 107aaf4ece6Schristos * @return First character in get area on success, EOF on error. 108aaf4ece6Schristos * 109aaf4ece6Schristos * This actually reads characters from gzipped file to stream 110aaf4ece6Schristos * buffer. Always buffered. 111aaf4ece6Schristos */ 112aaf4ece6Schristos virtual int_type 113aaf4ece6Schristos underflow(); 114aaf4ece6Schristos 115aaf4ece6Schristos /** 116aaf4ece6Schristos * @brief Write put area to gzipped file. 117aaf4ece6Schristos * @param c Extra character to add to buffer contents. 118aaf4ece6Schristos * @return Non-EOF on success, EOF on error. 119aaf4ece6Schristos * 120aaf4ece6Schristos * This actually writes characters in stream buffer to 121aaf4ece6Schristos * gzipped file. With unbuffered output this is done one 122aaf4ece6Schristos * character at a time. 123aaf4ece6Schristos */ 124aaf4ece6Schristos virtual int_type 125aaf4ece6Schristos overflow(int_type c = traits_type::eof()); 126aaf4ece6Schristos 127aaf4ece6Schristos /** 128aaf4ece6Schristos * @brief Installs external stream buffer. 129aaf4ece6Schristos * @param p Pointer to char buffer. 130aaf4ece6Schristos * @param n Size of external buffer. 131aaf4ece6Schristos * @return @c this on success, NULL on failure. 132aaf4ece6Schristos * 133aaf4ece6Schristos * Call setbuf(0,0) to enable unbuffered output. 134aaf4ece6Schristos */ 135aaf4ece6Schristos virtual std::streambuf* 136aaf4ece6Schristos setbuf(char_type* p, 137aaf4ece6Schristos std::streamsize n); 138aaf4ece6Schristos 139aaf4ece6Schristos /** 140aaf4ece6Schristos * @brief Flush stream buffer to file. 141aaf4ece6Schristos * @return 0 on success, -1 on error. 142aaf4ece6Schristos * 143aaf4ece6Schristos * This calls underflow(EOF) to do the job. 144aaf4ece6Schristos */ 145aaf4ece6Schristos virtual int 146aaf4ece6Schristos sync(); 147aaf4ece6Schristos 148aaf4ece6Schristos // 149aaf4ece6Schristos // Some future enhancements 150aaf4ece6Schristos // 151aaf4ece6Schristos // virtual int_type uflow(); 152aaf4ece6Schristos // virtual int_type pbackfail(int_type c = traits_type::eof()); 153aaf4ece6Schristos // virtual pos_type 154aaf4ece6Schristos // seekoff(off_type off, 155aaf4ece6Schristos // std::ios_base::seekdir way, 156aaf4ece6Schristos // std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out); 157aaf4ece6Schristos // virtual pos_type 158aaf4ece6Schristos // seekpos(pos_type sp, 159aaf4ece6Schristos // std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out); 160aaf4ece6Schristos 161aaf4ece6Schristos private: 162aaf4ece6Schristos /** 163aaf4ece6Schristos * @brief Allocate internal buffer. 164aaf4ece6Schristos * 165aaf4ece6Schristos * This function is safe to call multiple times. It will ensure 166aaf4ece6Schristos * that a proper internal buffer exists if it is required. If the 167aaf4ece6Schristos * buffer already exists or is external, the buffer pointers will be 168aaf4ece6Schristos * reset to their original state. 169aaf4ece6Schristos */ 170aaf4ece6Schristos void 171aaf4ece6Schristos enable_buffer(); 172aaf4ece6Schristos 173aaf4ece6Schristos /** 174aaf4ece6Schristos * @brief Destroy internal buffer. 175aaf4ece6Schristos * 176aaf4ece6Schristos * This function is safe to call multiple times. It will ensure 177aaf4ece6Schristos * that the internal buffer is deallocated if it exists. In any 178aaf4ece6Schristos * case, it will also reset the buffer pointers. 179aaf4ece6Schristos */ 180aaf4ece6Schristos void 181aaf4ece6Schristos disable_buffer(); 182aaf4ece6Schristos 183aaf4ece6Schristos /** 184aaf4ece6Schristos * Underlying file pointer. 185aaf4ece6Schristos */ 186aaf4ece6Schristos gzFile file; 187aaf4ece6Schristos 188aaf4ece6Schristos /** 189aaf4ece6Schristos * Mode in which file was opened. 190aaf4ece6Schristos */ 191aaf4ece6Schristos std::ios_base::openmode io_mode; 192aaf4ece6Schristos 193aaf4ece6Schristos /** 194aaf4ece6Schristos * @brief True if this object owns file descriptor. 195aaf4ece6Schristos * 196aaf4ece6Schristos * This makes the class responsible for closing the file 197aaf4ece6Schristos * upon destruction. 198aaf4ece6Schristos */ 199aaf4ece6Schristos bool own_fd; 200aaf4ece6Schristos 201aaf4ece6Schristos /** 202aaf4ece6Schristos * @brief Stream buffer. 203aaf4ece6Schristos * 204aaf4ece6Schristos * For simplicity this remains allocated on the free store for the 205aaf4ece6Schristos * entire life span of the gzfilebuf object, unless replaced by setbuf. 206aaf4ece6Schristos */ 207aaf4ece6Schristos char_type* buffer; 208aaf4ece6Schristos 209aaf4ece6Schristos /** 210aaf4ece6Schristos * @brief Stream buffer size. 211aaf4ece6Schristos * 212aaf4ece6Schristos * Defaults to system default buffer size (typically 8192 bytes). 213aaf4ece6Schristos * Modified by setbuf. 214aaf4ece6Schristos */ 215aaf4ece6Schristos std::streamsize buffer_size; 216aaf4ece6Schristos 217aaf4ece6Schristos /** 218aaf4ece6Schristos * @brief True if this object owns stream buffer. 219aaf4ece6Schristos * 220aaf4ece6Schristos * This makes the class responsible for deleting the buffer 221aaf4ece6Schristos * upon destruction. 222aaf4ece6Schristos */ 223aaf4ece6Schristos bool own_buffer; 224aaf4ece6Schristos }; 225aaf4ece6Schristos 226aaf4ece6Schristos /*****************************************************************************/ 227aaf4ece6Schristos 228aaf4ece6Schristos /** 229aaf4ece6Schristos * @brief Gzipped file input stream class. 230aaf4ece6Schristos * 231aaf4ece6Schristos * This class implements ifstream for gzipped files. Seeking and putback 232aaf4ece6Schristos * is not supported yet. 233aaf4ece6Schristos */ 234aaf4ece6Schristos class gzifstream : public std::istream 235aaf4ece6Schristos { 236aaf4ece6Schristos public: 237aaf4ece6Schristos // Default constructor 238aaf4ece6Schristos gzifstream(); 239aaf4ece6Schristos 240aaf4ece6Schristos /** 241aaf4ece6Schristos * @brief Construct stream on gzipped file to be opened. 242aaf4ece6Schristos * @param name File name. 243aaf4ece6Schristos * @param mode Open mode flags (forced to contain ios::in). 244aaf4ece6Schristos */ 245aaf4ece6Schristos explicit 246aaf4ece6Schristos gzifstream(const char* name, 247aaf4ece6Schristos std::ios_base::openmode mode = std::ios_base::in); 248aaf4ece6Schristos 249aaf4ece6Schristos /** 250aaf4ece6Schristos * @brief Construct stream on already open gzipped file. 251aaf4ece6Schristos * @param fd File descriptor. 252aaf4ece6Schristos * @param mode Open mode flags (forced to contain ios::in). 253aaf4ece6Schristos */ 254aaf4ece6Schristos explicit 255aaf4ece6Schristos gzifstream(int fd, 256aaf4ece6Schristos std::ios_base::openmode mode = std::ios_base::in); 257aaf4ece6Schristos 258aaf4ece6Schristos /** 259aaf4ece6Schristos * Obtain underlying stream buffer. 260aaf4ece6Schristos */ 261aaf4ece6Schristos gzfilebuf* 262aaf4ece6Schristos rdbuf() const 263aaf4ece6Schristos { return const_cast<gzfilebuf*>(&sb); } 264aaf4ece6Schristos 265aaf4ece6Schristos /** 266aaf4ece6Schristos * @brief Check if file is open. 267aaf4ece6Schristos * @return True if file is open. 268aaf4ece6Schristos */ 269aaf4ece6Schristos bool 270aaf4ece6Schristos is_open() { return sb.is_open(); } 271aaf4ece6Schristos 272aaf4ece6Schristos /** 273aaf4ece6Schristos * @brief Open gzipped file. 274aaf4ece6Schristos * @param name File name. 275aaf4ece6Schristos * @param mode Open mode flags (forced to contain ios::in). 276aaf4ece6Schristos * 277aaf4ece6Schristos * Stream will be in state good() if file opens successfully; 278aaf4ece6Schristos * otherwise in state fail(). This differs from the behavior of 279aaf4ece6Schristos * ifstream, which never sets the state to good() and therefore 280aaf4ece6Schristos * won't allow you to reuse the stream for a second file unless 281aaf4ece6Schristos * you manually clear() the state. The choice is a matter of 282aaf4ece6Schristos * convenience. 283aaf4ece6Schristos */ 284aaf4ece6Schristos void 285aaf4ece6Schristos open(const char* name, 286aaf4ece6Schristos std::ios_base::openmode mode = std::ios_base::in); 287aaf4ece6Schristos 288aaf4ece6Schristos /** 289aaf4ece6Schristos * @brief Attach to already open gzipped file. 290aaf4ece6Schristos * @param fd File descriptor. 291aaf4ece6Schristos * @param mode Open mode flags (forced to contain ios::in). 292aaf4ece6Schristos * 293aaf4ece6Schristos * Stream will be in state good() if attach succeeded; otherwise 294aaf4ece6Schristos * in state fail(). 295aaf4ece6Schristos */ 296aaf4ece6Schristos void 297aaf4ece6Schristos attach(int fd, 298aaf4ece6Schristos std::ios_base::openmode mode = std::ios_base::in); 299aaf4ece6Schristos 300aaf4ece6Schristos /** 301aaf4ece6Schristos * @brief Close gzipped file. 302aaf4ece6Schristos * 303aaf4ece6Schristos * Stream will be in state fail() if close failed. 304aaf4ece6Schristos */ 305aaf4ece6Schristos void 306aaf4ece6Schristos close(); 307aaf4ece6Schristos 308aaf4ece6Schristos private: 309aaf4ece6Schristos /** 310aaf4ece6Schristos * Underlying stream buffer. 311aaf4ece6Schristos */ 312aaf4ece6Schristos gzfilebuf sb; 313aaf4ece6Schristos }; 314aaf4ece6Schristos 315aaf4ece6Schristos /*****************************************************************************/ 316aaf4ece6Schristos 317aaf4ece6Schristos /** 318aaf4ece6Schristos * @brief Gzipped file output stream class. 319aaf4ece6Schristos * 320aaf4ece6Schristos * This class implements ofstream for gzipped files. Seeking and putback 321aaf4ece6Schristos * is not supported yet. 322aaf4ece6Schristos */ 323aaf4ece6Schristos class gzofstream : public std::ostream 324aaf4ece6Schristos { 325aaf4ece6Schristos public: 326aaf4ece6Schristos // Default constructor 327aaf4ece6Schristos gzofstream(); 328aaf4ece6Schristos 329aaf4ece6Schristos /** 330aaf4ece6Schristos * @brief Construct stream on gzipped file to be opened. 331aaf4ece6Schristos * @param name File name. 332aaf4ece6Schristos * @param mode Open mode flags (forced to contain ios::out). 333aaf4ece6Schristos */ 334aaf4ece6Schristos explicit 335aaf4ece6Schristos gzofstream(const char* name, 336aaf4ece6Schristos std::ios_base::openmode mode = std::ios_base::out); 337aaf4ece6Schristos 338aaf4ece6Schristos /** 339aaf4ece6Schristos * @brief Construct stream on already open gzipped file. 340aaf4ece6Schristos * @param fd File descriptor. 341aaf4ece6Schristos * @param mode Open mode flags (forced to contain ios::out). 342aaf4ece6Schristos */ 343aaf4ece6Schristos explicit 344aaf4ece6Schristos gzofstream(int fd, 345aaf4ece6Schristos std::ios_base::openmode mode = std::ios_base::out); 346aaf4ece6Schristos 347aaf4ece6Schristos /** 348aaf4ece6Schristos * Obtain underlying stream buffer. 349aaf4ece6Schristos */ 350aaf4ece6Schristos gzfilebuf* 351aaf4ece6Schristos rdbuf() const 352aaf4ece6Schristos { return const_cast<gzfilebuf*>(&sb); } 353aaf4ece6Schristos 354aaf4ece6Schristos /** 355aaf4ece6Schristos * @brief Check if file is open. 356aaf4ece6Schristos * @return True if file is open. 357aaf4ece6Schristos */ 358aaf4ece6Schristos bool 359aaf4ece6Schristos is_open() { return sb.is_open(); } 360aaf4ece6Schristos 361aaf4ece6Schristos /** 362aaf4ece6Schristos * @brief Open gzipped file. 363aaf4ece6Schristos * @param name File name. 364aaf4ece6Schristos * @param mode Open mode flags (forced to contain ios::out). 365aaf4ece6Schristos * 366aaf4ece6Schristos * Stream will be in state good() if file opens successfully; 367aaf4ece6Schristos * otherwise in state fail(). This differs from the behavior of 368aaf4ece6Schristos * ofstream, which never sets the state to good() and therefore 369aaf4ece6Schristos * won't allow you to reuse the stream for a second file unless 370aaf4ece6Schristos * you manually clear() the state. The choice is a matter of 371aaf4ece6Schristos * convenience. 372aaf4ece6Schristos */ 373aaf4ece6Schristos void 374aaf4ece6Schristos open(const char* name, 375aaf4ece6Schristos std::ios_base::openmode mode = std::ios_base::out); 376aaf4ece6Schristos 377aaf4ece6Schristos /** 378aaf4ece6Schristos * @brief Attach to already open gzipped file. 379aaf4ece6Schristos * @param fd File descriptor. 380aaf4ece6Schristos * @param mode Open mode flags (forced to contain ios::out). 381aaf4ece6Schristos * 382aaf4ece6Schristos * Stream will be in state good() if attach succeeded; otherwise 383aaf4ece6Schristos * in state fail(). 384aaf4ece6Schristos */ 385aaf4ece6Schristos void 386aaf4ece6Schristos attach(int fd, 387aaf4ece6Schristos std::ios_base::openmode mode = std::ios_base::out); 388aaf4ece6Schristos 389aaf4ece6Schristos /** 390aaf4ece6Schristos * @brief Close gzipped file. 391aaf4ece6Schristos * 392aaf4ece6Schristos * Stream will be in state fail() if close failed. 393aaf4ece6Schristos */ 394aaf4ece6Schristos void 395aaf4ece6Schristos close(); 396aaf4ece6Schristos 397aaf4ece6Schristos private: 398aaf4ece6Schristos /** 399aaf4ece6Schristos * Underlying stream buffer. 400aaf4ece6Schristos */ 401aaf4ece6Schristos gzfilebuf sb; 402aaf4ece6Schristos }; 403aaf4ece6Schristos 404aaf4ece6Schristos /*****************************************************************************/ 405aaf4ece6Schristos 406aaf4ece6Schristos /** 407aaf4ece6Schristos * @brief Gzipped file output stream manipulator class. 408aaf4ece6Schristos * 409aaf4ece6Schristos * This class defines a two-argument manipulator for gzofstream. It is used 410aaf4ece6Schristos * as base for the setcompression(int,int) manipulator. 411aaf4ece6Schristos */ 412aaf4ece6Schristos template<typename T1, typename T2> 413aaf4ece6Schristos class gzomanip2 414aaf4ece6Schristos { 415aaf4ece6Schristos public: 416*b175d1c2Schristos // Allows inserter to peek at internals 417aaf4ece6Schristos template <typename Ta, typename Tb> 418aaf4ece6Schristos friend gzofstream& 419aaf4ece6Schristos operator<<(gzofstream&, 420aaf4ece6Schristos const gzomanip2<Ta,Tb>&); 421aaf4ece6Schristos 422aaf4ece6Schristos // Constructor 423aaf4ece6Schristos gzomanip2(gzofstream& (*f)(gzofstream&, T1, T2), 424aaf4ece6Schristos T1 v1, 425aaf4ece6Schristos T2 v2); 426aaf4ece6Schristos private: 427aaf4ece6Schristos // Underlying manipulator function 428aaf4ece6Schristos gzofstream& 429aaf4ece6Schristos (*func)(gzofstream&, T1, T2); 430aaf4ece6Schristos 431aaf4ece6Schristos // Arguments for manipulator function 432aaf4ece6Schristos T1 val1; 433aaf4ece6Schristos T2 val2; 434aaf4ece6Schristos }; 435aaf4ece6Schristos 436aaf4ece6Schristos /*****************************************************************************/ 437aaf4ece6Schristos 438aaf4ece6Schristos // Manipulator function thunks through to stream buffer 439aaf4ece6Schristos inline gzofstream& 440aaf4ece6Schristos setcompression(gzofstream &gzs, int l, int s = Z_DEFAULT_STRATEGY) 441aaf4ece6Schristos { 442aaf4ece6Schristos (gzs.rdbuf())->setcompression(l, s); 443aaf4ece6Schristos return gzs; 444aaf4ece6Schristos } 445aaf4ece6Schristos 446aaf4ece6Schristos // Manipulator constructor stores arguments 447aaf4ece6Schristos template<typename T1, typename T2> 448aaf4ece6Schristos inline 449aaf4ece6Schristos gzomanip2<T1,T2>::gzomanip2(gzofstream &(*f)(gzofstream &, T1, T2), 450aaf4ece6Schristos T1 v1, 451aaf4ece6Schristos T2 v2) 452aaf4ece6Schristos : func(f), val1(v1), val2(v2) 453aaf4ece6Schristos { } 454aaf4ece6Schristos 455*b175d1c2Schristos // Inserter applies underlying manipulator function to stream 456aaf4ece6Schristos template<typename T1, typename T2> 457aaf4ece6Schristos inline gzofstream& 458aaf4ece6Schristos operator<<(gzofstream& s, const gzomanip2<T1,T2>& m) 459aaf4ece6Schristos { return (*m.func)(s, m.val1, m.val2); } 460aaf4ece6Schristos 461aaf4ece6Schristos // Insert this onto stream to simplify setting of compression level 462aaf4ece6Schristos inline gzomanip2<int,int> 463aaf4ece6Schristos setcompression(int l, int s = Z_DEFAULT_STRATEGY) 464aaf4ece6Schristos { return gzomanip2<int,int>(&setcompression, l, s); } 465aaf4ece6Schristos 466aaf4ece6Schristos #endif // ZFSTREAM_H 467