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