summaryrefslogtreecommitdiff
path: root/contrib/iostream3
diff options
context:
space:
mode:
authorMark Adler <madler@alumni.caltech.edu>2011-09-09 23:22:10 -0700
committerMark Adler <madler@alumni.caltech.edu>2011-09-09 23:22:10 -0700
commit8e34b3a8024c028dd9fd21d70525fc6d215efde5 (patch)
tree896a32f54abdf42ae3c1bb3c5d5627668b481ce4 /contrib/iostream3
parent13a294f044ef0a89b2dcbfbb5d4d4c792673348e (diff)
downloadzlib-1.2.0.2.tar.gz
zlib-1.2.0.2.tar.bz2
zlib-1.2.0.2.zip
zlib 1.2.0.2v1.2.0.2
Diffstat (limited to 'contrib/iostream3')
-rw-r--r--contrib/iostream3/README35
-rw-r--r--contrib/iostream3/TODO17
-rw-r--r--contrib/iostream3/test.cc50
-rw-r--r--contrib/iostream3/zfstream.cc479
-rw-r--r--contrib/iostream3/zfstream.h466
5 files changed, 1047 insertions, 0 deletions
diff --git a/contrib/iostream3/README b/contrib/iostream3/README
new file mode 100644
index 0000000..6f73d58
--- /dev/null
+++ b/contrib/iostream3/README
@@ -0,0 +1,35 @@
1These classes provide a C++ stream interface to the zlib library. It allows you
2to do things like:
3
4 gzofstream outf("blah.gz");
5 outf << "These go into the gzip file " << 123 << endl;
6
7It does this by deriving a specialized stream buffer for gzipped files, which is
8the way Stroustrup would have done it. :->
9
10The gzifstream and gzofstream classes were originally written by Kevin Ruland
11and made available in the zlib contrib/iostream directory. The older version still
12compiles under gcc 2.xx, but not under gcc 3.xx, which sparked the development of
13this version.
14
15The new classes are as standard-compliant as possible, closely following the
16approach of the standard library's fstream classes. It compiles under gcc versions
173.2 and 3.3, but not under gcc 2.xx. This is mainly due to changes in the standard
18library naming scheme. The new version of gzifstream/gzofstream/gzfilebuf differs
19from the previous one in the following respects:
20- added showmanyc
21- added setbuf, with support for unbuffered output via setbuf(0,0)
22- a few bug fixes of stream behavior
23- gzipped output file opened with default compression level instead of maximum level
24- setcompressionlevel()/strategy() members replaced by single setcompression()
25
26The code is provided "as is", with the permission to use, copy, modify, distribute
27and sell it for any purpose without fee.
28
29Ludwig Schwardt
30<schwardt@sun.ac.za>
31
32DSP Lab
33Electrical & Electronic Engineering Department
34University of Stellenbosch
35South Africa
diff --git a/contrib/iostream3/TODO b/contrib/iostream3/TODO
new file mode 100644
index 0000000..4578326
--- /dev/null
+++ b/contrib/iostream3/TODO
@@ -0,0 +1,17 @@
1Possible upgrades to gzfilebuf:
2
3- The ability to do putback (e.g. putbackfail)
4
5- The ability to seek (zlib supports this, but could be slow/tricky)
6
7- Simultaneous read/write access (does it make sense?)
8
9- Support for ios_base::ate open mode
10
11- Locale support?
12
13- Check public interface to see which calls give problems
14 (due to dependence on library internals)
15
16- Override operator<<(ostream&, gzfilebuf*) to allow direct copying
17 of stream buffer to stream ( i.e. os << is.rdbuf(); )
diff --git a/contrib/iostream3/test.cc b/contrib/iostream3/test.cc
new file mode 100644
index 0000000..9ffa8be
--- /dev/null
+++ b/contrib/iostream3/test.cc
@@ -0,0 +1,50 @@
1/*
2 * Test program for gzifstream and gzofstream
3 *
4 * by Ludwig Schwardt <schwardt@sun.ac.za>
5 * original version by Kevin Ruland <kevin@rodin.wustl.edu>
6 */
7
8#include "zfstream.h"
9#include <iostream> // for cout
10
11int main() {
12
13 gzofstream outf;
14 gzifstream inf;
15 char buf[80];
16
17 outf.open("test1.txt.gz");
18 outf << "The quick brown fox sidestepped the lazy canine\n"
19 << 1.3 << "\nPlan " << 9 << std::endl;
20 outf.close();
21 std::cout << "Wrote the following message to 'test1.txt.gz' (check with zcat or zless):\n"
22 << "The quick brown fox sidestepped the lazy canine\n"
23 << 1.3 << "\nPlan " << 9 << std::endl;
24
25 std::cout << "\nReading 'test1.txt.gz' (buffered) produces:\n";
26 inf.open("test1.txt.gz");
27 while (inf.getline(buf,80,'\n')) {
28 std::cout << buf << "\t(" << inf.rdbuf()->in_avail() << " chars left in buffer)\n";
29 }
30 inf.close();
31
32 outf.rdbuf()->pubsetbuf(0,0);
33 outf.open("test2.txt.gz");
34 outf << setcompression(Z_NO_COMPRESSION)
35 << "The quick brown fox sidestepped the lazy canine\n"
36 << 1.3 << "\nPlan " << 9 << std::endl;
37 outf.close();
38 std::cout << "\nWrote the same message to 'test2.txt.gz' in uncompressed form";
39
40 std::cout << "\nReading 'test2.txt.gz' (unbuffered) produces:\n";
41 inf.rdbuf()->pubsetbuf(0,0);
42 inf.open("test2.txt.gz");
43 while (inf.getline(buf,80,'\n')) {
44 std::cout << buf << "\t(" << inf.rdbuf()->in_avail() << " chars left in buffer)\n";
45 }
46 inf.close();
47
48 return 0;
49
50}
diff --git a/contrib/iostream3/zfstream.cc b/contrib/iostream3/zfstream.cc
new file mode 100644
index 0000000..24d15fa
--- /dev/null
+++ b/contrib/iostream3/zfstream.cc
@@ -0,0 +1,479 @@
1/*
2 * A C++ I/O streams interface to the zlib gz* functions
3 *
4 * by Ludwig Schwardt <schwardt@sun.ac.za>
5 * original version by Kevin Ruland <kevin@rodin.wustl.edu>
6 *
7 * This version is standard-compliant and compatible with gcc 3.x.
8 */
9
10#include "zfstream.h"
11#include <cstring> // for strcpy, strcat, strlen (mode strings)
12#include <cstdio> // for BUFSIZ
13
14// Internal buffer sizes (default and "unbuffered" versions)
15#define BIGBUFSIZE BUFSIZ
16#define SMALLBUFSIZE 1
17
18/*****************************************************************************/
19
20// Default constructor
21gzfilebuf::gzfilebuf()
22: file(NULL), io_mode(std::ios_base::openmode(0)), own_fd(false),
23 buffer(NULL), buffer_size(BIGBUFSIZE), own_buffer(true)
24{
25 // No buffers to start with
26 this->disable_buffer();
27}
28
29// Destructor
30gzfilebuf::~gzfilebuf()
31{
32 // Sync output buffer and close only if responsible for file
33 // (i.e. attached streams should be left open at this stage)
34 this->sync();
35 if (own_fd)
36 this->close();
37 // Make sure internal buffer is deallocated
38 this->disable_buffer();
39}
40
41// Set compression level and strategy
42int
43gzfilebuf::setcompression(int comp_level,
44 int comp_strategy)
45{
46 return gzsetparams(file, comp_level, comp_strategy);
47}
48
49// Open gzipped file
50gzfilebuf*
51gzfilebuf::open(const char *name,
52 std::ios_base::openmode mode)
53{
54 // Fail if file already open
55 if (this->is_open())
56 return NULL;
57 // Don't support simultaneous read/write access (yet)
58 if ((mode & std::ios_base::in) && (mode & std::ios_base::out))
59 return NULL;
60
61 // Build mode string for gzopen and check it [27.8.1.3.2]
62 char char_mode[6] = "\0\0\0\0\0";
63 if (!this->open_mode(mode, char_mode))
64 return NULL;
65
66 // Attempt to open file
67 if ((file = gzopen(name, char_mode)) == NULL)
68 return NULL;
69
70 // On success, allocate internal buffer and set flags
71 this->enable_buffer();
72 io_mode = mode;
73 own_fd = true;
74 return this;
75}
76
77// Attach to gzipped file
78gzfilebuf*
79gzfilebuf::attach(int fd,
80 std::ios_base::openmode mode)
81{
82 // Fail if file already open
83 if (this->is_open())
84 return NULL;
85 // Don't support simultaneous read/write access (yet)
86 if ((mode & std::ios_base::in) && (mode & std::ios_base::out))
87 return NULL;
88
89 // Build mode string for gzdopen and check it [27.8.1.3.2]
90 char char_mode[6] = "\0\0\0\0\0";
91 if (!this->open_mode(mode, char_mode))
92 return NULL;
93
94 // Attempt to attach to file
95 if ((file = gzdopen(fd, char_mode)) == NULL)
96 return NULL;
97
98 // On success, allocate internal buffer and set flags
99 this->enable_buffer();
100 io_mode = mode;
101 own_fd = false;
102 return this;
103}
104
105// Close gzipped file
106gzfilebuf*
107gzfilebuf::close()
108{
109 // Fail immediately if no file is open
110 if (!this->is_open())
111 return NULL;
112 // Assume success
113 gzfilebuf* retval = this;
114 // Attempt to sync and close gzipped file
115 if (this->sync() == -1)
116 retval = NULL;
117 if (gzclose(file) < 0)
118 retval = NULL;
119 // File is now gone anyway (postcondition [27.8.1.3.8])
120 file = NULL;
121 own_fd = false;
122 // Destroy internal buffer if it exists
123 this->disable_buffer();
124 return retval;
125}
126
127/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
128
129// Convert int open mode to mode string
130bool
131gzfilebuf::open_mode(std::ios_base::openmode mode,
132 char* c_mode) const
133{
134 bool testb = mode & std::ios_base::binary;
135 bool testi = mode & std::ios_base::in;
136 bool testo = mode & std::ios_base::out;
137 bool testt = mode & std::ios_base::trunc;
138 bool testa = mode & std::ios_base::app;
139
140 // Check for valid flag combinations - see [27.8.1.3.2] (Table 92)
141 // Original zfstream hardcoded the compression level to maximum here...
142 // Double the time for less than 1% size improvement seems
143 // excessive though - keeping it at the default level
144 // To change back, just append "9" to the next three mode strings
145 if (!testi && testo && !testt && !testa)
146 strcpy(c_mode, "w");
147 if (!testi && testo && !testt && testa)
148 strcpy(c_mode, "a");
149 if (!testi && testo && testt && !testa)
150 strcpy(c_mode, "w");
151 if (testi && !testo && !testt && !testa)
152 strcpy(c_mode, "r");
153 // No read/write mode yet
154// if (testi && testo && !testt && !testa)
155// strcpy(c_mode, "r+");
156// if (testi && testo && testt && !testa)
157// strcpy(c_mode, "w+");
158
159 // Mode string should be empty for invalid combination of flags
160 if (strlen(c_mode) == 0)
161 return false;
162 if (testb)
163 strcat(c_mode, "b");
164 return true;
165}
166
167// Determine number of characters in internal get buffer
168std::streamsize
169gzfilebuf::showmanyc()
170{
171 // Calls to underflow will fail if file not opened for reading
172 if (!this->is_open() || !(io_mode & std::ios_base::in))
173 return -1;
174 // Make sure get area is in use
175 if (this->gptr() && (this->gptr() < this->egptr()))
176 return std::streamsize(this->egptr() - this->gptr());
177 else
178 return 0;
179}
180
181// Fill get area from gzipped file
182gzfilebuf::int_type
183gzfilebuf::underflow()
184{
185 // If something is left in the get area by chance, return it
186 // (this shouldn't normally happen, as underflow is only supposed
187 // to be called when gptr >= egptr, but it serves as error check)
188 if (this->gptr() && (this->gptr() < this->egptr()))
189 return traits_type::to_int_type(*(this->gptr()));
190
191 // If the file hasn't been opened for reading, produce error
192 if (!this->is_open() || !(io_mode & std::ios_base::in))
193 return traits_type::eof();
194
195 // Attempt to fill internal buffer from gzipped file
196 // (buffer must be guaranteed to exist...)
197 int bytes_read = gzread(file, buffer, buffer_size);
198 // Indicates error or EOF
199 if (bytes_read <= 0)
200 {
201 // Reset get area
202 this->setg(buffer, buffer, buffer);
203 return traits_type::eof();
204 }
205 // Make all bytes read from file available as get area
206 this->setg(buffer, buffer, buffer + bytes_read);
207
208 // Return next character in get area
209 return traits_type::to_int_type(*(this->gptr()));
210}
211
212// Write put area to gzipped file
213gzfilebuf::int_type
214gzfilebuf::overflow(int_type c)
215{
216 // Determine whether put area is in use
217 if (this->pbase())
218 {
219 // Double-check pointer range
220 if (this->pptr() > this->epptr() || this->pptr() < this->pbase())
221 return traits_type::eof();
222 // Add extra character to buffer if not EOF
223 if (!traits_type::eq_int_type(c, traits_type::eof()))
224 {
225 *(this->pptr()) = traits_type::to_char_type(c);
226 this->pbump(1);
227 }
228 // Number of characters to write to file
229 int bytes_to_write = this->pptr() - this->pbase();
230 // Overflow doesn't fail if nothing is to be written
231 if (bytes_to_write > 0)
232 {
233 // If the file hasn't been opened for writing, produce error
234 if (!this->is_open() || !(io_mode & std::ios_base::out))
235 return traits_type::eof();
236 // If gzipped file won't accept all bytes written to it, fail
237 if (gzwrite(file, this->pbase(), bytes_to_write) != bytes_to_write)
238 return traits_type::eof();
239 // Reset next pointer to point to pbase on success
240 this->pbump(-bytes_to_write);
241 }
242 }
243 // Write extra character to file if not EOF
244 else if (!traits_type::eq_int_type(c, traits_type::eof()))
245 {
246 // If the file hasn't been opened for writing, produce error
247 if (!this->is_open() || !(io_mode & std::ios_base::out))
248 return traits_type::eof();
249 // Impromptu char buffer (allows "unbuffered" output)
250 char_type last_char = traits_type::to_char_type(c);
251 // If gzipped file won't accept this character, fail
252 if (gzwrite(file, &last_char, 1) != 1)
253 return traits_type::eof();
254 }
255
256 // If you got here, you have succeeded (even if c was EOF)
257 // The return value should therefore be non-EOF
258 if (traits_type::eq_int_type(c, traits_type::eof()))
259 return traits_type::not_eof(c);
260 else
261 return c;
262}
263
264// Assign new buffer
265std::streambuf*
266gzfilebuf::setbuf(char_type* p,
267 std::streamsize n)
268{
269 // First make sure stuff is sync'ed, for safety
270 if (this->sync() == -1)
271 return NULL;
272 // If buffering is turned off on purpose via setbuf(0,0), still allocate one...
273 // "Unbuffered" only really refers to put [27.8.1.4.10], while get needs at
274 // least a buffer of size 1 (very inefficient though, therefore make it bigger?)
275 // This follows from [27.5.2.4.3]/12 (gptr needs to point at something, it seems)
276 if (!p || !n)
277 {
278 // Replace existing buffer (if any) with small internal buffer
279 this->disable_buffer();
280 buffer = NULL;
281 buffer_size = 0;
282 own_buffer = true;
283 this->enable_buffer();
284 }
285 else
286 {
287 // Replace existing buffer (if any) with external buffer
288 this->disable_buffer();
289 buffer = p;
290 buffer_size = n;
291 own_buffer = false;
292 this->enable_buffer();
293 }
294 return this;
295}
296
297// Write put area to gzipped file (i.e. ensures that put area is empty)
298int
299gzfilebuf::sync()
300{
301 return traits_type::eq_int_type(this->overflow(), traits_type::eof()) ? -1 : 0;
302}
303
304/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
305
306// Allocate internal buffer
307void
308gzfilebuf::enable_buffer()
309{
310 // If internal buffer required, allocate one
311 if (own_buffer && !buffer)
312 {
313 // Check for buffered vs. "unbuffered"
314 if (buffer_size > 0)
315 {
316 // Allocate internal buffer
317 buffer = new char_type[buffer_size];
318 // Get area starts empty and will be expanded by underflow as need arises
319 this->setg(buffer, buffer, buffer);
320 // Setup entire internal buffer as put area.
321 // The one-past-end pointer actually points to the last element of the buffer,
322 // so that overflow(c) can safely add the extra character c to the sequence.
323 // These pointers remain in place for the duration of the buffer
324 this->setp(buffer, buffer + buffer_size - 1);
325 }
326 else
327 {
328 // Even in "unbuffered" case, (small?) get buffer is still required
329 buffer_size = SMALLBUFSIZE;
330 buffer = new char_type[buffer_size];
331 this->setg(buffer, buffer, buffer);
332 // "Unbuffered" means no put buffer
333 this->setp(0, 0);
334 }
335 }
336 else
337 {
338 // If buffer already allocated, reset buffer pointers just to make sure no
339 // stale chars are lying around
340 this->setg(buffer, buffer, buffer);
341 this->setp(buffer, buffer + buffer_size - 1);
342 }
343}
344
345// Destroy internal buffer
346void
347gzfilebuf::disable_buffer()
348{
349 // If internal buffer exists, deallocate it
350 if (own_buffer && buffer)
351 {
352 // Preserve unbuffered status by zeroing size
353 if (!this->pbase())
354 buffer_size = 0;
355 delete[] buffer;
356 buffer = NULL;
357 this->setg(0, 0, 0);
358 this->setp(0, 0);
359 }
360 else
361 {
362 // Reset buffer pointers to initial state if external buffer exists
363 this->setg(buffer, buffer, buffer);
364 if (buffer)
365 this->setp(buffer, buffer + buffer_size - 1);
366 else
367 this->setp(0, 0);
368 }
369}
370
371/*****************************************************************************/
372
373// Default constructor initializes stream buffer
374gzifstream::gzifstream()
375: std::istream(NULL), sb()
376{ this->init(&sb); }
377
378// Initialize stream buffer and open file
379gzifstream::gzifstream(const char* name,
380 std::ios_base::openmode mode)
381: std::istream(NULL), sb()
382{
383 this->init(&sb);
384 this->open(name, mode);
385}
386
387// Initialize stream buffer and attach to file
388gzifstream::gzifstream(int fd,
389 std::ios_base::openmode mode)
390: std::istream(NULL), sb()
391{
392 this->init(&sb);
393 this->attach(fd, mode);
394}
395
396// Open file and go into fail() state if unsuccessful
397void
398gzifstream::open(const char* name,
399 std::ios_base::openmode mode)
400{
401 if (!sb.open(name, mode | std::ios_base::in))
402 this->setstate(std::ios_base::failbit);
403 else
404 this->clear();
405}
406
407// Attach to file and go into fail() state if unsuccessful
408void
409gzifstream::attach(int fd,
410 std::ios_base::openmode mode)
411{
412 if (!sb.attach(fd, mode | std::ios_base::in))
413 this->setstate(std::ios_base::failbit);
414 else
415 this->clear();
416}
417
418// Close file
419void
420gzifstream::close()
421{
422 if (!sb.close())
423 this->setstate(std::ios_base::failbit);
424}
425
426/*****************************************************************************/
427
428// Default constructor initializes stream buffer
429gzofstream::gzofstream()
430: std::ostream(NULL), sb()
431{ this->init(&sb); }
432
433// Initialize stream buffer and open file
434gzofstream::gzofstream(const char* name,
435 std::ios_base::openmode mode)
436: std::ostream(NULL), sb()
437{
438 this->init(&sb);
439 this->open(name, mode);
440}
441
442// Initialize stream buffer and attach to file
443gzofstream::gzofstream(int fd,
444 std::ios_base::openmode mode)
445: std::ostream(NULL), sb()
446{
447 this->init(&sb);
448 this->attach(fd, mode);
449}
450
451// Open file and go into fail() state if unsuccessful
452void
453gzofstream::open(const char* name,
454 std::ios_base::openmode mode)
455{
456 if (!sb.open(name, mode | std::ios_base::out))
457 this->setstate(std::ios_base::failbit);
458 else
459 this->clear();
460}
461
462// Attach to file and go into fail() state if unsuccessful
463void
464gzofstream::attach(int fd,
465 std::ios_base::openmode mode)
466{
467 if (!sb.attach(fd, mode | std::ios_base::out))
468 this->setstate(std::ios_base::failbit);
469 else
470 this->clear();
471}
472
473// Close file
474void
475gzofstream::close()
476{
477 if (!sb.close())
478 this->setstate(std::ios_base::failbit);
479}
diff --git a/contrib/iostream3/zfstream.h b/contrib/iostream3/zfstream.h
new file mode 100644
index 0000000..ad76e8b
--- /dev/null
+++ b/contrib/iostream3/zfstream.h
@@ -0,0 +1,466 @@
1/*
2 * A C++ I/O streams interface to the zlib gz* functions
3 *
4 * by Ludwig Schwardt <schwardt@sun.ac.za>
5 * original version by Kevin Ruland <kevin@rodin.wustl.edu>
6 *
7 * This version is standard-compliant and compatible with gcc 3.x.
8 */
9
10#ifndef ZFSTREAM_H
11#define ZFSTREAM_H
12
13#include <istream> // not iostream, since we don't need cin/cout
14#include <ostream>
15#include "zlib.h"
16
17/*****************************************************************************/
18
19/**
20 * @brief Gzipped file stream buffer class.
21 *
22 * This class implements basic_filebuf for gzipped files. It doesn't yet support
23 * seeking (allowed by zlib but slow/limited), putback and read/write access
24 * (tricky). Otherwise, it attempts to be a drop-in replacement for the standard
25 * file streambuf.
26*/
27class gzfilebuf : public std::streambuf
28{
29public:
30 // Default constructor.
31 gzfilebuf();
32
33 // Destructor.
34 virtual
35 ~gzfilebuf();
36
37 /**
38 * @brief Set compression level and strategy on the fly.
39 * @param comp_level Compression level (see zlib.h for allowed values)
40 * @param comp_strategy Compression strategy (see zlib.h for allowed values)
41 * @return Z_OK on success, Z_STREAM_ERROR otherwise.
42 *
43 * Unfortunately, these parameters cannot be modified separately, as the
44 * previous zfstream version assumed. Since the strategy is seldom changed,
45 * it can default and setcompression(level) then becomes like the old
46 * setcompressionlevel(level).
47 */
48 int
49 setcompression(int comp_level,
50 int comp_strategy = Z_DEFAULT_STRATEGY);
51
52 /**
53 * @brief Check if file is open.
54 * @return True if file is open.
55 */
56 bool
57 is_open() const { return (file != NULL); }
58
59 /**
60 * @brief Open gzipped file.
61 * @param name File name.
62 * @param mode Open mode flags.
63 * @return @c this on success, NULL on failure.
64 */
65 gzfilebuf*
66 open(const char* name,
67 std::ios_base::openmode mode);
68
69 /**
70 * @brief Attach to already open gzipped file.
71 * @param fd File descriptor.
72 * @param mode Open mode flags.
73 * @return @c this on success, NULL on failure.
74 */
75 gzfilebuf*
76 attach(int fd,
77 std::ios_base::openmode mode);
78
79 /**
80 * @brief Close gzipped file.
81 * @return @c this on success, NULL on failure.
82 */
83 gzfilebuf*
84 close();
85
86protected:
87 /**
88 * @brief Convert ios open mode int to mode string used by zlib.
89 * @return True if valid mode flag combination.
90 */
91 bool
92 open_mode(std::ios_base::openmode mode,
93 char* c_mode) const;
94
95 /**
96 * @brief Number of characters available in stream buffer.
97 * @return Number of characters.
98 *
99 * This indicates number of characters in get area of stream buffer.
100 * These characters can be read without accessing the gzipped file.
101 */
102 virtual std::streamsize
103 showmanyc();
104
105 /**
106 * @brief Fill get area from gzipped file.
107 * @return First character in get area on success, EOF on error.
108 *
109 * This actually reads characters from gzipped file to stream
110 * buffer. Always buffered.
111 */
112 virtual int_type
113 underflow();
114
115 /**
116 * @brief Write put area to gzipped file.
117 * @param c Extra character to add to buffer contents.
118 * @return Non-EOF on success, EOF on error.
119 *
120 * This actually writes characters in stream buffer to
121 * gzipped file. With unbuffered output this is done one
122 * character at a time.
123 */
124 virtual int_type
125 overflow(int_type c = traits_type::eof());
126
127 /**
128 * @brief Installs external stream buffer.
129 * @param p Pointer to char buffer.
130 * @param n Size of external buffer.
131 * @return @c this on success, NULL on failure.
132 *
133 * Call setbuf(0,0) to enable unbuffered output.
134 */
135 virtual std::streambuf*
136 setbuf(char_type* p,
137 std::streamsize n);
138
139 /**
140 * @brief Flush stream buffer to file.
141 * @return 0 on success, -1 on error.
142 *
143 * This calls underflow(EOF) to do the job.
144 */
145 virtual int
146 sync();
147
148//
149// Some future enhancements
150//
151// virtual int_type uflow();
152// virtual int_type pbackfail(int_type c = traits_type::eof());
153// virtual pos_type
154// seekoff(off_type off,
155// std::ios_base::seekdir way,
156// std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out);
157// virtual pos_type
158// seekpos(pos_type sp,
159// std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out);
160
161private:
162 /**
163 * @brief Allocate internal buffer.
164 *
165 * This function is safe to call multiple times. It will ensure
166 * that a proper internal buffer exists if it is required. If the
167 * buffer already exists or is external, the buffer pointers will be
168 * reset to their original state.
169 */
170 void
171 enable_buffer();
172
173 /**
174 * @brief Destroy internal buffer.
175 *
176 * This function is safe to call multiple times. It will ensure
177 * that the internal buffer is deallocated if it exists. In any
178 * case, it will also reset the buffer pointers.
179 */
180 void
181 disable_buffer();
182
183 /**
184 * Underlying file pointer.
185 */
186 gzFile file;
187
188 /**
189 * Mode in which file was opened.
190 */
191 std::ios_base::openmode io_mode;
192
193 /**
194 * @brief True if this object owns file descriptor.
195 *
196 * This makes the class responsible for closing the file
197 * upon destruction.
198 */
199 bool own_fd;
200
201 /**
202 * @brief Stream buffer.
203 *
204 * For simplicity this remains allocated on the free store for the
205 * entire life span of the gzfilebuf object, unless replaced by setbuf.
206 */
207 char_type* buffer;
208
209 /**
210 * @brief Stream buffer size.
211 *
212 * Defaults to system default buffer size (typically 8192 bytes).
213 * Modified by setbuf.
214 */
215 std::streamsize buffer_size;
216
217 /**
218 * @brief True if this object owns stream buffer.
219 *
220 * This makes the class responsible for deleting the buffer
221 * upon destruction.
222 */
223 bool own_buffer;
224};
225
226/*****************************************************************************/
227
228/**
229 * @brief Gzipped file input stream class.
230 *
231 * This class implements ifstream for gzipped files. Seeking and putback
232 * is not supported yet.
233*/
234class gzifstream : public std::istream
235{
236public:
237 // Default constructor
238 gzifstream();
239
240 /**
241 * @brief Construct stream on gzipped file to be opened.
242 * @param name File name.
243 * @param mode Open mode flags (forced to contain ios::in).
244 */
245 explicit
246 gzifstream(const char* name,
247 std::ios_base::openmode mode = std::ios_base::in);
248
249 /**
250 * @brief Construct stream on already open gzipped file.
251 * @param fd File descriptor.
252 * @param mode Open mode flags (forced to contain ios::in).
253 */
254 explicit
255 gzifstream(int fd,
256 std::ios_base::openmode mode = std::ios_base::in);
257
258 /**
259 * Obtain underlying stream buffer.
260 */
261 gzfilebuf*
262 rdbuf() const
263 { return const_cast<gzfilebuf*>(&sb); }
264
265 /**
266 * @brief Check if file is open.
267 * @return True if file is open.
268 */
269 bool
270 is_open() { return sb.is_open(); }
271
272 /**
273 * @brief Open gzipped file.
274 * @param name File name.
275 * @param mode Open mode flags (forced to contain ios::in).
276 *
277 * Stream will be in state good() if file opens successfully;
278 * otherwise in state fail(). This differs from the behavior of
279 * ifstream, which never sets the state to good() and therefore
280 * won't allow you to reuse the stream for a second file unless
281 * you manually clear() the state. The choice is a matter of
282 * convenience.
283 */
284 void
285 open(const char* name,
286 std::ios_base::openmode mode = std::ios_base::in);
287
288 /**
289 * @brief Attach to already open gzipped file.
290 * @param fd File descriptor.
291 * @param mode Open mode flags (forced to contain ios::in).
292 *
293 * Stream will be in state good() if attach succeeded; otherwise
294 * in state fail().
295 */
296 void
297 attach(int fd,
298 std::ios_base::openmode mode = std::ios_base::in);
299
300 /**
301 * @brief Close gzipped file.
302 *
303 * Stream will be in state fail() if close failed.
304 */
305 void
306 close();
307
308private:
309 /**
310 * Underlying stream buffer.
311 */
312 gzfilebuf sb;
313};
314
315/*****************************************************************************/
316
317/**
318 * @brief Gzipped file output stream class.
319 *
320 * This class implements ofstream for gzipped files. Seeking and putback
321 * is not supported yet.
322*/
323class gzofstream : public std::ostream
324{
325public:
326 // Default constructor
327 gzofstream();
328
329 /**
330 * @brief Construct stream on gzipped file to be opened.
331 * @param name File name.
332 * @param mode Open mode flags (forced to contain ios::out).
333 */
334 explicit
335 gzofstream(const char* name,
336 std::ios_base::openmode mode = std::ios_base::out);
337
338 /**
339 * @brief Construct stream on already open gzipped file.
340 * @param fd File descriptor.
341 * @param mode Open mode flags (forced to contain ios::out).
342 */
343 explicit
344 gzofstream(int fd,
345 std::ios_base::openmode mode = std::ios_base::out);
346
347 /**
348 * Obtain underlying stream buffer.
349 */
350 gzfilebuf*
351 rdbuf() const
352 { return const_cast<gzfilebuf*>(&sb); }
353
354 /**
355 * @brief Check if file is open.
356 * @return True if file is open.
357 */
358 bool
359 is_open() { return sb.is_open(); }
360
361 /**
362 * @brief Open gzipped file.
363 * @param name File name.
364 * @param mode Open mode flags (forced to contain ios::out).
365 *
366 * Stream will be in state good() if file opens successfully;
367 * otherwise in state fail(). This differs from the behavior of
368 * ofstream, which never sets the state to good() and therefore
369 * won't allow you to reuse the stream for a second file unless
370 * you manually clear() the state. The choice is a matter of
371 * convenience.
372 */
373 void
374 open(const char* name,
375 std::ios_base::openmode mode = std::ios_base::out);
376
377 /**
378 * @brief Attach to already open gzipped file.
379 * @param fd File descriptor.
380 * @param mode Open mode flags (forced to contain ios::out).
381 *
382 * Stream will be in state good() if attach succeeded; otherwise
383 * in state fail().
384 */
385 void
386 attach(int fd,
387 std::ios_base::openmode mode = std::ios_base::out);
388
389 /**
390 * @brief Close gzipped file.
391 *
392 * Stream will be in state fail() if close failed.
393 */
394 void
395 close();
396
397private:
398 /**
399 * Underlying stream buffer.
400 */
401 gzfilebuf sb;
402};
403
404/*****************************************************************************/
405
406/**
407 * @brief Gzipped file output stream manipulator class.
408 *
409 * This class defines a two-argument manipulator for gzofstream. It is used
410 * as base for the setcompression(int,int) manipulator.
411*/
412template<typename T1, typename T2>
413 class gzomanip2
414 {
415 public:
416 // Allows insertor to peek at internals
417 template <typename Ta, typename Tb>
418 friend gzofstream&
419 operator<<(gzofstream&,
420 const gzomanip2<Ta,Tb>&);
421
422 // Constructor
423 gzomanip2(gzofstream& (*f)(gzofstream&, T1, T2),
424 T1 v1,
425 T2 v2);
426 private:
427 // Underlying manipulator function
428 gzofstream&
429 (*func)(gzofstream&, T1, T2);
430
431 // Arguments for manipulator function
432 T1 val1;
433 T2 val2;
434 };
435
436/*****************************************************************************/
437
438// Manipulator function thunks through to stream buffer
439inline gzofstream&
440setcompression(gzofstream &gzs, int l, int s = Z_DEFAULT_STRATEGY)
441{
442 (gzs.rdbuf())->setcompression(l, s);
443 return gzs;
444}
445
446// Manipulator constructor stores arguments
447template<typename T1, typename T2>
448 inline
449 gzomanip2<T1,T2>::gzomanip2(gzofstream &(*f)(gzofstream &, T1, T2),
450 T1 v1,
451 T2 v2)
452 : func(f), val1(v1), val2(v2)
453 { }
454
455// Insertor applies underlying manipulator function to stream
456template<typename T1, typename T2>
457 inline gzofstream&
458 operator<<(gzofstream& s, const gzomanip2<T1,T2>& m)
459 { return (*m.func)(s, m.val1, m.val2); }
460
461// Insert this onto stream to simplify setting of compression level
462inline gzomanip2<int,int>
463setcompression(int l, int s = Z_DEFAULT_STRATEGY)
464{ return gzomanip2<int,int>(&setcompression, l, s); }
465
466#endif // ZFSTREAM_H