zfstream.h revision 1.1 1 /* $NetBSD: zfstream.h,v 1.1 2006/01/14 20:10:54 christos Exp $ */
2
3 /*
4 * A C++ I/O streams interface to the zlib gz* functions
5 *
6 * by Ludwig Schwardt <schwardt (at) sun.ac.za>
7 * original version by Kevin Ruland <kevin (at) rodin.wustl.edu>
8 *
9 * This version is standard-compliant and compatible with gcc 3.x.
10 */
11
12 #ifndef ZFSTREAM_H
13 #define ZFSTREAM_H
14
15 #include <istream> // not iostream, since we don't need cin/cout
16 #include <ostream>
17 #include "zlib.h"
18
19 /*****************************************************************************/
20
21 /**
22 * @brief Gzipped file stream buffer class.
23 *
24 * This class implements basic_filebuf for gzipped files. It doesn't yet support
25 * seeking (allowed by zlib but slow/limited), putback and read/write access
26 * (tricky). Otherwise, it attempts to be a drop-in replacement for the standard
27 * file streambuf.
28 */
29 class gzfilebuf : public std::streambuf
30 {
31 public:
32 // Default constructor.
33 gzfilebuf();
34
35 // Destructor.
36 virtual
37 ~gzfilebuf();
38
39 /**
40 * @brief Set compression level and strategy on the fly.
41 * @param comp_level Compression level (see zlib.h for allowed values)
42 * @param comp_strategy Compression strategy (see zlib.h for allowed values)
43 * @return Z_OK on success, Z_STREAM_ERROR otherwise.
44 *
45 * Unfortunately, these parameters cannot be modified separately, as the
46 * previous zfstream version assumed. Since the strategy is seldom changed,
47 * it can default and setcompression(level) then becomes like the old
48 * setcompressionlevel(level).
49 */
50 int
51 setcompression(int comp_level,
52 int comp_strategy = Z_DEFAULT_STRATEGY);
53
54 /**
55 * @brief Check if file is open.
56 * @return True if file is open.
57 */
58 bool
59 is_open() const { return (file != NULL); }
60
61 /**
62 * @brief Open gzipped file.
63 * @param name File name.
64 * @param mode Open mode flags.
65 * @return @c this on success, NULL on failure.
66 */
67 gzfilebuf*
68 open(const char* name,
69 std::ios_base::openmode mode);
70
71 /**
72 * @brief Attach to already open gzipped file.
73 * @param fd File descriptor.
74 * @param mode Open mode flags.
75 * @return @c this on success, NULL on failure.
76 */
77 gzfilebuf*
78 attach(int fd,
79 std::ios_base::openmode mode);
80
81 /**
82 * @brief Close gzipped file.
83 * @return @c this on success, NULL on failure.
84 */
85 gzfilebuf*
86 close();
87
88 protected:
89 /**
90 * @brief Convert ios open mode int to mode string used by zlib.
91 * @return True if valid mode flag combination.
92 */
93 bool
94 open_mode(std::ios_base::openmode mode,
95 char* c_mode) const;
96
97 /**
98 * @brief Number of characters available in stream buffer.
99 * @return Number of characters.
100 *
101 * This indicates number of characters in get area of stream buffer.
102 * These characters can be read without accessing the gzipped file.
103 */
104 virtual std::streamsize
105 showmanyc();
106
107 /**
108 * @brief Fill get area from gzipped file.
109 * @return First character in get area on success, EOF on error.
110 *
111 * This actually reads characters from gzipped file to stream
112 * buffer. Always buffered.
113 */
114 virtual int_type
115 underflow();
116
117 /**
118 * @brief Write put area to gzipped file.
119 * @param c Extra character to add to buffer contents.
120 * @return Non-EOF on success, EOF on error.
121 *
122 * This actually writes characters in stream buffer to
123 * gzipped file. With unbuffered output this is done one
124 * character at a time.
125 */
126 virtual int_type
127 overflow(int_type c = traits_type::eof());
128
129 /**
130 * @brief Installs external stream buffer.
131 * @param p Pointer to char buffer.
132 * @param n Size of external buffer.
133 * @return @c this on success, NULL on failure.
134 *
135 * Call setbuf(0,0) to enable unbuffered output.
136 */
137 virtual std::streambuf*
138 setbuf(char_type* p,
139 std::streamsize n);
140
141 /**
142 * @brief Flush stream buffer to file.
143 * @return 0 on success, -1 on error.
144 *
145 * This calls underflow(EOF) to do the job.
146 */
147 virtual int
148 sync();
149
150 //
151 // Some future enhancements
152 //
153 // virtual int_type uflow();
154 // virtual int_type pbackfail(int_type c = traits_type::eof());
155 // virtual pos_type
156 // seekoff(off_type off,
157 // std::ios_base::seekdir way,
158 // std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out);
159 // virtual pos_type
160 // seekpos(pos_type sp,
161 // std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out);
162
163 private:
164 /**
165 * @brief Allocate internal buffer.
166 *
167 * This function is safe to call multiple times. It will ensure
168 * that a proper internal buffer exists if it is required. If the
169 * buffer already exists or is external, the buffer pointers will be
170 * reset to their original state.
171 */
172 void
173 enable_buffer();
174
175 /**
176 * @brief Destroy internal buffer.
177 *
178 * This function is safe to call multiple times. It will ensure
179 * that the internal buffer is deallocated if it exists. In any
180 * case, it will also reset the buffer pointers.
181 */
182 void
183 disable_buffer();
184
185 /**
186 * Underlying file pointer.
187 */
188 gzFile file;
189
190 /**
191 * Mode in which file was opened.
192 */
193 std::ios_base::openmode io_mode;
194
195 /**
196 * @brief True if this object owns file descriptor.
197 *
198 * This makes the class responsible for closing the file
199 * upon destruction.
200 */
201 bool own_fd;
202
203 /**
204 * @brief Stream buffer.
205 *
206 * For simplicity this remains allocated on the free store for the
207 * entire life span of the gzfilebuf object, unless replaced by setbuf.
208 */
209 char_type* buffer;
210
211 /**
212 * @brief Stream buffer size.
213 *
214 * Defaults to system default buffer size (typically 8192 bytes).
215 * Modified by setbuf.
216 */
217 std::streamsize buffer_size;
218
219 /**
220 * @brief True if this object owns stream buffer.
221 *
222 * This makes the class responsible for deleting the buffer
223 * upon destruction.
224 */
225 bool own_buffer;
226 };
227
228 /*****************************************************************************/
229
230 /**
231 * @brief Gzipped file input stream class.
232 *
233 * This class implements ifstream for gzipped files. Seeking and putback
234 * is not supported yet.
235 */
236 class gzifstream : public std::istream
237 {
238 public:
239 // Default constructor
240 gzifstream();
241
242 /**
243 * @brief Construct stream on gzipped file to be opened.
244 * @param name File name.
245 * @param mode Open mode flags (forced to contain ios::in).
246 */
247 explicit
248 gzifstream(const char* name,
249 std::ios_base::openmode mode = std::ios_base::in);
250
251 /**
252 * @brief Construct stream on already open gzipped file.
253 * @param fd File descriptor.
254 * @param mode Open mode flags (forced to contain ios::in).
255 */
256 explicit
257 gzifstream(int fd,
258 std::ios_base::openmode mode = std::ios_base::in);
259
260 /**
261 * Obtain underlying stream buffer.
262 */
263 gzfilebuf*
264 rdbuf() const
265 { return const_cast<gzfilebuf*>(&sb); }
266
267 /**
268 * @brief Check if file is open.
269 * @return True if file is open.
270 */
271 bool
272 is_open() { return sb.is_open(); }
273
274 /**
275 * @brief Open gzipped file.
276 * @param name File name.
277 * @param mode Open mode flags (forced to contain ios::in).
278 *
279 * Stream will be in state good() if file opens successfully;
280 * otherwise in state fail(). This differs from the behavior of
281 * ifstream, which never sets the state to good() and therefore
282 * won't allow you to reuse the stream for a second file unless
283 * you manually clear() the state. The choice is a matter of
284 * convenience.
285 */
286 void
287 open(const char* name,
288 std::ios_base::openmode mode = std::ios_base::in);
289
290 /**
291 * @brief Attach to already open gzipped file.
292 * @param fd File descriptor.
293 * @param mode Open mode flags (forced to contain ios::in).
294 *
295 * Stream will be in state good() if attach succeeded; otherwise
296 * in state fail().
297 */
298 void
299 attach(int fd,
300 std::ios_base::openmode mode = std::ios_base::in);
301
302 /**
303 * @brief Close gzipped file.
304 *
305 * Stream will be in state fail() if close failed.
306 */
307 void
308 close();
309
310 private:
311 /**
312 * Underlying stream buffer.
313 */
314 gzfilebuf sb;
315 };
316
317 /*****************************************************************************/
318
319 /**
320 * @brief Gzipped file output stream class.
321 *
322 * This class implements ofstream for gzipped files. Seeking and putback
323 * is not supported yet.
324 */
325 class gzofstream : public std::ostream
326 {
327 public:
328 // Default constructor
329 gzofstream();
330
331 /**
332 * @brief Construct stream on gzipped file to be opened.
333 * @param name File name.
334 * @param mode Open mode flags (forced to contain ios::out).
335 */
336 explicit
337 gzofstream(const char* name,
338 std::ios_base::openmode mode = std::ios_base::out);
339
340 /**
341 * @brief Construct stream on already open gzipped file.
342 * @param fd File descriptor.
343 * @param mode Open mode flags (forced to contain ios::out).
344 */
345 explicit
346 gzofstream(int fd,
347 std::ios_base::openmode mode = std::ios_base::out);
348
349 /**
350 * Obtain underlying stream buffer.
351 */
352 gzfilebuf*
353 rdbuf() const
354 { return const_cast<gzfilebuf*>(&sb); }
355
356 /**
357 * @brief Check if file is open.
358 * @return True if file is open.
359 */
360 bool
361 is_open() { return sb.is_open(); }
362
363 /**
364 * @brief Open gzipped file.
365 * @param name File name.
366 * @param mode Open mode flags (forced to contain ios::out).
367 *
368 * Stream will be in state good() if file opens successfully;
369 * otherwise in state fail(). This differs from the behavior of
370 * ofstream, which never sets the state to good() and therefore
371 * won't allow you to reuse the stream for a second file unless
372 * you manually clear() the state. The choice is a matter of
373 * convenience.
374 */
375 void
376 open(const char* name,
377 std::ios_base::openmode mode = std::ios_base::out);
378
379 /**
380 * @brief Attach to already open gzipped file.
381 * @param fd File descriptor.
382 * @param mode Open mode flags (forced to contain ios::out).
383 *
384 * Stream will be in state good() if attach succeeded; otherwise
385 * in state fail().
386 */
387 void
388 attach(int fd,
389 std::ios_base::openmode mode = std::ios_base::out);
390
391 /**
392 * @brief Close gzipped file.
393 *
394 * Stream will be in state fail() if close failed.
395 */
396 void
397 close();
398
399 private:
400 /**
401 * Underlying stream buffer.
402 */
403 gzfilebuf sb;
404 };
405
406 /*****************************************************************************/
407
408 /**
409 * @brief Gzipped file output stream manipulator class.
410 *
411 * This class defines a two-argument manipulator for gzofstream. It is used
412 * as base for the setcompression(int,int) manipulator.
413 */
414 template<typename T1, typename T2>
415 class gzomanip2
416 {
417 public:
418 // Allows insertor to peek at internals
419 template <typename Ta, typename Tb>
420 friend gzofstream&
421 operator<<(gzofstream&,
422 const gzomanip2<Ta,Tb>&);
423
424 // Constructor
425 gzomanip2(gzofstream& (*f)(gzofstream&, T1, T2),
426 T1 v1,
427 T2 v2);
428 private:
429 // Underlying manipulator function
430 gzofstream&
431 (*func)(gzofstream&, T1, T2);
432
433 // Arguments for manipulator function
434 T1 val1;
435 T2 val2;
436 };
437
438 /*****************************************************************************/
439
440 // Manipulator function thunks through to stream buffer
441 inline gzofstream&
442 setcompression(gzofstream &gzs, int l, int s = Z_DEFAULT_STRATEGY)
443 {
444 (gzs.rdbuf())->setcompression(l, s);
445 return gzs;
446 }
447
448 // Manipulator constructor stores arguments
449 template<typename T1, typename T2>
450 inline
451 gzomanip2<T1,T2>::gzomanip2(gzofstream &(*f)(gzofstream &, T1, T2),
452 T1 v1,
453 T2 v2)
454 : func(f), val1(v1), val2(v2)
455 { }
456
457 // Insertor applies underlying manipulator function to stream
458 template<typename T1, typename T2>
459 inline gzofstream&
460 operator<<(gzofstream& s, const gzomanip2<T1,T2>& m)
461 { return (*m.func)(s, m.val1, m.val2); }
462
463 // Insert this onto stream to simplify setting of compression level
464 inline gzomanip2<int,int>
465 setcompression(int l, int s = Z_DEFAULT_STRATEGY)
466 { return gzomanip2<int,int>(&setcompression, l, s); }
467
468 #endif // ZFSTREAM_H
469