1275793eaSopenharmony_ci/*
2275793eaSopenharmony_ci *
3275793eaSopenharmony_ci * Copyright (c) 1997
4275793eaSopenharmony_ci * Christian Michelsen Research AS
5275793eaSopenharmony_ci * Advanced Computing
6275793eaSopenharmony_ci * Fantoftvegen 38, 5036 BERGEN, Norway
7275793eaSopenharmony_ci * http://www.cmr.no
8275793eaSopenharmony_ci *
9275793eaSopenharmony_ci * Permission to use, copy, modify, distribute and sell this software
10275793eaSopenharmony_ci * and its documentation for any purpose is hereby granted without fee,
11275793eaSopenharmony_ci * provided that the above copyright notice appear in all copies and
12275793eaSopenharmony_ci * that both that copyright notice and this permission notice appear
13275793eaSopenharmony_ci * in supporting documentation.  Christian Michelsen Research AS makes no
14275793eaSopenharmony_ci * representations about the suitability of this software for any
15275793eaSopenharmony_ci * purpose.  It is provided "as is" without express or implied warranty.
16275793eaSopenharmony_ci *
17275793eaSopenharmony_ci */
18275793eaSopenharmony_ci
19275793eaSopenharmony_ci#ifndef ZSTREAM__H
20275793eaSopenharmony_ci#define ZSTREAM__H
21275793eaSopenharmony_ci
22275793eaSopenharmony_ci/*
23275793eaSopenharmony_ci * zstream.h - C++ interface to the 'zlib' general purpose compression library
24275793eaSopenharmony_ci * $Id: zstream.h 1.1 1997-06-25 12:00:56+02 tyge Exp tyge $
25275793eaSopenharmony_ci */
26275793eaSopenharmony_ci
27275793eaSopenharmony_ci#include <strstream.h>
28275793eaSopenharmony_ci#include <string.h>
29275793eaSopenharmony_ci#include <stdio.h>
30275793eaSopenharmony_ci#include "zlib.h"
31275793eaSopenharmony_ci
32275793eaSopenharmony_ci#if defined(_WIN32)
33275793eaSopenharmony_ci#   include <fcntl.h>
34275793eaSopenharmony_ci#   include <io.h>
35275793eaSopenharmony_ci#   define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
36275793eaSopenharmony_ci#else
37275793eaSopenharmony_ci#   define SET_BINARY_MODE(file)
38275793eaSopenharmony_ci#endif
39275793eaSopenharmony_ci
40275793eaSopenharmony_ciclass zstringlen {
41275793eaSopenharmony_cipublic:
42275793eaSopenharmony_ci    zstringlen(class izstream&);
43275793eaSopenharmony_ci    zstringlen(class ozstream&, const char*);
44275793eaSopenharmony_ci    size_t value() const { return val.word; }
45275793eaSopenharmony_ciprivate:
46275793eaSopenharmony_ci    struct Val { unsigned char byte; size_t word; } val;
47275793eaSopenharmony_ci};
48275793eaSopenharmony_ci
49275793eaSopenharmony_ci//  ----------------------------- izstream -----------------------------
50275793eaSopenharmony_ci
51275793eaSopenharmony_ciclass izstream
52275793eaSopenharmony_ci{
53275793eaSopenharmony_ci    public:
54275793eaSopenharmony_ci        izstream() : m_fp(0) {}
55275793eaSopenharmony_ci        izstream(FILE* fp) : m_fp(0) { open(fp); }
56275793eaSopenharmony_ci        izstream(const char* name) : m_fp(0) { open(name); }
57275793eaSopenharmony_ci        ~izstream() { close(); }
58275793eaSopenharmony_ci
59275793eaSopenharmony_ci        /* Opens a gzip (.gz) file for reading.
60275793eaSopenharmony_ci         * open() can be used to read a file which is not in gzip format;
61275793eaSopenharmony_ci         * in this case read() will directly read from the file without
62275793eaSopenharmony_ci         * decompression. errno can be checked to distinguish two error
63275793eaSopenharmony_ci         * cases (if errno is zero, the zlib error is Z_MEM_ERROR).
64275793eaSopenharmony_ci         */
65275793eaSopenharmony_ci        void open(const char* name) {
66275793eaSopenharmony_ci            if (m_fp) close();
67275793eaSopenharmony_ci            m_fp = ::gzopen(name, "rb");
68275793eaSopenharmony_ci        }
69275793eaSopenharmony_ci
70275793eaSopenharmony_ci        void open(FILE* fp) {
71275793eaSopenharmony_ci            SET_BINARY_MODE(fp);
72275793eaSopenharmony_ci            if (m_fp) close();
73275793eaSopenharmony_ci            m_fp = ::gzdopen(fileno(fp), "rb");
74275793eaSopenharmony_ci        }
75275793eaSopenharmony_ci
76275793eaSopenharmony_ci        /* Flushes all pending input if necessary, closes the compressed file
77275793eaSopenharmony_ci         * and deallocates all the (de)compression state. The return value is
78275793eaSopenharmony_ci         * the zlib error number (see function error() below).
79275793eaSopenharmony_ci         */
80275793eaSopenharmony_ci        int close() {
81275793eaSopenharmony_ci            int r = ::gzclose(m_fp);
82275793eaSopenharmony_ci            m_fp = 0; return r;
83275793eaSopenharmony_ci        }
84275793eaSopenharmony_ci
85275793eaSopenharmony_ci        /* Binary read the given number of bytes from the compressed file.
86275793eaSopenharmony_ci         */
87275793eaSopenharmony_ci        int read(void* buf, size_t len) {
88275793eaSopenharmony_ci            return ::gzread(m_fp, buf, len);
89275793eaSopenharmony_ci        }
90275793eaSopenharmony_ci
91275793eaSopenharmony_ci        /* Returns the error message for the last error which occurred on the
92275793eaSopenharmony_ci         * given compressed file. errnum is set to zlib error number. If an
93275793eaSopenharmony_ci         * error occurred in the file system and not in the compression library,
94275793eaSopenharmony_ci         * errnum is set to Z_ERRNO and the application may consult errno
95275793eaSopenharmony_ci         * to get the exact error code.
96275793eaSopenharmony_ci         */
97275793eaSopenharmony_ci        const char* error(int* errnum) {
98275793eaSopenharmony_ci            return ::gzerror(m_fp, errnum);
99275793eaSopenharmony_ci        }
100275793eaSopenharmony_ci
101275793eaSopenharmony_ci        gzFile fp() { return m_fp; }
102275793eaSopenharmony_ci
103275793eaSopenharmony_ci    private:
104275793eaSopenharmony_ci        gzFile m_fp;
105275793eaSopenharmony_ci};
106275793eaSopenharmony_ci
107275793eaSopenharmony_ci/*
108275793eaSopenharmony_ci * Binary read the given (array of) object(s) from the compressed file.
109275793eaSopenharmony_ci * If the input file was not in gzip format, read() copies the objects number
110275793eaSopenharmony_ci * of bytes into the buffer.
111275793eaSopenharmony_ci * returns the number of uncompressed bytes actually read
112275793eaSopenharmony_ci * (0 for end of file, -1 for error).
113275793eaSopenharmony_ci */
114275793eaSopenharmony_citemplate <class T, class Items>
115275793eaSopenharmony_ciinline int read(izstream& zs, T* x, Items items) {
116275793eaSopenharmony_ci    return ::gzread(zs.fp(), x, items*sizeof(T));
117275793eaSopenharmony_ci}
118275793eaSopenharmony_ci
119275793eaSopenharmony_ci/*
120275793eaSopenharmony_ci * Binary input with the '>' operator.
121275793eaSopenharmony_ci */
122275793eaSopenharmony_citemplate <class T>
123275793eaSopenharmony_ciinline izstream& operator>(izstream& zs, T& x) {
124275793eaSopenharmony_ci    ::gzread(zs.fp(), &x, sizeof(T));
125275793eaSopenharmony_ci    return zs;
126275793eaSopenharmony_ci}
127275793eaSopenharmony_ci
128275793eaSopenharmony_ci
129275793eaSopenharmony_ciinline zstringlen::zstringlen(izstream& zs) {
130275793eaSopenharmony_ci    zs > val.byte;
131275793eaSopenharmony_ci    if (val.byte == 255) zs > val.word;
132275793eaSopenharmony_ci    else val.word = val.byte;
133275793eaSopenharmony_ci}
134275793eaSopenharmony_ci
135275793eaSopenharmony_ci/*
136275793eaSopenharmony_ci * Read length of string + the string with the '>' operator.
137275793eaSopenharmony_ci */
138275793eaSopenharmony_ciinline izstream& operator>(izstream& zs, char* x) {
139275793eaSopenharmony_ci    zstringlen len(zs);
140275793eaSopenharmony_ci    ::gzread(zs.fp(), x, len.value());
141275793eaSopenharmony_ci    x[len.value()] = '\0';
142275793eaSopenharmony_ci    return zs;
143275793eaSopenharmony_ci}
144275793eaSopenharmony_ci
145275793eaSopenharmony_ciinline char* read_string(izstream& zs) {
146275793eaSopenharmony_ci    zstringlen len(zs);
147275793eaSopenharmony_ci    char* x = new char[len.value()+1];
148275793eaSopenharmony_ci    ::gzread(zs.fp(), x, len.value());
149275793eaSopenharmony_ci    x[len.value()] = '\0';
150275793eaSopenharmony_ci    return x;
151275793eaSopenharmony_ci}
152275793eaSopenharmony_ci
153275793eaSopenharmony_ci// ----------------------------- ozstream -----------------------------
154275793eaSopenharmony_ci
155275793eaSopenharmony_ciclass ozstream
156275793eaSopenharmony_ci{
157275793eaSopenharmony_ci    public:
158275793eaSopenharmony_ci        ozstream() : m_fp(0), m_os(0) {
159275793eaSopenharmony_ci        }
160275793eaSopenharmony_ci        ozstream(FILE* fp, int level = Z_DEFAULT_COMPRESSION)
161275793eaSopenharmony_ci            : m_fp(0), m_os(0) {
162275793eaSopenharmony_ci            open(fp, level);
163275793eaSopenharmony_ci        }
164275793eaSopenharmony_ci        ozstream(const char* name, int level = Z_DEFAULT_COMPRESSION)
165275793eaSopenharmony_ci            : m_fp(0), m_os(0) {
166275793eaSopenharmony_ci            open(name, level);
167275793eaSopenharmony_ci        }
168275793eaSopenharmony_ci        ~ozstream() {
169275793eaSopenharmony_ci            close();
170275793eaSopenharmony_ci        }
171275793eaSopenharmony_ci
172275793eaSopenharmony_ci        /* Opens a gzip (.gz) file for writing.
173275793eaSopenharmony_ci         * The compression level parameter should be in 0..9
174275793eaSopenharmony_ci         * errno can be checked to distinguish two error cases
175275793eaSopenharmony_ci         * (if errno is zero, the zlib error is Z_MEM_ERROR).
176275793eaSopenharmony_ci         */
177275793eaSopenharmony_ci        void open(const char* name, int level = Z_DEFAULT_COMPRESSION) {
178275793eaSopenharmony_ci            char mode[4] = "wb\0";
179275793eaSopenharmony_ci            if (level != Z_DEFAULT_COMPRESSION) mode[2] = '0'+level;
180275793eaSopenharmony_ci            if (m_fp) close();
181275793eaSopenharmony_ci            m_fp = ::gzopen(name, mode);
182275793eaSopenharmony_ci        }
183275793eaSopenharmony_ci
184275793eaSopenharmony_ci        /* open from a FILE pointer.
185275793eaSopenharmony_ci         */
186275793eaSopenharmony_ci        void open(FILE* fp, int level = Z_DEFAULT_COMPRESSION) {
187275793eaSopenharmony_ci            SET_BINARY_MODE(fp);
188275793eaSopenharmony_ci            char mode[4] = "wb\0";
189275793eaSopenharmony_ci            if (level != Z_DEFAULT_COMPRESSION) mode[2] = '0'+level;
190275793eaSopenharmony_ci            if (m_fp) close();
191275793eaSopenharmony_ci            m_fp = ::gzdopen(fileno(fp), mode);
192275793eaSopenharmony_ci        }
193275793eaSopenharmony_ci
194275793eaSopenharmony_ci        /* Flushes all pending output if necessary, closes the compressed file
195275793eaSopenharmony_ci         * and deallocates all the (de)compression state. The return value is
196275793eaSopenharmony_ci         * the zlib error number (see function error() below).
197275793eaSopenharmony_ci         */
198275793eaSopenharmony_ci        int close() {
199275793eaSopenharmony_ci            if (m_os) {
200275793eaSopenharmony_ci                ::gzwrite(m_fp, m_os->str(), m_os->pcount());
201275793eaSopenharmony_ci                delete[] m_os->str(); delete m_os; m_os = 0;
202275793eaSopenharmony_ci            }
203275793eaSopenharmony_ci            int r = ::gzclose(m_fp); m_fp = 0; return r;
204275793eaSopenharmony_ci        }
205275793eaSopenharmony_ci
206275793eaSopenharmony_ci        /* Binary write the given number of bytes into the compressed file.
207275793eaSopenharmony_ci         */
208275793eaSopenharmony_ci        int write(const void* buf, size_t len) {
209275793eaSopenharmony_ci            return ::gzwrite(m_fp, (voidp) buf, len);
210275793eaSopenharmony_ci        }
211275793eaSopenharmony_ci
212275793eaSopenharmony_ci        /* Flushes all pending output into the compressed file. The parameter
213275793eaSopenharmony_ci         * _flush is as in the deflate() function. The return value is the zlib
214275793eaSopenharmony_ci         * error number (see function gzerror below). flush() returns Z_OK if
215275793eaSopenharmony_ci         * the flush_ parameter is Z_FINISH and all output could be flushed.
216275793eaSopenharmony_ci         * flush() should be called only when strictly necessary because it can
217275793eaSopenharmony_ci         * degrade compression.
218275793eaSopenharmony_ci         */
219275793eaSopenharmony_ci        int flush(int _flush) {
220275793eaSopenharmony_ci            os_flush();
221275793eaSopenharmony_ci            return ::gzflush(m_fp, _flush);
222275793eaSopenharmony_ci        }
223275793eaSopenharmony_ci
224275793eaSopenharmony_ci        /* Returns the error message for the last error which occurred on the
225275793eaSopenharmony_ci         * given compressed file. errnum is set to zlib error number. If an
226275793eaSopenharmony_ci         * error occurred in the file system and not in the compression library,
227275793eaSopenharmony_ci         * errnum is set to Z_ERRNO and the application may consult errno
228275793eaSopenharmony_ci         * to get the exact error code.
229275793eaSopenharmony_ci         */
230275793eaSopenharmony_ci        const char* error(int* errnum) {
231275793eaSopenharmony_ci            return ::gzerror(m_fp, errnum);
232275793eaSopenharmony_ci        }
233275793eaSopenharmony_ci
234275793eaSopenharmony_ci        gzFile fp() { return m_fp; }
235275793eaSopenharmony_ci
236275793eaSopenharmony_ci        ostream& os() {
237275793eaSopenharmony_ci            if (m_os == 0) m_os = new ostrstream;
238275793eaSopenharmony_ci            return *m_os;
239275793eaSopenharmony_ci        }
240275793eaSopenharmony_ci
241275793eaSopenharmony_ci        void os_flush() {
242275793eaSopenharmony_ci            if (m_os && m_os->pcount()>0) {
243275793eaSopenharmony_ci                ostrstream* oss = new ostrstream;
244275793eaSopenharmony_ci                oss->fill(m_os->fill());
245275793eaSopenharmony_ci                oss->flags(m_os->flags());
246275793eaSopenharmony_ci                oss->precision(m_os->precision());
247275793eaSopenharmony_ci                oss->width(m_os->width());
248275793eaSopenharmony_ci                ::gzwrite(m_fp, m_os->str(), m_os->pcount());
249275793eaSopenharmony_ci                delete[] m_os->str(); delete m_os; m_os = oss;
250275793eaSopenharmony_ci            }
251275793eaSopenharmony_ci        }
252275793eaSopenharmony_ci
253275793eaSopenharmony_ci    private:
254275793eaSopenharmony_ci        gzFile m_fp;
255275793eaSopenharmony_ci        ostrstream* m_os;
256275793eaSopenharmony_ci};
257275793eaSopenharmony_ci
258275793eaSopenharmony_ci/*
259275793eaSopenharmony_ci * Binary write the given (array of) object(s) into the compressed file.
260275793eaSopenharmony_ci * returns the number of uncompressed bytes actually written
261275793eaSopenharmony_ci * (0 in case of error).
262275793eaSopenharmony_ci */
263275793eaSopenharmony_citemplate <class T, class Items>
264275793eaSopenharmony_ciinline int write(ozstream& zs, const T* x, Items items) {
265275793eaSopenharmony_ci    return ::gzwrite(zs.fp(), (voidp) x, items*sizeof(T));
266275793eaSopenharmony_ci}
267275793eaSopenharmony_ci
268275793eaSopenharmony_ci/*
269275793eaSopenharmony_ci * Binary output with the '<' operator.
270275793eaSopenharmony_ci */
271275793eaSopenharmony_citemplate <class T>
272275793eaSopenharmony_ciinline ozstream& operator<(ozstream& zs, const T& x) {
273275793eaSopenharmony_ci    ::gzwrite(zs.fp(), (voidp) &x, sizeof(T));
274275793eaSopenharmony_ci    return zs;
275275793eaSopenharmony_ci}
276275793eaSopenharmony_ci
277275793eaSopenharmony_ciinline zstringlen::zstringlen(ozstream& zs, const char* x) {
278275793eaSopenharmony_ci    val.byte = 255;  val.word = ::strlen(x);
279275793eaSopenharmony_ci    if (val.word < 255) zs < (val.byte = val.word);
280275793eaSopenharmony_ci    else zs < val;
281275793eaSopenharmony_ci}
282275793eaSopenharmony_ci
283275793eaSopenharmony_ci/*
284275793eaSopenharmony_ci * Write length of string + the string with the '<' operator.
285275793eaSopenharmony_ci */
286275793eaSopenharmony_ciinline ozstream& operator<(ozstream& zs, const char* x) {
287275793eaSopenharmony_ci    zstringlen len(zs, x);
288275793eaSopenharmony_ci    ::gzwrite(zs.fp(), (voidp) x, len.value());
289275793eaSopenharmony_ci    return zs;
290275793eaSopenharmony_ci}
291275793eaSopenharmony_ci
292275793eaSopenharmony_ci#ifdef _MSC_VER
293275793eaSopenharmony_ciinline ozstream& operator<(ozstream& zs, char* const& x) {
294275793eaSopenharmony_ci    return zs < (const char*) x;
295275793eaSopenharmony_ci}
296275793eaSopenharmony_ci#endif
297275793eaSopenharmony_ci
298275793eaSopenharmony_ci/*
299275793eaSopenharmony_ci * Ascii write with the << operator;
300275793eaSopenharmony_ci */
301275793eaSopenharmony_citemplate <class T>
302275793eaSopenharmony_ciinline ostream& operator<<(ozstream& zs, const T& x) {
303275793eaSopenharmony_ci    zs.os_flush();
304275793eaSopenharmony_ci    return zs.os() << x;
305275793eaSopenharmony_ci}
306275793eaSopenharmony_ci
307275793eaSopenharmony_ci#endif
308