111293Sandreas.hansson@arm.com/*
211293Sandreas.hansson@arm.com * A C++ I/O streams interface to the zlib gz* functions
311293Sandreas.hansson@arm.com *
411293Sandreas.hansson@arm.com * by Ludwig Schwardt <schwardt@sun.ac.za>
511293Sandreas.hansson@arm.com * original version by Kevin Ruland <kevin@rodin.wustl.edu>
611293Sandreas.hansson@arm.com *
711293Sandreas.hansson@arm.com * This version is standard-compliant and compatible with gcc 3.x.
811293Sandreas.hansson@arm.com */
911293Sandreas.hansson@arm.com
1011293Sandreas.hansson@arm.com#include "zfstream.h"
1111293Sandreas.hansson@arm.com#include <cstring>          // for strcpy, strcat, strlen (mode strings)
1211293Sandreas.hansson@arm.com#include <cstdio>           // for BUFSIZ
1311293Sandreas.hansson@arm.com
1411293Sandreas.hansson@arm.com// Internal buffer sizes (default and "unbuffered" versions)
1511293Sandreas.hansson@arm.com#define BIGBUFSIZE BUFSIZ
1611293Sandreas.hansson@arm.com#define SMALLBUFSIZE 1
1711293Sandreas.hansson@arm.com
1811293Sandreas.hansson@arm.com/*****************************************************************************/
1911293Sandreas.hansson@arm.com
2011293Sandreas.hansson@arm.com// Default constructor
2111293Sandreas.hansson@arm.comgzfilebuf::gzfilebuf()
2211293Sandreas.hansson@arm.com: file(NULL), io_mode(std::ios_base::openmode(0)), own_fd(false),
2311293Sandreas.hansson@arm.com  buffer(NULL), buffer_size(BIGBUFSIZE), own_buffer(true)
2411293Sandreas.hansson@arm.com{
2511293Sandreas.hansson@arm.com  // No buffers to start with
2611293Sandreas.hansson@arm.com  this->disable_buffer();
2711293Sandreas.hansson@arm.com}
2811293Sandreas.hansson@arm.com
2911293Sandreas.hansson@arm.com// Destructor
3011293Sandreas.hansson@arm.comgzfilebuf::~gzfilebuf()
3111293Sandreas.hansson@arm.com{
3211293Sandreas.hansson@arm.com  // Sync output buffer and close only if responsible for file
3311293Sandreas.hansson@arm.com  // (i.e. attached streams should be left open at this stage)
3411293Sandreas.hansson@arm.com  this->sync();
3511293Sandreas.hansson@arm.com  if (own_fd)
3611293Sandreas.hansson@arm.com    this->close();
3711293Sandreas.hansson@arm.com  // Make sure internal buffer is deallocated
3811293Sandreas.hansson@arm.com  this->disable_buffer();
3911293Sandreas.hansson@arm.com}
4011293Sandreas.hansson@arm.com
4111293Sandreas.hansson@arm.com// Set compression level and strategy
4211293Sandreas.hansson@arm.comint
4311293Sandreas.hansson@arm.comgzfilebuf::setcompression(int comp_level,
4411293Sandreas.hansson@arm.com                          int comp_strategy)
4511293Sandreas.hansson@arm.com{
4611293Sandreas.hansson@arm.com  return gzsetparams(file, comp_level, comp_strategy);
4711293Sandreas.hansson@arm.com}
4811293Sandreas.hansson@arm.com
4911293Sandreas.hansson@arm.com// Open gzipped file
5011293Sandreas.hansson@arm.comgzfilebuf*
5111293Sandreas.hansson@arm.comgzfilebuf::open(const char *name,
5211293Sandreas.hansson@arm.com                std::ios_base::openmode mode)
5311293Sandreas.hansson@arm.com{
5411293Sandreas.hansson@arm.com  // Fail if file already open
5511293Sandreas.hansson@arm.com  if (this->is_open())
5611293Sandreas.hansson@arm.com    return NULL;
5711293Sandreas.hansson@arm.com  // Don't support simultaneous read/write access (yet)
5811293Sandreas.hansson@arm.com  if ((mode & std::ios_base::in) && (mode & std::ios_base::out))
5911293Sandreas.hansson@arm.com    return NULL;
6011293Sandreas.hansson@arm.com
6111293Sandreas.hansson@arm.com  // Build mode string for gzopen and check it [27.8.1.3.2]
6211293Sandreas.hansson@arm.com  char char_mode[6] = "\0\0\0\0\0";
6311293Sandreas.hansson@arm.com  if (!this->open_mode(mode, char_mode))
6411293Sandreas.hansson@arm.com    return NULL;
6511293Sandreas.hansson@arm.com
6611293Sandreas.hansson@arm.com  // Attempt to open file
6711293Sandreas.hansson@arm.com  if ((file = gzopen(name, char_mode)) == NULL)
6811293Sandreas.hansson@arm.com    return NULL;
6911293Sandreas.hansson@arm.com
7011293Sandreas.hansson@arm.com  // On success, allocate internal buffer and set flags
7111293Sandreas.hansson@arm.com  this->enable_buffer();
7211293Sandreas.hansson@arm.com  io_mode = mode;
7311293Sandreas.hansson@arm.com  own_fd = true;
7411293Sandreas.hansson@arm.com  return this;
7511293Sandreas.hansson@arm.com}
7611293Sandreas.hansson@arm.com
7711293Sandreas.hansson@arm.com// Attach to gzipped file
7811293Sandreas.hansson@arm.comgzfilebuf*
7911293Sandreas.hansson@arm.comgzfilebuf::attach(int fd,
8011293Sandreas.hansson@arm.com                  std::ios_base::openmode mode)
8111293Sandreas.hansson@arm.com{
8211293Sandreas.hansson@arm.com  // Fail if file already open
8311293Sandreas.hansson@arm.com  if (this->is_open())
8411293Sandreas.hansson@arm.com    return NULL;
8511293Sandreas.hansson@arm.com  // Don't support simultaneous read/write access (yet)
8611293Sandreas.hansson@arm.com  if ((mode & std::ios_base::in) && (mode & std::ios_base::out))
8711293Sandreas.hansson@arm.com    return NULL;
8811293Sandreas.hansson@arm.com
8911293Sandreas.hansson@arm.com  // Build mode string for gzdopen and check it [27.8.1.3.2]
9011293Sandreas.hansson@arm.com  char char_mode[6] = "\0\0\0\0\0";
9111293Sandreas.hansson@arm.com  if (!this->open_mode(mode, char_mode))
9211293Sandreas.hansson@arm.com    return NULL;
9311293Sandreas.hansson@arm.com
9411293Sandreas.hansson@arm.com  // Attempt to attach to file
9511293Sandreas.hansson@arm.com  if ((file = gzdopen(fd, char_mode)) == NULL)
9611293Sandreas.hansson@arm.com    return NULL;
9711293Sandreas.hansson@arm.com
9811293Sandreas.hansson@arm.com  // On success, allocate internal buffer and set flags
9911293Sandreas.hansson@arm.com  this->enable_buffer();
10011293Sandreas.hansson@arm.com  io_mode = mode;
10111293Sandreas.hansson@arm.com  own_fd = false;
10211293Sandreas.hansson@arm.com  return this;
10311293Sandreas.hansson@arm.com}
10411293Sandreas.hansson@arm.com
10511293Sandreas.hansson@arm.com// Close gzipped file
10611293Sandreas.hansson@arm.comgzfilebuf*
10711293Sandreas.hansson@arm.comgzfilebuf::close()
10811293Sandreas.hansson@arm.com{
10911293Sandreas.hansson@arm.com  // Fail immediately if no file is open
11011293Sandreas.hansson@arm.com  if (!this->is_open())
11111293Sandreas.hansson@arm.com    return NULL;
11211293Sandreas.hansson@arm.com  // Assume success
11311293Sandreas.hansson@arm.com  gzfilebuf* retval = this;
11411293Sandreas.hansson@arm.com  // Attempt to sync and close gzipped file
11511293Sandreas.hansson@arm.com  if (this->sync() == -1)
11611293Sandreas.hansson@arm.com    retval = NULL;
11711293Sandreas.hansson@arm.com  if (gzclose(file) < 0)
11811293Sandreas.hansson@arm.com    retval = NULL;
11911293Sandreas.hansson@arm.com  // File is now gone anyway (postcondition [27.8.1.3.8])
12011293Sandreas.hansson@arm.com  file = NULL;
12111293Sandreas.hansson@arm.com  own_fd = false;
12211293Sandreas.hansson@arm.com  // Destroy internal buffer if it exists
12311293Sandreas.hansson@arm.com  this->disable_buffer();
12411293Sandreas.hansson@arm.com  return retval;
12511293Sandreas.hansson@arm.com}
12611293Sandreas.hansson@arm.com
12711293Sandreas.hansson@arm.com/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12811293Sandreas.hansson@arm.com
12911293Sandreas.hansson@arm.com// Convert int open mode to mode string
13011293Sandreas.hansson@arm.combool
13111293Sandreas.hansson@arm.comgzfilebuf::open_mode(std::ios_base::openmode mode,
13211293Sandreas.hansson@arm.com                     char* c_mode) const
13311293Sandreas.hansson@arm.com{
13411293Sandreas.hansson@arm.com  bool testb = mode & std::ios_base::binary;
13511293Sandreas.hansson@arm.com  bool testi = mode & std::ios_base::in;
13611293Sandreas.hansson@arm.com  bool testo = mode & std::ios_base::out;
13711293Sandreas.hansson@arm.com  bool testt = mode & std::ios_base::trunc;
13811293Sandreas.hansson@arm.com  bool testa = mode & std::ios_base::app;
13911293Sandreas.hansson@arm.com
14011293Sandreas.hansson@arm.com  // Check for valid flag combinations - see [27.8.1.3.2] (Table 92)
14111293Sandreas.hansson@arm.com  // Original zfstream hardcoded the compression level to maximum here...
14211293Sandreas.hansson@arm.com  // Double the time for less than 1% size improvement seems
14311293Sandreas.hansson@arm.com  // excessive though - keeping it at the default level
14411293Sandreas.hansson@arm.com  // To change back, just append "9" to the next three mode strings
14511293Sandreas.hansson@arm.com  if (!testi && testo && !testt && !testa)
14611293Sandreas.hansson@arm.com    strcpy(c_mode, "w");
14711293Sandreas.hansson@arm.com  if (!testi && testo && !testt && testa)
14811293Sandreas.hansson@arm.com    strcpy(c_mode, "a");
14911293Sandreas.hansson@arm.com  if (!testi && testo && testt && !testa)
15011293Sandreas.hansson@arm.com    strcpy(c_mode, "w");
15111293Sandreas.hansson@arm.com  if (testi && !testo && !testt && !testa)
15211293Sandreas.hansson@arm.com    strcpy(c_mode, "r");
15311293Sandreas.hansson@arm.com  // No read/write mode yet
15411293Sandreas.hansson@arm.com//  if (testi && testo && !testt && !testa)
15511293Sandreas.hansson@arm.com//    strcpy(c_mode, "r+");
15611293Sandreas.hansson@arm.com//  if (testi && testo && testt && !testa)
15711293Sandreas.hansson@arm.com//    strcpy(c_mode, "w+");
15811293Sandreas.hansson@arm.com
15911293Sandreas.hansson@arm.com  // Mode string should be empty for invalid combination of flags
16011293Sandreas.hansson@arm.com  if (strlen(c_mode) == 0)
16111293Sandreas.hansson@arm.com    return false;
16211293Sandreas.hansson@arm.com  if (testb)
16311293Sandreas.hansson@arm.com    strcat(c_mode, "b");
16411293Sandreas.hansson@arm.com  return true;
16511293Sandreas.hansson@arm.com}
16611293Sandreas.hansson@arm.com
16711293Sandreas.hansson@arm.com// Determine number of characters in internal get buffer
16811293Sandreas.hansson@arm.comstd::streamsize
16911293Sandreas.hansson@arm.comgzfilebuf::showmanyc()
17011293Sandreas.hansson@arm.com{
17111293Sandreas.hansson@arm.com  // Calls to underflow will fail if file not opened for reading
17211293Sandreas.hansson@arm.com  if (!this->is_open() || !(io_mode & std::ios_base::in))
17311293Sandreas.hansson@arm.com    return -1;
17411293Sandreas.hansson@arm.com  // Make sure get area is in use
17511293Sandreas.hansson@arm.com  if (this->gptr() && (this->gptr() < this->egptr()))
17611293Sandreas.hansson@arm.com    return std::streamsize(this->egptr() - this->gptr());
17711293Sandreas.hansson@arm.com  else
17811293Sandreas.hansson@arm.com    return 0;
17911293Sandreas.hansson@arm.com}
18011293Sandreas.hansson@arm.com
18111293Sandreas.hansson@arm.com// Fill get area from gzipped file
18211293Sandreas.hansson@arm.comgzfilebuf::int_type
18311293Sandreas.hansson@arm.comgzfilebuf::underflow()
18411293Sandreas.hansson@arm.com{
18511293Sandreas.hansson@arm.com  // If something is left in the get area by chance, return it
18611293Sandreas.hansson@arm.com  // (this shouldn't normally happen, as underflow is only supposed
18711293Sandreas.hansson@arm.com  // to be called when gptr >= egptr, but it serves as error check)
18811293Sandreas.hansson@arm.com  if (this->gptr() && (this->gptr() < this->egptr()))
18911293Sandreas.hansson@arm.com    return traits_type::to_int_type(*(this->gptr()));
19011293Sandreas.hansson@arm.com
19111293Sandreas.hansson@arm.com  // If the file hasn't been opened for reading, produce error
19211293Sandreas.hansson@arm.com  if (!this->is_open() || !(io_mode & std::ios_base::in))
19311293Sandreas.hansson@arm.com    return traits_type::eof();
19411293Sandreas.hansson@arm.com
19511293Sandreas.hansson@arm.com  // Attempt to fill internal buffer from gzipped file
19611293Sandreas.hansson@arm.com  // (buffer must be guaranteed to exist...)
19711293Sandreas.hansson@arm.com  int bytes_read = gzread(file, buffer, buffer_size);
19811293Sandreas.hansson@arm.com  // Indicates error or EOF
19911293Sandreas.hansson@arm.com  if (bytes_read <= 0)
20011293Sandreas.hansson@arm.com  {
20111293Sandreas.hansson@arm.com    // Reset get area
20211293Sandreas.hansson@arm.com    this->setg(buffer, buffer, buffer);
20311293Sandreas.hansson@arm.com    return traits_type::eof();
20411293Sandreas.hansson@arm.com  }
20511293Sandreas.hansson@arm.com  // Make all bytes read from file available as get area
20611293Sandreas.hansson@arm.com  this->setg(buffer, buffer, buffer + bytes_read);
20711293Sandreas.hansson@arm.com
20811293Sandreas.hansson@arm.com  // Return next character in get area
20911293Sandreas.hansson@arm.com  return traits_type::to_int_type(*(this->gptr()));
21011293Sandreas.hansson@arm.com}
21111293Sandreas.hansson@arm.com
21211293Sandreas.hansson@arm.com// Write put area to gzipped file
21311293Sandreas.hansson@arm.comgzfilebuf::int_type
21411293Sandreas.hansson@arm.comgzfilebuf::overflow(int_type c)
21511293Sandreas.hansson@arm.com{
21611293Sandreas.hansson@arm.com  // Determine whether put area is in use
21711293Sandreas.hansson@arm.com  if (this->pbase())
21811293Sandreas.hansson@arm.com  {
21911293Sandreas.hansson@arm.com    // Double-check pointer range
22011293Sandreas.hansson@arm.com    if (this->pptr() > this->epptr() || this->pptr() < this->pbase())
22111293Sandreas.hansson@arm.com      return traits_type::eof();
22211293Sandreas.hansson@arm.com    // Add extra character to buffer if not EOF
22311293Sandreas.hansson@arm.com    if (!traits_type::eq_int_type(c, traits_type::eof()))
22411293Sandreas.hansson@arm.com    {
22511293Sandreas.hansson@arm.com      *(this->pptr()) = traits_type::to_char_type(c);
22611293Sandreas.hansson@arm.com      this->pbump(1);
22711293Sandreas.hansson@arm.com    }
22811293Sandreas.hansson@arm.com    // Number of characters to write to file
22911293Sandreas.hansson@arm.com    int bytes_to_write = this->pptr() - this->pbase();
23011293Sandreas.hansson@arm.com    // Overflow doesn't fail if nothing is to be written
23111293Sandreas.hansson@arm.com    if (bytes_to_write > 0)
23211293Sandreas.hansson@arm.com    {
23311293Sandreas.hansson@arm.com      // If the file hasn't been opened for writing, produce error
23411293Sandreas.hansson@arm.com      if (!this->is_open() || !(io_mode & std::ios_base::out))
23511293Sandreas.hansson@arm.com        return traits_type::eof();
23611293Sandreas.hansson@arm.com      // If gzipped file won't accept all bytes written to it, fail
23711293Sandreas.hansson@arm.com      if (gzwrite(file, this->pbase(), bytes_to_write) != bytes_to_write)
23811293Sandreas.hansson@arm.com        return traits_type::eof();
23911293Sandreas.hansson@arm.com      // Reset next pointer to point to pbase on success
24011293Sandreas.hansson@arm.com      this->pbump(-bytes_to_write);
24111293Sandreas.hansson@arm.com    }
24211293Sandreas.hansson@arm.com  }
24311293Sandreas.hansson@arm.com  // Write extra character to file if not EOF
24411293Sandreas.hansson@arm.com  else if (!traits_type::eq_int_type(c, traits_type::eof()))
24511293Sandreas.hansson@arm.com  {
24611293Sandreas.hansson@arm.com    // If the file hasn't been opened for writing, produce error
24711293Sandreas.hansson@arm.com    if (!this->is_open() || !(io_mode & std::ios_base::out))
24811293Sandreas.hansson@arm.com      return traits_type::eof();
24911293Sandreas.hansson@arm.com    // Impromptu char buffer (allows "unbuffered" output)
25011293Sandreas.hansson@arm.com    char_type last_char = traits_type::to_char_type(c);
25111293Sandreas.hansson@arm.com    // If gzipped file won't accept this character, fail
25211293Sandreas.hansson@arm.com    if (gzwrite(file, &last_char, 1) != 1)
25311293Sandreas.hansson@arm.com      return traits_type::eof();
25411293Sandreas.hansson@arm.com  }
25511293Sandreas.hansson@arm.com
25611293Sandreas.hansson@arm.com  // If you got here, you have succeeded (even if c was EOF)
25711293Sandreas.hansson@arm.com  // The return value should therefore be non-EOF
25811293Sandreas.hansson@arm.com  if (traits_type::eq_int_type(c, traits_type::eof()))
25911293Sandreas.hansson@arm.com    return traits_type::not_eof(c);
26011293Sandreas.hansson@arm.com  else
26111293Sandreas.hansson@arm.com    return c;
26211293Sandreas.hansson@arm.com}
26311293Sandreas.hansson@arm.com
26411293Sandreas.hansson@arm.com// Assign new buffer
26511293Sandreas.hansson@arm.comstd::streambuf*
26611293Sandreas.hansson@arm.comgzfilebuf::setbuf(char_type* p,
26711293Sandreas.hansson@arm.com                  std::streamsize n)
26811293Sandreas.hansson@arm.com{
26911293Sandreas.hansson@arm.com  // First make sure stuff is sync'ed, for safety
27011293Sandreas.hansson@arm.com  if (this->sync() == -1)
27111293Sandreas.hansson@arm.com    return NULL;
27211293Sandreas.hansson@arm.com  // If buffering is turned off on purpose via setbuf(0,0), still allocate one...
27311293Sandreas.hansson@arm.com  // "Unbuffered" only really refers to put [27.8.1.4.10], while get needs at
27411293Sandreas.hansson@arm.com  // least a buffer of size 1 (very inefficient though, therefore make it bigger?)
27511293Sandreas.hansson@arm.com  // This follows from [27.5.2.4.3]/12 (gptr needs to point at something, it seems)
27611293Sandreas.hansson@arm.com  if (!p || !n)
27711293Sandreas.hansson@arm.com  {
27811293Sandreas.hansson@arm.com    // Replace existing buffer (if any) with small internal buffer
27911293Sandreas.hansson@arm.com    this->disable_buffer();
28011293Sandreas.hansson@arm.com    buffer = NULL;
28111293Sandreas.hansson@arm.com    buffer_size = 0;
28211293Sandreas.hansson@arm.com    own_buffer = true;
28311293Sandreas.hansson@arm.com    this->enable_buffer();
28411293Sandreas.hansson@arm.com  }
28511293Sandreas.hansson@arm.com  else
28611293Sandreas.hansson@arm.com  {
28711293Sandreas.hansson@arm.com    // Replace existing buffer (if any) with external buffer
28811293Sandreas.hansson@arm.com    this->disable_buffer();
28911293Sandreas.hansson@arm.com    buffer = p;
29011293Sandreas.hansson@arm.com    buffer_size = n;
29111293Sandreas.hansson@arm.com    own_buffer = false;
29211293Sandreas.hansson@arm.com    this->enable_buffer();
29311293Sandreas.hansson@arm.com  }
29411293Sandreas.hansson@arm.com  return this;
29511293Sandreas.hansson@arm.com}
29611293Sandreas.hansson@arm.com
29711293Sandreas.hansson@arm.com// Write put area to gzipped file (i.e. ensures that put area is empty)
29811293Sandreas.hansson@arm.comint
29911293Sandreas.hansson@arm.comgzfilebuf::sync()
30011293Sandreas.hansson@arm.com{
30111293Sandreas.hansson@arm.com  return traits_type::eq_int_type(this->overflow(), traits_type::eof()) ? -1 : 0;
30211293Sandreas.hansson@arm.com}
30311293Sandreas.hansson@arm.com
30411293Sandreas.hansson@arm.com/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
30511293Sandreas.hansson@arm.com
30611293Sandreas.hansson@arm.com// Allocate internal buffer
30711293Sandreas.hansson@arm.comvoid
30811293Sandreas.hansson@arm.comgzfilebuf::enable_buffer()
30911293Sandreas.hansson@arm.com{
31011293Sandreas.hansson@arm.com  // If internal buffer required, allocate one
31111293Sandreas.hansson@arm.com  if (own_buffer && !buffer)
31211293Sandreas.hansson@arm.com  {
31311293Sandreas.hansson@arm.com    // Check for buffered vs. "unbuffered"
31411293Sandreas.hansson@arm.com    if (buffer_size > 0)
31511293Sandreas.hansson@arm.com    {
31611293Sandreas.hansson@arm.com      // Allocate internal buffer
31711293Sandreas.hansson@arm.com      buffer = new char_type[buffer_size];
31811293Sandreas.hansson@arm.com      // Get area starts empty and will be expanded by underflow as need arises
31911293Sandreas.hansson@arm.com      this->setg(buffer, buffer, buffer);
32011293Sandreas.hansson@arm.com      // Setup entire internal buffer as put area.
32111293Sandreas.hansson@arm.com      // The one-past-end pointer actually points to the last element of the buffer,
32211293Sandreas.hansson@arm.com      // so that overflow(c) can safely add the extra character c to the sequence.
32311293Sandreas.hansson@arm.com      // These pointers remain in place for the duration of the buffer
32411293Sandreas.hansson@arm.com      this->setp(buffer, buffer + buffer_size - 1);
32511293Sandreas.hansson@arm.com    }
32611293Sandreas.hansson@arm.com    else
32711293Sandreas.hansson@arm.com    {
32811293Sandreas.hansson@arm.com      // Even in "unbuffered" case, (small?) get buffer is still required
32911293Sandreas.hansson@arm.com      buffer_size = SMALLBUFSIZE;
33011293Sandreas.hansson@arm.com      buffer = new char_type[buffer_size];
33111293Sandreas.hansson@arm.com      this->setg(buffer, buffer, buffer);
33211293Sandreas.hansson@arm.com      // "Unbuffered" means no put buffer
33311293Sandreas.hansson@arm.com      this->setp(0, 0);
33411293Sandreas.hansson@arm.com    }
33511293Sandreas.hansson@arm.com  }
33611293Sandreas.hansson@arm.com  else
33711293Sandreas.hansson@arm.com  {
33811293Sandreas.hansson@arm.com    // If buffer already allocated, reset buffer pointers just to make sure no
33911293Sandreas.hansson@arm.com    // stale chars are lying around
34011293Sandreas.hansson@arm.com    this->setg(buffer, buffer, buffer);
34111293Sandreas.hansson@arm.com    this->setp(buffer, buffer + buffer_size - 1);
34211293Sandreas.hansson@arm.com  }
34311293Sandreas.hansson@arm.com}
34411293Sandreas.hansson@arm.com
34511293Sandreas.hansson@arm.com// Destroy internal buffer
34611293Sandreas.hansson@arm.comvoid
34711293Sandreas.hansson@arm.comgzfilebuf::disable_buffer()
34811293Sandreas.hansson@arm.com{
34911293Sandreas.hansson@arm.com  // If internal buffer exists, deallocate it
35011293Sandreas.hansson@arm.com  if (own_buffer && buffer)
35111293Sandreas.hansson@arm.com  {
35211293Sandreas.hansson@arm.com    // Preserve unbuffered status by zeroing size
35311293Sandreas.hansson@arm.com    if (!this->pbase())
35411293Sandreas.hansson@arm.com      buffer_size = 0;
35511293Sandreas.hansson@arm.com    delete[] buffer;
35611293Sandreas.hansson@arm.com    buffer = NULL;
35711293Sandreas.hansson@arm.com    this->setg(0, 0, 0);
35811293Sandreas.hansson@arm.com    this->setp(0, 0);
35911293Sandreas.hansson@arm.com  }
36011293Sandreas.hansson@arm.com  else
36111293Sandreas.hansson@arm.com  {
36211293Sandreas.hansson@arm.com    // Reset buffer pointers to initial state if external buffer exists
36311293Sandreas.hansson@arm.com    this->setg(buffer, buffer, buffer);
36411293Sandreas.hansson@arm.com    if (buffer)
36511293Sandreas.hansson@arm.com      this->setp(buffer, buffer + buffer_size - 1);
36611293Sandreas.hansson@arm.com    else
36711293Sandreas.hansson@arm.com      this->setp(0, 0);
36811293Sandreas.hansson@arm.com  }
36911293Sandreas.hansson@arm.com}
37011293Sandreas.hansson@arm.com
37111293Sandreas.hansson@arm.com/*****************************************************************************/
37211293Sandreas.hansson@arm.com
37311293Sandreas.hansson@arm.com// Default constructor initializes stream buffer
37411293Sandreas.hansson@arm.comgzifstream::gzifstream()
37511293Sandreas.hansson@arm.com: std::istream(NULL), sb()
37611293Sandreas.hansson@arm.com{ this->init(&sb); }
37711293Sandreas.hansson@arm.com
37811293Sandreas.hansson@arm.com// Initialize stream buffer and open file
37911293Sandreas.hansson@arm.comgzifstream::gzifstream(const char* name,
38011293Sandreas.hansson@arm.com                       std::ios_base::openmode mode)
38111293Sandreas.hansson@arm.com: std::istream(NULL), sb()
38211293Sandreas.hansson@arm.com{
38311293Sandreas.hansson@arm.com  this->init(&sb);
38411293Sandreas.hansson@arm.com  this->open(name, mode);
38511293Sandreas.hansson@arm.com}
38611293Sandreas.hansson@arm.com
38711293Sandreas.hansson@arm.com// Initialize stream buffer and attach to file
38811293Sandreas.hansson@arm.comgzifstream::gzifstream(int fd,
38911293Sandreas.hansson@arm.com                       std::ios_base::openmode mode)
39011293Sandreas.hansson@arm.com: std::istream(NULL), sb()
39111293Sandreas.hansson@arm.com{
39211293Sandreas.hansson@arm.com  this->init(&sb);
39311293Sandreas.hansson@arm.com  this->attach(fd, mode);
39411293Sandreas.hansson@arm.com}
39511293Sandreas.hansson@arm.com
39611293Sandreas.hansson@arm.com// Open file and go into fail() state if unsuccessful
39711293Sandreas.hansson@arm.comvoid
39811293Sandreas.hansson@arm.comgzifstream::open(const char* name,
39911293Sandreas.hansson@arm.com                 std::ios_base::openmode mode)
40011293Sandreas.hansson@arm.com{
40111293Sandreas.hansson@arm.com  if (!sb.open(name, mode | std::ios_base::in))
40211293Sandreas.hansson@arm.com    this->setstate(std::ios_base::failbit);
40311293Sandreas.hansson@arm.com  else
40411293Sandreas.hansson@arm.com    this->clear();
40511293Sandreas.hansson@arm.com}
40611293Sandreas.hansson@arm.com
40711293Sandreas.hansson@arm.com// Attach to file and go into fail() state if unsuccessful
40811293Sandreas.hansson@arm.comvoid
40911293Sandreas.hansson@arm.comgzifstream::attach(int fd,
41011293Sandreas.hansson@arm.com                   std::ios_base::openmode mode)
41111293Sandreas.hansson@arm.com{
41211293Sandreas.hansson@arm.com  if (!sb.attach(fd, mode | std::ios_base::in))
41311293Sandreas.hansson@arm.com    this->setstate(std::ios_base::failbit);
41411293Sandreas.hansson@arm.com  else
41511293Sandreas.hansson@arm.com    this->clear();
41611293Sandreas.hansson@arm.com}
41711293Sandreas.hansson@arm.com
41811293Sandreas.hansson@arm.com// Close file
41911293Sandreas.hansson@arm.comvoid
42011293Sandreas.hansson@arm.comgzifstream::close()
42111293Sandreas.hansson@arm.com{
42211293Sandreas.hansson@arm.com  if (!sb.close())
42311293Sandreas.hansson@arm.com    this->setstate(std::ios_base::failbit);
42411293Sandreas.hansson@arm.com}
42511293Sandreas.hansson@arm.com
42611293Sandreas.hansson@arm.com/*****************************************************************************/
42711293Sandreas.hansson@arm.com
42811293Sandreas.hansson@arm.com// Default constructor initializes stream buffer
42911293Sandreas.hansson@arm.comgzofstream::gzofstream()
43011293Sandreas.hansson@arm.com: std::ostream(NULL), sb()
43111293Sandreas.hansson@arm.com{ this->init(&sb); }
43211293Sandreas.hansson@arm.com
43311293Sandreas.hansson@arm.com// Initialize stream buffer and open file
43411293Sandreas.hansson@arm.comgzofstream::gzofstream(const char* name,
43511293Sandreas.hansson@arm.com                       std::ios_base::openmode mode)
43611293Sandreas.hansson@arm.com: std::ostream(NULL), sb()
43711293Sandreas.hansson@arm.com{
43811293Sandreas.hansson@arm.com  this->init(&sb);
43911293Sandreas.hansson@arm.com  this->open(name, mode);
44011293Sandreas.hansson@arm.com}
44111293Sandreas.hansson@arm.com
44211293Sandreas.hansson@arm.com// Initialize stream buffer and attach to file
44311293Sandreas.hansson@arm.comgzofstream::gzofstream(int fd,
44411293Sandreas.hansson@arm.com                       std::ios_base::openmode mode)
44511293Sandreas.hansson@arm.com: std::ostream(NULL), sb()
44611293Sandreas.hansson@arm.com{
44711293Sandreas.hansson@arm.com  this->init(&sb);
44811293Sandreas.hansson@arm.com  this->attach(fd, mode);
44911293Sandreas.hansson@arm.com}
45011293Sandreas.hansson@arm.com
45111293Sandreas.hansson@arm.com// Open file and go into fail() state if unsuccessful
45211293Sandreas.hansson@arm.comvoid
45311293Sandreas.hansson@arm.comgzofstream::open(const char* name,
45411293Sandreas.hansson@arm.com                 std::ios_base::openmode mode)
45511293Sandreas.hansson@arm.com{
45611293Sandreas.hansson@arm.com  if (!sb.open(name, mode | std::ios_base::out))
45711293Sandreas.hansson@arm.com    this->setstate(std::ios_base::failbit);
45811293Sandreas.hansson@arm.com  else
45911293Sandreas.hansson@arm.com    this->clear();
46011293Sandreas.hansson@arm.com}
46111293Sandreas.hansson@arm.com
46211293Sandreas.hansson@arm.com// Attach to file and go into fail() state if unsuccessful
46311293Sandreas.hansson@arm.comvoid
46411293Sandreas.hansson@arm.comgzofstream::attach(int fd,
46511293Sandreas.hansson@arm.com                   std::ios_base::openmode mode)
46611293Sandreas.hansson@arm.com{
46711293Sandreas.hansson@arm.com  if (!sb.attach(fd, mode | std::ios_base::out))
46811293Sandreas.hansson@arm.com    this->setstate(std::ios_base::failbit);
46911293Sandreas.hansson@arm.com  else
47011293Sandreas.hansson@arm.com    this->clear();
47111293Sandreas.hansson@arm.com}
47211293Sandreas.hansson@arm.com
47311293Sandreas.hansson@arm.com// Close file
47411293Sandreas.hansson@arm.comvoid
47511293Sandreas.hansson@arm.comgzofstream::close()
47611293Sandreas.hansson@arm.com{
47711293Sandreas.hansson@arm.com  if (!sb.close())
47811293Sandreas.hansson@arm.com    this->setstate(std::ios_base::failbit);
47911293Sandreas.hansson@arm.com}
480