mosesdecoder/moses/gzfilebuf.h
Jeroen Vermeulen bd86ceffbe Check for error when opening gzfilebuf.
This replaces a segfault when a file can't be found with an exception.
Not as helpful as it could be yet, but certainly better than just
crashing.

Also, make InputFileStream constructor from path "explicit" to avoid
mistakes.
2015-06-13 21:31:53 +07:00

92 lines
2.4 KiB
C++

#ifndef moses_gzfile_buf_h
#define moses_gzfile_buf_h
#include <stdexcept>
#include <streambuf>
#include <zlib.h>
#include <cstring>
/** wrapper around gzip input stream. Unknown parentage
* @todo replace with boost version - output stream already uses it
*/
class gzfilebuf : public std::streambuf
{
public:
gzfilebuf(const char *filename) {
_gzf = gzopen(filename, "rb");
if (!_gzf)
throw std::runtime_error("Could not open " + std::string(filename) + ".");
setg (_buff+sizeof(int), // beginning of putback area
_buff+sizeof(int), // read position
_buff+sizeof(int)); // end position
}
~gzfilebuf() {
gzclose(_gzf);
}
protected:
virtual int_type overflow (int_type /* c */) {
throw;
}
// write multiple characters
virtual
std::streamsize xsputn (const char* /* s */,
std::streamsize /* num */) {
throw;
}
virtual std::streampos seekpos ( std::streampos /* sp */, std::ios_base::openmode /* which = std::ios_base::in | std::ios_base::out */ ) {
throw;
}
//read one character
virtual int_type underflow () {
// is read position before end of _buff?
if (gptr() < egptr()) {
return traits_type::to_int_type(*gptr());
}
/* process size of putback area
* - use number of characters read
* - but at most four
*/
unsigned int numPutback = gptr() - eback();
if (numPutback > sizeof(int)) {
numPutback = sizeof(int);
}
/* copy up to four characters previously read into
* the putback _buff (area of first four characters)
*/
std::memmove (_buff+(sizeof(int)-numPutback), gptr()-numPutback,
numPutback);
// read new characters
int num = gzread(_gzf, _buff+sizeof(int), _buffsize-sizeof(int));
if (num <= 0) {
// ERROR or EOF
return EOF;
}
// reset _buff pointers
setg (_buff+(sizeof(int)-numPutback), // beginning of putback area
_buff+sizeof(int), // read position
_buff+sizeof(int)+num); // end of buffer
// return next character
return traits_type::to_int_type(*gptr());
}
std::streamsize xsgetn (char* s,
std::streamsize num) {
return gzread(_gzf,s,num);
}
private:
gzFile _gzf;
static const unsigned int _buffsize = 1024;
char _buff[_buffsize];
};
#endif