mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-16 03:23:15 +01:00
Merge pull request #22595 from ZehMatt/sawyer-junk-2
Improve performance for SawyerChunkReader once again
This commit is contained in:
@@ -9,10 +9,11 @@
|
||||
|
||||
#include "SawyerChunk.h"
|
||||
|
||||
#include "../core/Memory.hpp"
|
||||
#include "SawyerChunkReader.h"
|
||||
|
||||
SawyerChunk::SawyerChunk(SAWYER_ENCODING encoding, std::vector<uint8_t>&& data)
|
||||
using namespace OpenRCT2;
|
||||
|
||||
SawyerChunk::SawyerChunk(SAWYER_ENCODING encoding, MemoryStream&& data)
|
||||
: _data(std::move(data))
|
||||
, _encoding(encoding)
|
||||
{
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "../core/MemoryStream.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
/**
|
||||
* The type of encoding / compression for a sawyer encoded chunk.
|
||||
@@ -29,22 +30,22 @@ enum class SAWYER_ENCODING : uint8_t
|
||||
class SawyerChunk final
|
||||
{
|
||||
private:
|
||||
std::vector<uint8_t> _data;
|
||||
OpenRCT2::MemoryStream _data;
|
||||
SAWYER_ENCODING _encoding = SAWYER_ENCODING::NONE;
|
||||
|
||||
public:
|
||||
const void* GetData() const
|
||||
{
|
||||
return _data.data();
|
||||
return _data.GetData();
|
||||
}
|
||||
size_t GetLength() const
|
||||
{
|
||||
return _data.size();
|
||||
return _data.GetLength();
|
||||
}
|
||||
SAWYER_ENCODING GetEncoding() const
|
||||
{
|
||||
return _encoding;
|
||||
}
|
||||
|
||||
SawyerChunk(SAWYER_ENCODING encoding, std::vector<uint8_t>&& data);
|
||||
SawyerChunk(SAWYER_ENCODING encoding, OpenRCT2::MemoryStream&& data);
|
||||
};
|
||||
|
||||
@@ -10,20 +10,11 @@
|
||||
#include "SawyerChunkReader.h"
|
||||
|
||||
#include "../core/IStream.hpp"
|
||||
#include "../core/MemoryStream.h"
|
||||
#include "../core/Numerics.hpp"
|
||||
|
||||
using namespace OpenRCT2;
|
||||
|
||||
// malloc is very slow for large allocations in MSVC debug builds as it allocates
|
||||
// memory on a special debug heap and then initialises all the memory to 0xCC.
|
||||
#if defined(_WIN32) && defined(DEBUG)
|
||||
# define __USE_HEAP_ALLOC__
|
||||
# ifndef WIN32_LEAN_AND_MEAN
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# endif
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
// Allow chunks to be uncompressed to a maximum of 16 MiB
|
||||
constexpr size_t MAX_UNCOMPRESSED_CHUNK_SIZE = 16 * 1024 * 1024;
|
||||
|
||||
@@ -33,6 +24,8 @@ constexpr const char* EXCEPTION_MSG_DESTINATION_TOO_SMALL = "Chunk data larger t
|
||||
constexpr const char* EXCEPTION_MSG_INVALID_CHUNK_ENCODING = "Invalid chunk encoding.";
|
||||
constexpr const char* EXCEPTION_MSG_ZERO_SIZED_CHUNK = "Encountered zero-sized chunk.";
|
||||
|
||||
static MemoryStream DecodeChunk(const void* src, const SawyerCodingChunkHeader& header);
|
||||
|
||||
SawyerChunkReader::SawyerChunkReader(OpenRCT2::IStream* stream)
|
||||
: _stream(stream)
|
||||
{
|
||||
@@ -77,10 +70,11 @@ std::shared_ptr<SawyerChunk> SawyerChunkReader::ReadChunk()
|
||||
}
|
||||
|
||||
auto buffer = DecodeChunk(compressedData.get(), header);
|
||||
if (buffer.empty())
|
||||
if (buffer.GetLength() == 0)
|
||||
{
|
||||
throw SawyerChunkException(EXCEPTION_MSG_ZERO_SIZED_CHUNK);
|
||||
}
|
||||
|
||||
return std::make_shared<SawyerChunk>(static_cast<SAWYER_ENCODING>(header.encoding), std::move(buffer));
|
||||
}
|
||||
default:
|
||||
@@ -116,7 +110,7 @@ std::shared_ptr<SawyerChunk> SawyerChunkReader::ReadChunkTrack()
|
||||
|
||||
SawyerCodingChunkHeader header{ CHUNK_ENCODING_RLE, compressedDataLength };
|
||||
auto buffer = DecodeChunk(compressedData.get(), header);
|
||||
if (buffer.empty())
|
||||
if (buffer.GetLength() == 0)
|
||||
{
|
||||
throw SawyerChunkException(EXCEPTION_MSG_ZERO_SIZED_CHUNK);
|
||||
}
|
||||
@@ -151,40 +145,9 @@ void SawyerChunkReader::ReadChunk(void* dst, size_t length)
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> SawyerChunkReader::DecodeChunk(const void* src, const SawyerCodingChunkHeader& header)
|
||||
static MemoryStream DecodeChunkRLE(const void* src, size_t srcLength)
|
||||
{
|
||||
std::vector<uint8_t> buf;
|
||||
switch (header.encoding)
|
||||
{
|
||||
case CHUNK_ENCODING_NONE:
|
||||
buf.resize(header.length);
|
||||
std::memcpy(buf.data(), src, header.length);
|
||||
break;
|
||||
case CHUNK_ENCODING_RLE:
|
||||
buf = DecodeChunkRLE(src, header.length);
|
||||
break;
|
||||
case CHUNK_ENCODING_RLECOMPRESSED:
|
||||
buf = DecodeChunkRLERepeat(src, header.length);
|
||||
break;
|
||||
case CHUNK_ENCODING_ROTATE:
|
||||
buf = DecodeChunkRotate(src, header.length);
|
||||
break;
|
||||
default:
|
||||
throw SawyerChunkException(EXCEPTION_MSG_INVALID_CHUNK_ENCODING);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> SawyerChunkReader::DecodeChunkRLERepeat(const void* src, size_t srcLength)
|
||||
{
|
||||
auto tempBuf = DecodeChunkRLE(src, srcLength);
|
||||
return DecodeChunkRepeat(tempBuf.data(), tempBuf.size());
|
||||
}
|
||||
|
||||
std::vector<uint8_t> SawyerChunkReader::DecodeChunkRLE(const void* src, size_t srcLength)
|
||||
{
|
||||
std::vector<uint8_t> buf;
|
||||
buf.reserve(srcLength);
|
||||
MemoryStream buf;
|
||||
|
||||
auto src8 = static_cast<const uint8_t*>(src);
|
||||
for (size_t i = 0; i < srcLength; i++)
|
||||
@@ -199,12 +162,15 @@ std::vector<uint8_t> SawyerChunkReader::DecodeChunkRLE(const void* src, size_t s
|
||||
{
|
||||
throw SawyerChunkException(EXCEPTION_MSG_CORRUPT_RLE);
|
||||
}
|
||||
if (buf.size() + count > MAX_UNCOMPRESSED_CHUNK_SIZE)
|
||||
if (buf.GetLength() + count > MAX_UNCOMPRESSED_CHUNK_SIZE)
|
||||
{
|
||||
throw SawyerChunkException(EXCEPTION_MSG_DESTINATION_TOO_SMALL);
|
||||
}
|
||||
|
||||
buf.insert(buf.end(), count, src8[i]);
|
||||
for (size_t n = 0; n < count; n++)
|
||||
{
|
||||
buf.Write1(src8 + i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -214,7 +180,7 @@ std::vector<uint8_t> SawyerChunkReader::DecodeChunkRLE(const void* src, size_t s
|
||||
{
|
||||
throw SawyerChunkException(EXCEPTION_MSG_CORRUPT_RLE);
|
||||
}
|
||||
if (buf.size() + len > MAX_UNCOMPRESSED_CHUNK_SIZE)
|
||||
if (buf.GetLength() + len > MAX_UNCOMPRESSED_CHUNK_SIZE)
|
||||
{
|
||||
throw SawyerChunkException(EXCEPTION_MSG_DESTINATION_TOO_SMALL);
|
||||
}
|
||||
@@ -224,8 +190,8 @@ std::vector<uint8_t> SawyerChunkReader::DecodeChunkRLE(const void* src, size_t s
|
||||
}
|
||||
|
||||
const auto* pos = src8 + i + 1;
|
||||
buf.insert(buf.end(), pos, pos + len);
|
||||
|
||||
buf.Write(pos, len);
|
||||
i += len;
|
||||
}
|
||||
}
|
||||
@@ -233,10 +199,9 @@ std::vector<uint8_t> SawyerChunkReader::DecodeChunkRLE(const void* src, size_t s
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> SawyerChunkReader::DecodeChunkRepeat(const void* src, size_t srcLength)
|
||||
static MemoryStream DecodeChunkRepeat(const void* src, size_t srcLength)
|
||||
{
|
||||
std::vector<uint8_t> buf;
|
||||
buf.reserve(srcLength);
|
||||
MemoryStream buf;
|
||||
|
||||
auto src8 = static_cast<const uint8_t*>(src);
|
||||
for (size_t i = 0; i < srcLength; i++)
|
||||
@@ -247,15 +212,17 @@ std::vector<uint8_t> SawyerChunkReader::DecodeChunkRepeat(const void* src, size_
|
||||
{
|
||||
throw SawyerChunkException(EXCEPTION_MSG_CORRUPT_RLE);
|
||||
}
|
||||
buf.push_back(src8[++i]);
|
||||
i++;
|
||||
buf.Write1(src8 + i);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t count = (src8[i] & 7) + 1;
|
||||
int32_t offset = static_cast<int32_t>(src8[i] >> 3) - 32;
|
||||
const uint8_t* copySrc = buf.data() + (buf.size() + offset);
|
||||
const uint8_t* copySrc = static_cast<const uint8_t*>(buf.GetData()) + (buf.GetLength() + offset);
|
||||
|
||||
if (copySrc < buf.data() || copySrc + count > buf.data() + buf.size())
|
||||
if (copySrc < static_cast<const uint8_t*>(buf.GetData())
|
||||
|| copySrc + count > static_cast<const uint8_t*>(buf.GetData()) + buf.GetLength())
|
||||
{
|
||||
throw SawyerChunkException(EXCEPTION_MSG_CORRUPT_RLE);
|
||||
}
|
||||
@@ -264,26 +231,60 @@ std::vector<uint8_t> SawyerChunkReader::DecodeChunkRepeat(const void* src, size_
|
||||
uint8_t temp[16];
|
||||
std::memcpy(temp, copySrc, count);
|
||||
|
||||
buf.insert(buf.end(), std::begin(temp), std::begin(temp) + count);
|
||||
buf.Write(temp, count);
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> SawyerChunkReader::DecodeChunkRotate(const void* src, size_t srcLength)
|
||||
static MemoryStream DecodeChunkRLERepeat(const void* src, size_t srcLength)
|
||||
{
|
||||
std::vector<uint8_t> buf;
|
||||
buf.reserve(srcLength);
|
||||
auto tempBuf = DecodeChunkRLE(src, srcLength);
|
||||
return DecodeChunkRepeat(tempBuf.GetData(), tempBuf.GetLength());
|
||||
}
|
||||
|
||||
static MemoryStream DecodeChunkRotate(const void* src, size_t srcLength)
|
||||
{
|
||||
MemoryStream buf;
|
||||
|
||||
auto src8 = static_cast<const uint8_t*>(src);
|
||||
|
||||
uint8_t code = 1;
|
||||
for (size_t i = 0; i < srcLength; i++)
|
||||
{
|
||||
buf.push_back(Numerics::ror8(src8[i], code));
|
||||
uint8_t temp = Numerics::ror8(src8[i], code);
|
||||
buf.Write1(&temp);
|
||||
code = (code + 2) % 8;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static MemoryStream DecodeChunk(const void* src, const SawyerCodingChunkHeader& header)
|
||||
{
|
||||
MemoryStream buf;
|
||||
|
||||
switch (header.encoding)
|
||||
{
|
||||
case CHUNK_ENCODING_NONE:
|
||||
buf.Write(src, header.length);
|
||||
break;
|
||||
case CHUNK_ENCODING_RLE:
|
||||
buf = DecodeChunkRLE(src, header.length);
|
||||
break;
|
||||
case CHUNK_ENCODING_RLECOMPRESSED:
|
||||
buf = DecodeChunkRLERepeat(src, header.length);
|
||||
break;
|
||||
case CHUNK_ENCODING_ROTATE:
|
||||
buf = DecodeChunkRotate(src, header.length);
|
||||
break;
|
||||
default:
|
||||
throw SawyerChunkException(EXCEPTION_MSG_INVALID_CHUNK_ENCODING);
|
||||
}
|
||||
|
||||
// Return the stream with the position at the beginning.
|
||||
buf.SetPosition(0);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -85,11 +85,4 @@ public:
|
||||
ReadChunk(&result, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
static std::vector<uint8_t> DecodeChunk(const void* src, const SawyerCodingChunkHeader& header);
|
||||
static std::vector<uint8_t> DecodeChunkRLERepeat(const void* src, size_t srcLength);
|
||||
static std::vector<uint8_t> DecodeChunkRLE(const void* src, size_t srcLength);
|
||||
static std::vector<uint8_t> DecodeChunkRepeat(const void* src, size_t srcLength);
|
||||
static std::vector<uint8_t> DecodeChunkRotate(const void* src, size_t srcLength);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user