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