IO: updated zip streams

master
Martin Gerhardy 2022-01-27 18:23:04 +01:00
parent 1e43d5bef9
commit ec9700f9c9
9 changed files with 151 additions and 26 deletions

View File

@ -41,9 +41,15 @@ int BufferedReadWriteStream::write(const void *buf, size_t size) {
}
int BufferedReadWriteStream::read(void *buf, size_t size) {
if (_pos + (int64_t)size > _size) {
const int64_t remainingSize = remaining();
if (remainingSize <= 0) {
return -1;
}
if ((int64_t)size > remainingSize) {
core_memcpy(buf, &_buffer[_pos], remainingSize);
_pos += (int64_t)remainingSize;
return (int)remainingSize;
}
core_memcpy(buf, &_buffer[_pos], size);
_pos += (int64_t)size;
return (int)size;

View File

@ -27,6 +27,7 @@ set(TEST_SRCS
tests/FormatDescriptionTest.cpp
tests/FileTest.cpp
tests/MemoryReadStreamTest.cpp
tests/ZipStreamTest.cpp
)
gtest_suite_sources(tests ${TEST_SRCS})

View File

@ -5,6 +5,7 @@
#pragma once
#include "core/Common.h"
#include "core/NonCopyable.h"
#include "core/String.h"
#include <stdio.h>
#include <stddef.h>
@ -12,7 +13,7 @@
namespace io {
class ReadStream {
class ReadStream : public core::NonCopyable {
public:
virtual ~ReadStream() {}
/**
@ -85,7 +86,7 @@ inline bool SeekableReadStream::empty() const {
return size() == 0;
}
class WriteStream {
class WriteStream : public core::NonCopyable {
public:
virtual ~WriteStream() {}
/**

View File

@ -3,14 +3,18 @@
*/
#include "ZipReadStream.h"
#include "core/Log.h"
#include "core/StandardLib.h"
#include "core/miniz.h"
namespace io {
ZipReadStream::ZipReadStream(io::ReadStream &readStream) : _readStream(readStream) {
ZipReadStream::ZipReadStream(io::SeekableReadStream &readStream, int size)
: _readStream(readStream), _size(size), _remaining(size) {
_stream = (mz_stream *)core_malloc(sizeof(*_stream));
core_memset(_stream, 0, sizeof(*_stream));
_stream->zalloc = Z_NULL;
_stream->zfree = Z_NULL;
mz_inflateInit(_stream);
}
@ -20,35 +24,56 @@ ZipReadStream::~ZipReadStream() {
}
bool ZipReadStream::eos() const {
return _eos;
return remaining() == 0;
}
int64_t ZipReadStream::remaining() const {
if (_size >= 0) {
core_assert_msg(_remaining >= 0, "if size is given (%i), remaining should be >= 0 - but is %i", _size, _remaining);
return core_min(_remaining, _readStream.remaining());
}
return _readStream.remaining();
}
int ZipReadStream::read(void *buf, size_t size) {
_stream->next_out = (unsigned char *)buf;
_stream->avail_out = static_cast<unsigned int>(size);
while (_stream->avail_out != 0) {
uint8_t *targetPtr = (uint8_t *)buf;
const size_t originalSize = size;
while (size > 0) {
if (_stream->avail_in == 0) {
const int retVal = _readStream.read(_buf, sizeof(_buf));
if (retVal == -1) {
return -1;
}
int64_t remainingSize = remaining();
_stream->next_in = _buf;
_stream->avail_in = static_cast<unsigned int>(retVal);
_stream->avail_in = (unsigned int)core_min(remainingSize, (int64_t)sizeof(_buf));
if (remainingSize > 0) {
_readStream.read(_buf, _stream->avail_in);
if (_size >= 0) {
_remaining -= (int)_stream->avail_in;
}
}
}
const int mzRet = mz_inflate(_stream, MZ_NO_FLUSH);
if (mzRet == MZ_STREAM_END) {
_eos = true;
return (int)(size - _stream->avail_out);
_stream->avail_out = (unsigned int)size;
_stream->next_out = targetPtr;
const int retval = mz_inflate(_stream, MZ_NO_FLUSH);
switch (retval) {
case MZ_STREAM_ERROR:
case MZ_NEED_DICT:
case MZ_DATA_ERROR:
case MZ_MEM_ERROR:
return -1;
}
if (mzRet != MZ_OK) {
const size_t outputSize = size - (size_t)_stream->avail_out;
targetPtr += outputSize;
core_assert(size >= outputSize);
size -= outputSize;
if (size > 0 && retval == MZ_STREAM_END) {
// attempting to read past the end of the stream
return -1;
}
}
return (int)(size - _stream->avail_out);
return (int)originalSize;
}
} // namespace io

View File

@ -13,16 +13,18 @@ namespace io {
class ZipReadStream : public io::ReadStream {
private:
struct mz_stream_s *_stream;
io::ReadStream &_readStream;
io::SeekableReadStream &_readStream;
uint8_t _buf[256 * 1024];
bool _eos = false;
const int _size;
int _remaining;
public:
ZipReadStream(io::ReadStream &readStream);
ZipReadStream(io::SeekableReadStream &readStream, int size = -1);
virtual ~ZipReadStream();
int read(void *dataPtr, size_t dataSize) override;
bool eos() const override;
int64_t remaining() const;
};
} // namespace io

View File

@ -11,10 +11,13 @@ namespace io {
ZipWriteStream::ZipWriteStream(io::WriteStream &out, int level) : _outStream(out) {
_stream = (mz_stream *)core_malloc(sizeof(*_stream));
core_memset(_stream, 0, sizeof(*_stream));
_stream->zalloc = Z_NULL;
_stream->zfree = Z_NULL;
mz_deflateInit(_stream, level);
}
ZipWriteStream::~ZipWriteStream() {
flush();
const int retVal = mz_deflateEnd(_stream);
core_free(_stream);
core_assert(retVal == MZ_OK);
@ -44,4 +47,18 @@ int ZipWriteStream::write(const void *buf, size_t size) {
return (int)size;
}
bool ZipWriteStream::flush() {
_stream->avail_in = 0;
_stream->avail_out = sizeof(_out);
_stream->next_out = _out;
const int retVal = mz_deflate(_stream, MZ_FINISH);
if (retVal == MZ_STREAM_ERROR) {
return false;
}
size_t remaining = sizeof(_out) - _stream->avail_out;
return _outStream.write(_out, remaining) != -1;
}
} // namespace io

View File

@ -23,6 +23,7 @@ public:
int write(const void *buf, size_t size) override;
int64_t pos() const;
bool flush();
};
inline int64_t ZipWriteStream::pos() const {

View File

@ -109,10 +109,9 @@ TEST(BufferedReadWriteStreamTest, testReadExceedsSize) {
int8_t writeVal = 0;
stream.writeInt8(writeVal);
stream.seek(0);
const int64_t previous = stream.remaining();
int64_t readVal;
EXPECT_EQ(-1, stream.readInt64(readVal));
EXPECT_EQ(previous, stream.remaining());
EXPECT_EQ(0, stream.remaining());
}
TEST(BufferedReadWriteStreamTest, testSeek) {

View File

@ -0,0 +1,73 @@
/**
* @file
*/
#include "io/BufferedReadWriteStream.h"
#include "io/ZipReadStream.h"
#include "io/ZipWriteStream.h"
#include <gtest/gtest.h>
namespace io {
class ZipStreamTest : public testing::Test {};
TEST_F(ZipStreamTest, testZipStream) {
BufferedReadWriteStream stream(1024);
{
ZipWriteStream w(stream);
for (int i = 0; i < 64; ++i) {
ASSERT_TRUE(w.writeInt32(i + 0)) << "unexpected write failure for step: " << i;
ASSERT_TRUE(w.writeInt32(i + 1)) << "unexpected write failure for step: " << i;
ASSERT_TRUE(w.writeInt32(i + 2)) << "unexpected write failure for step: " << i;
ASSERT_TRUE(w.writeInt32(i + 3)) << "unexpected write failure for step: " << i;
}
ASSERT_TRUE(w.flush());
}
const int size = (int)stream.size();
stream.seek(0);
{
ZipReadStream r(stream, size);
for (int i = 0; i < 64; ++i) {
int32_t n;
ASSERT_EQ(0, r.readInt32(n)) << "unexpected read failure for step: " << i;
ASSERT_EQ(n, i + 0) << "unexpected extracted value for step: " << i;
ASSERT_EQ(0, r.readInt32(n)) << "unexpected read failure for step: " << i;
ASSERT_EQ(n, i + 1) << "unexpected extracted value for step: " << i;
ASSERT_EQ(0, r.readInt32(n)) << "unexpected read failure for step: " << i;
ASSERT_EQ(n, i + 2) << "unexpected extracted value for step: " << i;
ASSERT_EQ(0, r.readInt32(n)) << "unexpected read failure for step: " << i;
ASSERT_EQ(n, i + 3) << "unexpected extracted value for step: " << i;
}
}
}
TEST_F(ZipStreamTest, testZipStreamNoSize) {
BufferedReadWriteStream stream(1024);
{
ZipWriteStream w(stream);
for (int i = 0; i < 64; ++i) {
ASSERT_TRUE(w.writeInt32(i + 0)) << "unexpected write failure for step: " << i;
ASSERT_TRUE(w.writeInt32(i + 1)) << "unexpected write failure for step: " << i;
ASSERT_TRUE(w.writeInt32(i + 2)) << "unexpected write failure for step: " << i;
ASSERT_TRUE(w.writeInt32(i + 3)) << "unexpected write failure for step: " << i;
}
ASSERT_TRUE(w.flush());
}
stream.seek(0);
{
ZipReadStream r(stream);
for (int i = 0; i < 64; ++i) {
int32_t n;
ASSERT_EQ(0, r.readInt32(n)) << "unexpected read failure for step: " << i;
ASSERT_EQ(n, i + 0) << "unexpected extracted value for step: " << i;
ASSERT_EQ(0, r.readInt32(n)) << "unexpected read failure for step: " << i;
ASSERT_EQ(n, i + 1) << "unexpected extracted value for step: " << i;
ASSERT_EQ(0, r.readInt32(n)) << "unexpected read failure for step: " << i;
ASSERT_EQ(n, i + 2) << "unexpected extracted value for step: " << i;
ASSERT_EQ(0, r.readInt32(n)) << "unexpected read failure for step: " << i;
ASSERT_EQ(n, i + 3) << "unexpected extracted value for step: " << i;
}
}
}
} // namespace io