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