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