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