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