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*);
value()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:
izstream()56         izstream() : m_fp(0) {}
izstream(FILE * fp)57         izstream(FILE* fp) : m_fp(0) { open(fp); }
izstream(const char * name)58         izstream(const char* name) : m_fp(0) { open(name); }
~izstream()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          */
open(const char * name)67         void open(const char* name) {
68             if (m_fp) close();
69             m_fp = ::gzopen(name, "rb");
70         }
71 
open(FILE * fp)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          */
close()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          */
read(void * buf,size_t len)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          */
error(int * errnum)99         const char* error(int* errnum) {
100             return ::gzerror(m_fp, errnum);
101         }
102 
fp()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>
read(izstream & zs,T * x,Items 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 
zstringlen(izstream & zs)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 
read_string(izstream & zs)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:
ozstream()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         }
~ozstream()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          */
close()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          */
write(const void * buf,size_t len)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          */
flush(int _flush)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          */
error(int * errnum)232         const char* error(int* errnum) {
233             return ::gzerror(m_fp, errnum);
234         }
235 
fp()236         gzFile fp() { return m_fp; }
237 
os()238         ostream& os() {
239             if (m_os == 0) m_os = new ostrstream;
240             return *m_os;
241         }
242 
os_flush()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>
write(ozstream & zs,const T * x,Items 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 
zstringlen(ozstream & zs,const char * x)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