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