fix: Add framebuffer release/realloc and improved lazy indexing (#2563)

This commit is contained in:
Justin Mitchell
2026-07-12 13:16:48 -04:00
committed by GitHub
parent 859f6cb0d5
commit 444d87de82
24 changed files with 10398 additions and 147 deletions
+22 -22
View File
@@ -1,13 +1,12 @@
#include "ZipFile.h"
#include <HalStorage.h>
#include <InflateReader.h>
#include <InflateStream.h>
#include <Logging.h>
#include <algorithm>
struct ZipInflateCtx {
InflateReader reader; // Must be first — callback casts uzlib_uncomp* to ZipInflateCtx*
HalFile* file = nullptr;
size_t fileRemaining = 0;
uint8_t* readBuf = nullptr;
@@ -40,19 +39,16 @@ class ScopedOpenClose final {
bool ok = true; // true when zip was already open (no open() call needed)
};
int zipReadCallback(uzlib_uncomp* uncomp) {
auto* ctx = reinterpret_cast<ZipInflateCtx*>(uncomp);
if (ctx->fileRemaining == 0) return -1;
size_t zipFillCallback(void* vctx, const uint8_t** data) {
auto* ctx = static_cast<ZipInflateCtx*>(vctx);
if (ctx->fileRemaining == 0) return 0;
const size_t toRead = ctx->fileRemaining < ctx->readBufSize ? ctx->fileRemaining : ctx->readBufSize;
const size_t bytesRead = ctx->file->read(ctx->readBuf, toRead);
ctx->fileRemaining -= bytesRead;
if (bytesRead == 0) return -1;
uncomp->source = ctx->readBuf + 1;
uncomp->source_limit = ctx->readBuf + bytesRead;
return ctx->readBuf[0];
*data = ctx->readBuf;
return bytesRead;
}
} // namespace
@@ -410,15 +406,18 @@ uint8_t* ZipFile::readFileToMemory(const char* filename, size_t* size, const boo
ctx.readBuf = fileReadBuffer;
ctx.readBufSize = 1024;
if (!ctx.reader.init(true)) {
LOG_ERR("ZIP", "Failed to init inflate reader");
// One-shot mode: `data` holds the entire output, so back-references
// resolve inside it and no 32KB window is allocated.
InflateStream inflate;
if (!inflate.init(false)) {
LOG_ERR("ZIP", "Failed to init inflate stream");
free(fileReadBuffer);
free(data);
return nullptr;
}
ctx.reader.setReadCallback(zipReadCallback);
inflate.setFill(zipFillCallback, &ctx);
if (!ctx.reader.read(data, inflatedDataSize)) {
if (!inflate.read(data, inflatedDataSize)) {
LOG_ERR("ZIP", "Failed to inflate file");
free(fileReadBuffer);
free(data);
@@ -501,20 +500,21 @@ bool ZipFile::readFileToStream(const char* filename, Print& out, const size_t ch
ctx.readBuf = fileReadBuffer;
ctx.readBufSize = chunkSize;
if (!ctx.reader.init(true)) {
LOG_ERR("ZIP", "Failed to init inflate reader");
InflateStream inflate;
if (!inflate.init(true)) {
LOG_ERR("ZIP", "Failed to init inflate stream");
free(outputBuffer);
free(fileReadBuffer);
return false;
}
ctx.reader.setReadCallback(zipReadCallback);
inflate.setFill(zipFillCallback, &ctx);
bool success = false;
size_t totalProduced = 0;
while (true) {
size_t produced;
const InflateStatus status = ctx.reader.readAtMost(outputBuffer, chunkSize, &produced);
const InflateStream::Status status = inflate.readAtMost(outputBuffer, chunkSize, &produced);
totalProduced += produced;
if (totalProduced > static_cast<size_t>(inflatedDataSize)) {
@@ -530,7 +530,7 @@ bool ZipFile::readFileToStream(const char* filename, Print& out, const size_t ch
}
}
if (status == InflateStatus::Done) {
if (status == InflateStream::Status::Done) {
if (totalProduced != static_cast<size_t>(inflatedDataSize)) {
LOG_ERR("ZIP", "Decompressed size mismatch (expected %zu, got %zu)", static_cast<size_t>(inflatedDataSize),
totalProduced);
@@ -541,16 +541,16 @@ bool ZipFile::readFileToStream(const char* filename, Print& out, const size_t ch
break;
}
if (status == InflateStatus::Error) {
if (status == InflateStream::Status::Error) {
LOG_ERR("ZIP", "Decompression failed");
break;
}
// InflateStatus::Ok: output buffer full, continue
// InflateStream::Status::Ok: output buffer full, continue
}
free(outputBuffer);
free(fileReadBuffer);
return success; // ctx.reader destructor frees the ring buffer
return success; // inflate destructor frees the decompressor state + window
}
LOG_ERR("ZIP", "Unsupported compression method");