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