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