mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-13 08:13:46 +00:00
feat(common): Sd0::Compress, a default Sd0 and room for chunks that don't shrink
Sd0 gets a default constructor and Sd0::Compress(data), the raw sd0 bytes of some data (what the client reads for UGC files it downloads without 3D services). FromData compresses into a heap buffer big enough for a chunk that grows when deflated (it used a 256 KiB stack buffer, so random data failed and workers carried a large stack frame), and drops a half-written result. Tests: chunks as the 1.10.64 client inflates them, incompressible data, empty. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -98,17 +98,20 @@ void Sd0::FromData(const uint8_t* data, size_t bufferSize) {
|
||||
if (bufferSize == 0) return;
|
||||
|
||||
m_Chunks.clear();
|
||||
// Room for a chunk that doesn't compress (zlib makes it slightly bigger), on the heap: this runs on worker threads
|
||||
std::vector<uint8_t> compressedChunk(ZCompression::GetMaxCompressedLength(MAX_UNCOMPRESSED_CHUNK_SIZE));
|
||||
while (bufferSize > 0) {
|
||||
const auto numToCopy = std::min(MAX_UNCOMPRESSED_CHUNK_SIZE, bufferSize);
|
||||
const auto* startOffset = data + originalBufferSize - bufferSize;
|
||||
bufferSize -= numToCopy;
|
||||
std::array<uint8_t, MAX_UNCOMPRESSED_CHUNK_SIZE> compressedChunk;
|
||||
const auto compressedSize = ZCompression::Compress(
|
||||
startOffset, numToCopy,
|
||||
compressedChunk.data(), compressedChunk.size());
|
||||
|
||||
if (compressedSize == -1) {
|
||||
LOG("Failed to compress chunk, aborting");
|
||||
// Part of the data isn't a usable buffer
|
||||
m_Chunks.clear();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -128,6 +131,15 @@ void Sd0::FromData(const uint8_t* data, size_t bufferSize) {
|
||||
|
||||
}
|
||||
|
||||
std::string Sd0::Compress(std::string_view data) {
|
||||
Sd0 sd0;
|
||||
if (data.empty()) return std::string(SD0_HEADER, 5);
|
||||
sd0.FromData(reinterpret_cast<const uint8_t*>(data.data()), data.size());
|
||||
std::string out;
|
||||
for (const auto& chunk : sd0.GetAsVector()) out.append(reinterpret_cast<const char*>(chunk.data()), chunk.size());
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string Sd0::GetAsStringUncompressed() const {
|
||||
std::string toReturn;
|
||||
bool first = true;
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#define SD0_H
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
// Sd0 is comprised of multiple zlib compressed buffers stored in a row.
|
||||
@@ -21,9 +23,16 @@ public:
|
||||
*/
|
||||
static constexpr inline size_t MAX_UNCOMPRESSED_CHUNK_SIZE = 1024 * 256;
|
||||
|
||||
// Empty, for FromData
|
||||
Sd0() = default;
|
||||
|
||||
// Read the input buffer into an internal chunk stream to be used later
|
||||
Sd0(std::istream& buffer);
|
||||
|
||||
// `data` compressed into an sd0 buffer, returned in its raw compressed form (what the client reads, e.g. the UGC
|
||||
// files it downloads without 3D services); only the header when `data` is empty, empty when it can't be compressed
|
||||
[[nodiscard]] static std::string Compress(std::string_view data);
|
||||
|
||||
// Uncompresses the entire Sd0 buffer and returns it as a string
|
||||
[[nodiscard]] std::string GetAsStringUncompressed() const;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user