Home | History | Annotate | Line # | Download | only in iostream3
zfstream.h revision 1.1
      1 /*	$NetBSD: zfstream.h,v 1.1 2006/01/14 20:10:54 christos Exp $	*/
      2 
      3 /*
      4  * A C++ I/O streams interface to the zlib gz* functions
      5  *
      6  * by Ludwig Schwardt <schwardt (at) sun.ac.za>
      7  * original version by Kevin Ruland <kevin (at) 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 */
     29 class gzfilebuf : public std::streambuf
     30 {
     31 public:
     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 
     88 protected:
     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 
    163 private:
    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 */
    236 class gzifstream : public std::istream
    237 {
    238 public:
    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 
    310 private:
    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 */
    325 class gzofstream : public std::ostream
    326 {
    327 public:
    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 
    399 private:
    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 */
    414 template<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
    441 inline gzofstream&
    442 setcompression(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
    449 template<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
    458 template<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
    464 inline gzomanip2<int,int>
    465 setcompression(int l, int s = Z_DEFAULT_STRATEGY)
    466 { return gzomanip2<int,int>(&setcompression, l, s); }
    467 
    468 #endif // ZFSTREAM_H
    469