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