Home | History | Annotate | Line # | Download | only in iostream2
zstream.h revision 1.1.1.1
      1 /*	$NetBSD: zstream.h,v 1.1.1.1 2006/01/14 20:10:54 christos Exp $	*/
      2 
      3 /*
      4  *
      5  * Copyright (c) 1997
      6  * Christian Michelsen Research AS
      7  * Advanced Computing
      8  * Fantoftvegen 38, 5036 BERGEN, Norway
      9  * http://www.cmr.no
     10  *
     11  * Permission to use, copy, modify, distribute and sell this software
     12  * and its documentation for any purpose is hereby granted without fee,
     13  * provided that the above copyright notice appear in all copies and
     14  * that both that copyright notice and this permission notice appear
     15  * in supporting documentation.  Christian Michelsen Research AS makes no
     16  * representations about the suitability of this software for any
     17  * purpose.  It is provided "as is" without express or implied warranty.
     18  *
     19  */
     20 
     21 #ifndef ZSTREAM__H
     22 #define ZSTREAM__H
     23 
     24 /*
     25  * zstream.h - C++ interface to the 'zlib' general purpose compression library
     26  * Id: zstream.h 1.1 1997-06-25 12:00:56+02 tyge Exp tyge
     27  */
     28 
     29 #include <strstream.h>
     30 #include <string.h>
     31 #include <stdio.h>
     32 #include "zlib.h"
     33 
     34 #if defined(_WIN32)
     35 #   include <fcntl.h>
     36 #   include <io.h>
     37 #   define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
     38 #else
     39 #   define SET_BINARY_MODE(file)
     40 #endif
     41 
     42 class zstringlen {
     43 public:
     44     zstringlen(class izstream&);
     45     zstringlen(class ozstream&, const char*);
     46     size_t value() const { return val.word; }
     47 private:
     48     struct Val { unsigned char byte; size_t word; } val;
     49 };
     50 
     51 //  ----------------------------- izstream -----------------------------
     52 
     53 class izstream
     54 {
     55     public:
     56         izstream() : m_fp(0) {}
     57         izstream(FILE* fp) : m_fp(0) { open(fp); }
     58         izstream(const char* name) : m_fp(0) { open(name); }
     59         ~izstream() { close(); }
     60 
     61         /* Opens a gzip (.gz) file for reading.
     62          * open() can be used to read a file which is not in gzip format;
     63          * in this case read() will directly read from the file without
     64          * decompression. errno can be checked to distinguish two error
     65          * cases (if errno is zero, the zlib error is Z_MEM_ERROR).
     66          */
     67         void open(const char* name) {
     68             if (m_fp) close();
     69             m_fp = ::gzopen(name, "rb");
     70         }
     71 
     72         void open(FILE* fp) {
     73             SET_BINARY_MODE(fp);
     74             if (m_fp) close();
     75             m_fp = ::gzdopen(fileno(fp), "rb");
     76         }
     77 
     78         /* Flushes all pending input if necessary, closes the compressed file
     79          * and deallocates all the (de)compression state. The return value is
     80          * the zlib error number (see function error() below).
     81          */
     82         int close() {
     83             int r = ::gzclose(m_fp);
     84             m_fp = 0; return r;
     85         }
     86 
     87         /* Binary read the given number of bytes from the compressed file.
     88          */
     89         int read(void* buf, size_t len) {
     90             return ::gzread(m_fp, buf, len);
     91         }
     92 
     93         /* Returns the error message for the last error which occurred on the
     94          * given compressed file. errnum is set to zlib error number. If an
     95          * error occurred in the file system and not in the compression library,
     96          * errnum is set to Z_ERRNO and the application may consult errno
     97          * to get the exact error code.
     98          */
     99         const char* error(int* errnum) {
    100             return ::gzerror(m_fp, errnum);
    101         }
    102 
    103         gzFile fp() { return m_fp; }
    104 
    105     private:
    106         gzFile m_fp;
    107 };
    108 
    109 /*
    110  * Binary read the given (array of) object(s) from the compressed file.
    111  * If the input file was not in gzip format, read() copies the objects number
    112  * of bytes into the buffer.
    113  * returns the number of uncompressed bytes actually read
    114  * (0 for end of file, -1 for error).
    115  */
    116 template <class T, class Items>
    117 inline int read(izstream& zs, T* x, Items items) {
    118     return ::gzread(zs.fp(), x, items*sizeof(T));
    119 }
    120 
    121 /*
    122  * Binary input with the '>' operator.
    123  */
    124 template <class T>
    125 inline izstream& operator>(izstream& zs, T& x) {
    126     ::gzread(zs.fp(), &x, sizeof(T));
    127     return zs;
    128 }
    129 
    130 
    131 inline zstringlen::zstringlen(izstream& zs) {
    132     zs > val.byte;
    133     if (val.byte == 255) zs > val.word;
    134     else val.word = val.byte;
    135 }
    136 
    137 /*
    138  * Read length of string + the string with the '>' operator.
    139  */
    140 inline izstream& operator>(izstream& zs, char* x) {
    141     zstringlen len(zs);
    142     ::gzread(zs.fp(), x, len.value());
    143     x[len.value()] = '\0';
    144     return zs;
    145 }
    146 
    147 inline char* read_string(izstream& zs) {
    148     zstringlen len(zs);
    149     char* x = new char[len.value()+1];
    150     ::gzread(zs.fp(), x, len.value());
    151     x[len.value()] = '\0';
    152     return x;
    153 }
    154 
    155 // ----------------------------- ozstream -----------------------------
    156 
    157 class ozstream
    158 {
    159     public:
    160         ozstream() : m_fp(0), m_os(0) {
    161         }
    162         ozstream(FILE* fp, int level = Z_DEFAULT_COMPRESSION)
    163             : m_fp(0), m_os(0) {
    164             open(fp, level);
    165         }
    166         ozstream(const char* name, int level = Z_DEFAULT_COMPRESSION)
    167             : m_fp(0), m_os(0) {
    168             open(name, level);
    169         }
    170         ~ozstream() {
    171             close();
    172         }
    173 
    174         /* Opens a gzip (.gz) file for writing.
    175          * The compression level parameter should be in 0..9
    176          * errno can be checked to distinguish two error cases
    177          * (if errno is zero, the zlib error is Z_MEM_ERROR).
    178          */
    179         void open(const char* name, int level = Z_DEFAULT_COMPRESSION) {
    180             char mode[4] = "wb\0";
    181             if (level != Z_DEFAULT_COMPRESSION) mode[2] = '0'+level;
    182             if (m_fp) close();
    183             m_fp = ::gzopen(name, mode);
    184         }
    185 
    186         /* open from a FILE pointer.
    187          */
    188         void open(FILE* fp, int level = Z_DEFAULT_COMPRESSION) {
    189             SET_BINARY_MODE(fp);
    190             char mode[4] = "wb\0";
    191             if (level != Z_DEFAULT_COMPRESSION) mode[2] = '0'+level;
    192             if (m_fp) close();
    193             m_fp = ::gzdopen(fileno(fp), mode);
    194         }
    195 
    196         /* Flushes all pending output if necessary, closes the compressed file
    197          * and deallocates all the (de)compression state. The return value is
    198          * the zlib error number (see function error() below).
    199          */
    200         int close() {
    201             if (m_os) {
    202                 ::gzwrite(m_fp, m_os->str(), m_os->pcount());
    203                 delete[] m_os->str(); delete m_os; m_os = 0;
    204             }
    205             int r = ::gzclose(m_fp); m_fp = 0; return r;
    206         }
    207 
    208         /* Binary write the given number of bytes into the compressed file.
    209          */
    210         int write(const void* buf, size_t len) {
    211             return ::gzwrite(m_fp, (voidp) buf, len);
    212         }
    213 
    214         /* Flushes all pending output into the compressed file. The parameter
    215          * _flush is as in the deflate() function. The return value is the zlib
    216          * error number (see function gzerror below). flush() returns Z_OK if
    217          * the flush_ parameter is Z_FINISH and all output could be flushed.
    218          * flush() should be called only when strictly necessary because it can
    219          * degrade compression.
    220          */
    221         int flush(int _flush) {
    222             os_flush();
    223             return ::gzflush(m_fp, _flush);
    224         }
    225 
    226         /* Returns the error message for the last error which occurred on the
    227          * given compressed file. errnum is set to zlib error number. If an
    228          * error occurred in the file system and not in the compression library,
    229          * errnum is set to Z_ERRNO and the application may consult errno
    230          * to get the exact error code.
    231          */
    232         const char* error(int* errnum) {
    233             return ::gzerror(m_fp, errnum);
    234         }
    235 
    236         gzFile fp() { return m_fp; }
    237 
    238         ostream& os() {
    239             if (m_os == 0) m_os = new ostrstream;
    240             return *m_os;
    241         }
    242 
    243         void os_flush() {
    244             if (m_os && m_os->pcount()>0) {
    245                 ostrstream* oss = new ostrstream;
    246                 oss->fill(m_os->fill());
    247                 oss->flags(m_os->flags());
    248                 oss->precision(m_os->precision());
    249                 oss->width(m_os->width());
    250                 ::gzwrite(m_fp, m_os->str(), m_os->pcount());
    251                 delete[] m_os->str(); delete m_os; m_os = oss;
    252             }
    253         }
    254 
    255     private:
    256         gzFile m_fp;
    257         ostrstream* m_os;
    258 };
    259 
    260 /*
    261  * Binary write the given (array of) object(s) into the compressed file.
    262  * returns the number of uncompressed bytes actually written
    263  * (0 in case of error).
    264  */
    265 template <class T, class Items>
    266 inline int write(ozstream& zs, const T* x, Items items) {
    267     return ::gzwrite(zs.fp(), (voidp) x, items*sizeof(T));
    268 }
    269 
    270 /*
    271  * Binary output with the '<' operator.
    272  */
    273 template <class T>
    274 inline ozstream& operator<(ozstream& zs, const T& x) {
    275     ::gzwrite(zs.fp(), (voidp) &x, sizeof(T));
    276     return zs;
    277 }
    278 
    279 inline zstringlen::zstringlen(ozstream& zs, const char* x) {
    280     val.byte = 255;  val.word = ::strlen(x);
    281     if (val.word < 255) zs < (val.byte = val.word);
    282     else zs < val;
    283 }
    284 
    285 /*
    286  * Write length of string + the string with the '<' operator.
    287  */
    288 inline ozstream& operator<(ozstream& zs, const char* x) {
    289     zstringlen len(zs, x);
    290     ::gzwrite(zs.fp(), (voidp) x, len.value());
    291     return zs;
    292 }
    293 
    294 #ifdef _MSC_VER
    295 inline ozstream& operator<(ozstream& zs, char* const& x) {
    296     return zs < (const char*) x;
    297 }
    298 #endif
    299 
    300 /*
    301  * Ascii write with the << operator;
    302  */
    303 template <class T>
    304 inline ostream& operator<<(ozstream& zs, const T& x) {
    305     zs.os_flush();
    306     return zs.os() << x;
    307 }
    308 
    309 #endif
    310