#include "zfstream.h"
#include <cstring> // for strcpy, strcat, strlen (mode strings)
#include <cstdio> // for BUFSIZ
#define BIGBUFSIZE BUFSIZ
#define SMALLBUFSIZE 1
gzfilebuf::gzfilebuf()
: file(NULL), io_mode(std::ios_base::openmode(0)), own_fd(false),
buffer(NULL), buffer_size(BIGBUFSIZE), own_buffer(true)
{
this->disable_buffer();
}
gzfilebuf::~gzfilebuf()
{
this->sync();
if (own_fd)
this->close();
this->disable_buffer();
}
int
gzfilebuf::setcompression(int comp_level,
int comp_strategy)
{
return gzsetparams(file, comp_level, comp_strategy);
}
gzfilebuf*
gzfilebuf::open(const char *name,
std::ios_base::openmode mode)
{
if (this->is_open())
return NULL;
if ((mode & std::ios_base::in) && (mode & std::ios_base::out))
return NULL;
char char_mode[6] = "\0\0\0\0\0";
if (!this->open_mode(mode, char_mode))
return NULL;
if ((file = gzopen(name, char_mode)) == NULL)
return NULL;
this->enable_buffer();
io_mode = mode;
own_fd = true;
return this;
}
gzfilebuf*
gzfilebuf::attach(int fd,
std::ios_base::openmode mode)
{
if (this->is_open())
return NULL;
if ((mode & std::ios_base::in) && (mode & std::ios_base::out))
return NULL;
char char_mode[6] = "\0\0\0\0\0";
if (!this->open_mode(mode, char_mode))
return NULL;
if ((file = gzdopen(fd, char_mode)) == NULL)
return NULL;
this->enable_buffer();
io_mode = mode;
own_fd = false;
return this;
}
gzfilebuf*
gzfilebuf::close()
{
if (!this->is_open())
return NULL;
gzfilebuf* retval = this;
if (this->sync() == -1)
retval = NULL;
if (gzclose(file) < 0)
retval = NULL;
file = NULL;
own_fd = false;
this->disable_buffer();
return retval;
}
bool
gzfilebuf::open_mode(std::ios_base::openmode mode,
char* c_mode) const
{
bool testb = mode & std::ios_base::binary;
bool testi = mode & std::ios_base::in;
bool testo = mode & std::ios_base::out;
bool testt = mode & std::ios_base::trunc;
bool testa = mode & std::ios_base::app;
if (!testi && testo && !testt && !testa)
strcpy(c_mode, "w");
if (!testi && testo && !testt && testa)
strcpy(c_mode, "a");
if (!testi && testo && testt && !testa)
strcpy(c_mode, "w");
if (testi && !testo && !testt && !testa)
strcpy(c_mode, "r");
if (strlen(c_mode) == 0)
return false;
if (testb)
strcat(c_mode, "b");
return true;
}
std::streamsize
gzfilebuf::showmanyc()
{
if (!this->is_open() || !(io_mode & std::ios_base::in))
return -1;
if (this->gptr() && (this->gptr() < this->egptr()))
return std::streamsize(this->egptr() - this->gptr());
else
return 0;
}
gzfilebuf::int_type
gzfilebuf::underflow()
{
if (this->gptr() && (this->gptr() < this->egptr()))
return traits_type::to_int_type(*(this->gptr()));
if (!this->is_open() || !(io_mode & std::ios_base::in))
return traits_type::eof();
int bytes_read = gzread(file, buffer, buffer_size);
if (bytes_read <= 0)
{
this->setg(buffer, buffer, buffer);
return traits_type::eof();
}
this->setg(buffer, buffer, buffer + bytes_read);
return traits_type::to_int_type(*(this->gptr()));
}
gzfilebuf::int_type
gzfilebuf::overflow(int_type c)
{
if (this->pbase())
{
if (this->pptr() > this->epptr() || this->pptr() < this->pbase())
return traits_type::eof();
if (!traits_type::eq_int_type(c, traits_type::eof()))
{
*(this->pptr()) = traits_type::to_char_type(c);
this->pbump(1);
}
int bytes_to_write = this->pptr() - this->pbase();
if (bytes_to_write > 0)
{
if (!this->is_open() || !(io_mode & std::ios_base::out))
return traits_type::eof();
if (gzwrite(file, this->pbase(), bytes_to_write) != bytes_to_write)
return traits_type::eof();
this->pbump(-bytes_to_write);
}
}
else if (!traits_type::eq_int_type(c, traits_type::eof()))
{
if (!this->is_open() || !(io_mode & std::ios_base::out))
return traits_type::eof();
char_type last_char = traits_type::to_char_type(c);
if (gzwrite(file, &last_char, 1) != 1)
return traits_type::eof();
}
if (traits_type::eq_int_type(c, traits_type::eof()))
return traits_type::not_eof(c);
else
return c;
}
std::streambuf*
gzfilebuf::setbuf(char_type* p,
std::streamsize n)
{
if (this->sync() == -1)
return NULL;
if (!p || !n)
{
this->disable_buffer();
buffer = NULL;
buffer_size = 0;
own_buffer = true;
this->enable_buffer();
}
else
{
this->disable_buffer();
buffer = p;
buffer_size = n;
own_buffer = false;
this->enable_buffer();
}
return this;
}
int
gzfilebuf::sync()
{
return traits_type::eq_int_type(this->overflow(), traits_type::eof()) ? -1 : 0;
}
void
gzfilebuf::enable_buffer()
{
if (own_buffer && !buffer)
{
if (buffer_size > 0)
{
buffer = new char_type[buffer_size];
this->setg(buffer, buffer, buffer);
this->setp(buffer, buffer + buffer_size - 1);
}
else
{
buffer_size = SMALLBUFSIZE;
buffer = new char_type[buffer_size];
this->setg(buffer, buffer, buffer);
this->setp(0, 0);
}
}
else
{
this->setg(buffer, buffer, buffer);
this->setp(buffer, buffer + buffer_size - 1);
}
}
void
gzfilebuf::disable_buffer()
{
if (own_buffer && buffer)
{
if (!this->pbase())
buffer_size = 0;
delete[] buffer;
buffer = NULL;
this->setg(0, 0, 0);
this->setp(0, 0);
}
else
{
this->setg(buffer, buffer, buffer);
if (buffer)
this->setp(buffer, buffer + buffer_size - 1);
else
this->setp(0, 0);
}
}
gzifstream::gzifstream()
: std::istream(NULL), sb()
{ this->init(&sb); }
gzifstream::gzifstream(const char* name,
std::ios_base::openmode mode)
: std::istream(NULL), sb()
{
this->init(&sb);
this->open(name, mode);
}
gzifstream::gzifstream(int fd,
std::ios_base::openmode mode)
: std::istream(NULL), sb()
{
this->init(&sb);
this->attach(fd, mode);
}
void
gzifstream::open(const char* name,
std::ios_base::openmode mode)
{
if (!sb.open(name, mode | std::ios_base::in))
this->setstate(std::ios_base::failbit);
else
this->clear();
}
void
gzifstream::attach(int fd,
std::ios_base::openmode mode)
{
if (!sb.attach(fd, mode | std::ios_base::in))
this->setstate(std::ios_base::failbit);
else
this->clear();
}
void
gzifstream::close()
{
if (!sb.close())
this->setstate(std::ios_base::failbit);
}
gzofstream::gzofstream()
: std::ostream(NULL), sb()
{ this->init(&sb); }
gzofstream::gzofstream(const char* name,
std::ios_base::openmode mode)
: std::ostream(NULL), sb()
{
this->init(&sb);
this->open(name, mode);
}
gzofstream::gzofstream(int fd,
std::ios_base::openmode mode)
: std::ostream(NULL), sb()
{
this->init(&sb);
this->attach(fd, mode);
}
void
gzofstream::open(const char* name,
std::ios_base::openmode mode)
{
if (!sb.open(name, mode | std::ios_base::out))
this->setstate(std::ios_base::failbit);
else
this->clear();
}
void
gzofstream::attach(int fd,
std::ios_base::openmode mode)
{
if (!sb.attach(fd, mode | std::ios_base::out))
this->setstate(std::ios_base::failbit);
else
this->clear();
}
void
gzofstream::close()
{
if (!sb.close())
this->setstate(std::ios_base::failbit);
}