Rizin
unix-like reverse engineering framework and cli tools
zfstream.cc
Go to the documentation of this file.
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
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
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
42 int
44  int comp_strategy)
45 {
46  return gzsetparams(file, comp_level, comp_strategy);
47 }
48 
49 // Open gzipped file
50 gzfilebuf*
51 gzfilebuf::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
78 gzfilebuf*
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
106 gzfilebuf*
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
130 bool
131 gzfilebuf::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
168 std::streamsize
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
182 gzfilebuf::int_type
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
213 gzfilebuf::int_type
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
265 std::streambuf*
266 gzfilebuf::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)
298 int
300 {
301  return traits_type::eq_int_type(this->overflow(), traits_type::eof()) ? -1 : 0;
302 }
303 
304 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
305 
306 // Allocate internal buffer
307 void
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
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
346 void
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
375 : std::istream(NULL), sb()
376 { this->init(&sb); }
377 
378 // Initialize stream buffer and open file
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
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
397 void
398 gzifstream::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
408 void
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
419 void
421 {
422  if (!sb.close())
423  this->setstate(std::ios_base::failbit);
424 }
425 
426 /*****************************************************************************/
427 
428 // Default constructor initializes stream buffer
430 : std::ostream(NULL), sb()
431 { this->init(&sb); }
432 
433 // Initialize stream buffer and open file
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
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
452 void
453 gzofstream::open(const char* name,
454  std::ios_base::openmode mode)
455 {
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
463 void
465  std::ios_base::openmode mode)
466 {
468  this->setstate(std::ios_base::failbit);
469  else
470  this->clear();
471 }
472 
473 // Close file
474 void
476 {
477  if (!sb.close())
478  this->setstate(std::ios_base::failbit);
479 }
static SblHeader sb
Definition: bin_mbn.c:26
const lzma_allocator const uint8_t * in
Definition: block.h:527
const lzma_allocator const uint8_t size_t uint8_t * out
Definition: block.h:528
Gzipped file stream buffer class.
Definition: zfstream.h:8
std::streamsize buffer_size
Stream buffer size.
Definition: zfstream.h:215
gzfilebuf * close()
Definition: zfstream.cpp:102
virtual int underflow()
Definition: zfstream.cpp:135
std::ios_base::openmode io_mode
Definition: zfstream.h:191
bool own_fd
True if this object owns file descriptor.
Definition: zfstream.h:199
gzfilebuf * attach(int file_descriptor, int io_mode)
Definition: zfstream.cpp:60
short mode
Definition: zfstream.h:36
virtual ~gzfilebuf()
Definition: zfstream.cpp:10
virtual int overflow(int=EOF)
Definition: zfstream.cpp:173
virtual std::streambuf * setbuf(char_type *p, std::streamsize n)
Installs external stream buffer.
Definition: zfstream.cc:266
void disable_buffer()
Destroy internal buffer.
Definition: zfstream.cc:347
char_type * buffer
Stream buffer.
Definition: zfstream.h:207
gzfilebuf()
Definition: zfstream.cpp:4
bool open_mode(std::ios_base::openmode mode, char *c_mode) const
Convert ios open mode int to mode string used by zlib.
Definition: zfstream.cc:131
bool own_buffer
True if this object owns stream buffer.
Definition: zfstream.h:223
int setcompression(int comp_level, int comp_strategy=Z_DEFAULT_STRATEGY)
Set compression level and strategy on the fly.
Definition: zfstream.cc:43
void enable_buffer()
Allocate internal buffer.
Definition: zfstream.cc:308
gzfilebuf * open(const char *name, int io_mode)
Definition: zfstream.cpp:18
virtual int sync()
Definition: zfstream.cpp:206
int is_open() const
Definition: zfstream.h:22
virtual std::streamsize showmanyc()
Number of characters available in stream buffer.
Definition: zfstream.cc:169
void close()
Close gzipped file.
Definition: zfstream.cc:420
void attach(int fd, std::ios_base::openmode mode=std::ios_base::in)
Attach to already open gzipped file.
Definition: zfstream.cc:409
gzfilebuf sb
Definition: zfstream.h:312
void open(const char *name, std::ios_base::openmode mode=std::ios_base::in)
Open gzipped file.
Definition: zfstream.cc:398
gzfilebuf sb
Definition: zfstream.h:401
void close()
Close gzipped file.
Definition: zfstream.cc:475
void attach(int fd, std::ios_base::openmode mode=std::ios_base::out)
Attach to already open gzipped file.
Definition: zfstream.cc:464
void open(const char *name, std::ios_base::openmode mode=std::ios_base::out)
Open gzipped file.
Definition: zfstream.cc:453
#define NULL
Definition: cris-opc.c:27
#define true
#define false
int ZEXPORT gzclose(gzFile file)
Definition: gzclose.c:11
gzFile ZEXPORT gzopen(char *path, const char *mode) const
Definition: gzlib.c:272
gzFile ZEXPORT gzdopen(int fd, const char *mode)
Definition: gzlib.c:288
int ZEXPORT gzread(gzFile file, voidp buf, unsigned len)
Definition: gzread.c:375
int ZEXPORT gzsetparams(gzFile file, int level, int strategy)
Definition: gzwrite.c:597
int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len)
Definition: gzwrite.c:255
const char int mode
Definition: ioapi.h:137
void * p
Definition: libc.cpp:67
int n
Definition: mipsasm.c:19
#define c(i)
Definition: sha256.c:43
Definition: buffer.h:15
Definition: gzappend.c:170
Definition: z80asm.h:102
static char * binary(unsigned int val, unsigned int bits)
Definition: debug.c:3
bool init
Definition: core.c:77
static const z80_opcode fd[]
Definition: z80_tab.h:997
#define SMALLBUFSIZE
Definition: zfstream.cc:16
#define BIGBUFSIZE
Definition: zfstream.cc:15
#define buffer_size(buffer)