simgear/io/iostreams/zlibstream.*: improved support for reading compressed data.

Added support for seeking (forwards only) - in ZlibAbstractIStreambuf, added
seekoff().

Also disabled assert that checked that we reach EOF compressed data at same
time as EOF uncompressed data; was breaking things when using embedded
compressed streams within fgtape recording.

Added ZLibCompressionFormat::ZLIB_RAW, uses windowBits=-15, for zlib compressed
streams without header or trailer.

Fixed clang build error with std::min().
This commit is contained in:
Julian Smith 2021-06-13 20:39:48 +01:00
parent d01e9ca2e6
commit 95239fea87
2 changed files with 36 additions and 4 deletions

View File

@ -157,7 +157,6 @@ ZlibAbstractIStreambuf::ZlibAbstractIStreambuf(std::istream& iStream,
_putbackSize(putbackSize)
{
assert(_inBufSize > 0);
assert(_putbackSize >= 0); // guaranteed unless the type is changed...
assert(_putbackSize < _outBufSize);
if (_inBuf == nullptr) {
@ -249,6 +248,28 @@ int ZlibAbstractIStreambuf::underflow()
return (gptr() == egptr()) ? traits::eof() : traits::to_int_type(*gptr());
}
std::streampos ZlibAbstractIStreambuf::seekoff(std::streamoff off,
std::ios_base::seekdir way,
std::ios_base::openmode which)
{
if (way != std::ios_base::cur || off < 0) return -1;
for(;;) {
if (!off) break;
char* g = gptr();
char* eg = egptr();
if (eg > g) {
size_t delta = (off < eg - g) ? off : eg - g;
setg(g + delta, g + delta, eg);
off -= delta;
}
else {
if (underflow() == EOF) return -1;
}
}
return 0;
}
// Simple utility method for fillOutputBuffer(), used to improve readability.
// Return the remaining space available in the output buffer, where zlib can
// write.
@ -320,7 +341,7 @@ char* ZlibAbstractIStreambuf::fillOutputBuffer()
if (retCode == Z_BUF_ERROR) {
handleZ_BUF_ERROR(); // doesn't return
} else if (retCode == Z_STREAM_END) {
assert(_zstream.avail_in == 0); // all of _inBuf must have been used
//assert(_zstream.avail_in == 0); // all of _inBuf must have been used
_allFinished = true;
break;
} else if (retCode < 0) { // negative codes are errors
@ -481,7 +502,7 @@ std::streamsize ZlibAbstractIStreambuf::xsgetn(char* dest, std::streamsize n)
if (retCode == Z_BUF_ERROR) {
handleZ_BUF_ERROR(); // doesn't return
} else if (retCode == Z_STREAM_END) {
assert(_zstream.avail_in == 0); // all of _inBuf must have been used
//assert(_zstream.avail_in == 0); // all of _inBuf must have been used
_allFinished = true;
break;
} else if (retCode < 0) { // negative codes are errors
@ -730,6 +751,9 @@ void ZlibDecompressorIStreambuf::zStreamInit(ZLibCompressionFormat format)
case ZLibCompressionFormat::AUTODETECT:
windowBits = 47; // 47 = 32 + 15
break;
case ZLibCompressionFormat::ZLIB_RAW:
windowBits = -15;
break;
default:
throw std::logic_error("Unexpected compression format: " +
std::to_string(enumValue(format)));

View File

@ -103,7 +103,8 @@ namespace simgear
enum class ZLibCompressionFormat {
ZLIB = 0,
GZIP,
AUTODETECT
AUTODETECT,
ZLIB_RAW, // No zlib header or trailer.
};
enum class ZLibMemoryStrategy {
@ -196,6 +197,13 @@ private:
// Callback whose role is to refill the output buffer when it's empty and
// the “client” tries to read more.
virtual int underflow() override;
// We only support seeking forwards, with way==std::ios_base::cur and
// off>=0, returning 0. Otherwise we return -1.
std::streampos seekoff(std::streamoff off,
std::ios_base::seekdir way,
std::ios_base::openmode which) override;
// Optional override when subclassing std::streambuf. This is the most
// efficient way of reading several characters (as soon as we've emptied the
// output buffer, data is written by zlib directly to the destination