Chris@43: /* Chris@43: * Chris@43: * Copyright (c) 1997 Chris@43: * Christian Michelsen Research AS Chris@43: * Advanced Computing Chris@43: * Fantoftvegen 38, 5036 BERGEN, Norway Chris@43: * http://www.cmr.no Chris@43: * Chris@43: * Permission to use, copy, modify, distribute and sell this software Chris@43: * and its documentation for any purpose is hereby granted without fee, Chris@43: * provided that the above copyright notice appear in all copies and Chris@43: * that both that copyright notice and this permission notice appear Chris@43: * in supporting documentation. Christian Michelsen Research AS makes no Chris@43: * representations about the suitability of this software for any Chris@43: * purpose. It is provided "as is" without express or implied warranty. Chris@43: * Chris@43: */ Chris@43: Chris@43: #ifndef ZSTREAM__H Chris@43: #define ZSTREAM__H Chris@43: Chris@43: /* Chris@43: * zstream.h - C++ interface to the 'zlib' general purpose compression library Chris@43: * $Id: zstream.h 1.1 1997-06-25 12:00:56+02 tyge Exp tyge $ Chris@43: */ Chris@43: Chris@43: #include Chris@43: #include Chris@43: #include Chris@43: #include "zlib.h" Chris@43: Chris@43: #if defined(_WIN32) Chris@43: # include Chris@43: # include Chris@43: # define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) Chris@43: #else Chris@43: # define SET_BINARY_MODE(file) Chris@43: #endif Chris@43: Chris@43: class zstringlen { Chris@43: public: Chris@43: zstringlen(class izstream&); Chris@43: zstringlen(class ozstream&, const char*); Chris@43: size_t value() const { return val.word; } Chris@43: private: Chris@43: struct Val { unsigned char byte; size_t word; } val; Chris@43: }; Chris@43: Chris@43: // ----------------------------- izstream ----------------------------- Chris@43: Chris@43: class izstream Chris@43: { Chris@43: public: Chris@43: izstream() : m_fp(0) {} Chris@43: izstream(FILE* fp) : m_fp(0) { open(fp); } Chris@43: izstream(const char* name) : m_fp(0) { open(name); } Chris@43: ~izstream() { close(); } Chris@43: Chris@43: /* Opens a gzip (.gz) file for reading. Chris@43: * open() can be used to read a file which is not in gzip format; Chris@43: * in this case read() will directly read from the file without Chris@43: * decompression. errno can be checked to distinguish two error Chris@43: * cases (if errno is zero, the zlib error is Z_MEM_ERROR). Chris@43: */ Chris@43: void open(const char* name) { Chris@43: if (m_fp) close(); Chris@43: m_fp = ::gzopen(name, "rb"); Chris@43: } Chris@43: Chris@43: void open(FILE* fp) { Chris@43: SET_BINARY_MODE(fp); Chris@43: if (m_fp) close(); Chris@43: m_fp = ::gzdopen(fileno(fp), "rb"); Chris@43: } Chris@43: Chris@43: /* Flushes all pending input if necessary, closes the compressed file Chris@43: * and deallocates all the (de)compression state. The return value is Chris@43: * the zlib error number (see function error() below). Chris@43: */ Chris@43: int close() { Chris@43: int r = ::gzclose(m_fp); Chris@43: m_fp = 0; return r; Chris@43: } Chris@43: Chris@43: /* Binary read the given number of bytes from the compressed file. Chris@43: */ Chris@43: int read(void* buf, size_t len) { Chris@43: return ::gzread(m_fp, buf, len); Chris@43: } Chris@43: Chris@43: /* Returns the error message for the last error which occurred on the Chris@43: * given compressed file. errnum is set to zlib error number. If an Chris@43: * error occurred in the file system and not in the compression library, Chris@43: * errnum is set to Z_ERRNO and the application may consult errno Chris@43: * to get the exact error code. Chris@43: */ Chris@43: const char* error(int* errnum) { Chris@43: return ::gzerror(m_fp, errnum); Chris@43: } Chris@43: Chris@43: gzFile fp() { return m_fp; } Chris@43: Chris@43: private: Chris@43: gzFile m_fp; Chris@43: }; Chris@43: Chris@43: /* Chris@43: * Binary read the given (array of) object(s) from the compressed file. Chris@43: * If the input file was not in gzip format, read() copies the objects number Chris@43: * of bytes into the buffer. Chris@43: * returns the number of uncompressed bytes actually read Chris@43: * (0 for end of file, -1 for error). Chris@43: */ Chris@43: template Chris@43: inline int read(izstream& zs, T* x, Items items) { Chris@43: return ::gzread(zs.fp(), x, items*sizeof(T)); Chris@43: } Chris@43: Chris@43: /* Chris@43: * Binary input with the '>' operator. Chris@43: */ Chris@43: template Chris@43: inline izstream& operator>(izstream& zs, T& x) { Chris@43: ::gzread(zs.fp(), &x, sizeof(T)); Chris@43: return zs; Chris@43: } Chris@43: Chris@43: Chris@43: inline zstringlen::zstringlen(izstream& zs) { Chris@43: zs > val.byte; Chris@43: if (val.byte == 255) zs > val.word; Chris@43: else val.word = val.byte; Chris@43: } Chris@43: Chris@43: /* Chris@43: * Read length of string + the string with the '>' operator. Chris@43: */ Chris@43: inline izstream& operator>(izstream& zs, char* x) { Chris@43: zstringlen len(zs); Chris@43: ::gzread(zs.fp(), x, len.value()); Chris@43: x[len.value()] = '\0'; Chris@43: return zs; Chris@43: } Chris@43: Chris@43: inline char* read_string(izstream& zs) { Chris@43: zstringlen len(zs); Chris@43: char* x = new char[len.value()+1]; Chris@43: ::gzread(zs.fp(), x, len.value()); Chris@43: x[len.value()] = '\0'; Chris@43: return x; Chris@43: } Chris@43: Chris@43: // ----------------------------- ozstream ----------------------------- Chris@43: Chris@43: class ozstream Chris@43: { Chris@43: public: Chris@43: ozstream() : m_fp(0), m_os(0) { Chris@43: } Chris@43: ozstream(FILE* fp, int level = Z_DEFAULT_COMPRESSION) Chris@43: : m_fp(0), m_os(0) { Chris@43: open(fp, level); Chris@43: } Chris@43: ozstream(const char* name, int level = Z_DEFAULT_COMPRESSION) Chris@43: : m_fp(0), m_os(0) { Chris@43: open(name, level); Chris@43: } Chris@43: ~ozstream() { Chris@43: close(); Chris@43: } Chris@43: Chris@43: /* Opens a gzip (.gz) file for writing. Chris@43: * The compression level parameter should be in 0..9 Chris@43: * errno can be checked to distinguish two error cases Chris@43: * (if errno is zero, the zlib error is Z_MEM_ERROR). Chris@43: */ Chris@43: void open(const char* name, int level = Z_DEFAULT_COMPRESSION) { Chris@43: char mode[4] = "wb\0"; Chris@43: if (level != Z_DEFAULT_COMPRESSION) mode[2] = '0'+level; Chris@43: if (m_fp) close(); Chris@43: m_fp = ::gzopen(name, mode); Chris@43: } Chris@43: Chris@43: /* open from a FILE pointer. Chris@43: */ Chris@43: void open(FILE* fp, int level = Z_DEFAULT_COMPRESSION) { Chris@43: SET_BINARY_MODE(fp); Chris@43: char mode[4] = "wb\0"; Chris@43: if (level != Z_DEFAULT_COMPRESSION) mode[2] = '0'+level; Chris@43: if (m_fp) close(); Chris@43: m_fp = ::gzdopen(fileno(fp), mode); Chris@43: } Chris@43: Chris@43: /* Flushes all pending output if necessary, closes the compressed file Chris@43: * and deallocates all the (de)compression state. The return value is Chris@43: * the zlib error number (see function error() below). Chris@43: */ Chris@43: int close() { Chris@43: if (m_os) { Chris@43: ::gzwrite(m_fp, m_os->str(), m_os->pcount()); Chris@43: delete[] m_os->str(); delete m_os; m_os = 0; Chris@43: } Chris@43: int r = ::gzclose(m_fp); m_fp = 0; return r; Chris@43: } Chris@43: Chris@43: /* Binary write the given number of bytes into the compressed file. Chris@43: */ Chris@43: int write(const void* buf, size_t len) { Chris@43: return ::gzwrite(m_fp, (voidp) buf, len); Chris@43: } Chris@43: Chris@43: /* Flushes all pending output into the compressed file. The parameter Chris@43: * _flush is as in the deflate() function. The return value is the zlib Chris@43: * error number (see function gzerror below). flush() returns Z_OK if Chris@43: * the flush_ parameter is Z_FINISH and all output could be flushed. Chris@43: * flush() should be called only when strictly necessary because it can Chris@43: * degrade compression. Chris@43: */ Chris@43: int flush(int _flush) { Chris@43: os_flush(); Chris@43: return ::gzflush(m_fp, _flush); Chris@43: } Chris@43: Chris@43: /* Returns the error message for the last error which occurred on the Chris@43: * given compressed file. errnum is set to zlib error number. If an Chris@43: * error occurred in the file system and not in the compression library, Chris@43: * errnum is set to Z_ERRNO and the application may consult errno Chris@43: * to get the exact error code. Chris@43: */ Chris@43: const char* error(int* errnum) { Chris@43: return ::gzerror(m_fp, errnum); Chris@43: } Chris@43: Chris@43: gzFile fp() { return m_fp; } Chris@43: Chris@43: ostream& os() { Chris@43: if (m_os == 0) m_os = new ostrstream; Chris@43: return *m_os; Chris@43: } Chris@43: Chris@43: void os_flush() { Chris@43: if (m_os && m_os->pcount()>0) { Chris@43: ostrstream* oss = new ostrstream; Chris@43: oss->fill(m_os->fill()); Chris@43: oss->flags(m_os->flags()); Chris@43: oss->precision(m_os->precision()); Chris@43: oss->width(m_os->width()); Chris@43: ::gzwrite(m_fp, m_os->str(), m_os->pcount()); Chris@43: delete[] m_os->str(); delete m_os; m_os = oss; Chris@43: } Chris@43: } Chris@43: Chris@43: private: Chris@43: gzFile m_fp; Chris@43: ostrstream* m_os; Chris@43: }; Chris@43: Chris@43: /* Chris@43: * Binary write the given (array of) object(s) into the compressed file. Chris@43: * returns the number of uncompressed bytes actually written Chris@43: * (0 in case of error). Chris@43: */ Chris@43: template Chris@43: inline int write(ozstream& zs, const T* x, Items items) { Chris@43: return ::gzwrite(zs.fp(), (voidp) x, items*sizeof(T)); Chris@43: } Chris@43: Chris@43: /* Chris@43: * Binary output with the '<' operator. Chris@43: */ Chris@43: template Chris@43: inline ozstream& operator<(ozstream& zs, const T& x) { Chris@43: ::gzwrite(zs.fp(), (voidp) &x, sizeof(T)); Chris@43: return zs; Chris@43: } Chris@43: Chris@43: inline zstringlen::zstringlen(ozstream& zs, const char* x) { Chris@43: val.byte = 255; val.word = ::strlen(x); Chris@43: if (val.word < 255) zs < (val.byte = val.word); Chris@43: else zs < val; Chris@43: } Chris@43: Chris@43: /* Chris@43: * Write length of string + the string with the '<' operator. Chris@43: */ Chris@43: inline ozstream& operator<(ozstream& zs, const char* x) { Chris@43: zstringlen len(zs, x); Chris@43: ::gzwrite(zs.fp(), (voidp) x, len.value()); Chris@43: return zs; Chris@43: } Chris@43: Chris@43: #ifdef _MSC_VER Chris@43: inline ozstream& operator<(ozstream& zs, char* const& x) { Chris@43: return zs < (const char*) x; Chris@43: } Chris@43: #endif Chris@43: Chris@43: /* Chris@43: * Ascii write with the << operator; Chris@43: */ Chris@43: template Chris@43: inline ostream& operator<<(ozstream& zs, const T& x) { Chris@43: zs.os_flush(); Chris@43: return zs.os() << x; Chris@43: } Chris@43: Chris@43: #endif