IO: updated zip streams
parent
1e43d5bef9
commit
ec9700f9c9
|
@ -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;
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -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() {}
|
||||
/**
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue