From aa2a70de8d6c9b00cce2d7eb6f2ccceaae646ff7 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 6 May 2026 08:13:04 -0700 Subject: [PATCH] fix(wcp): detect truncated WCP files on unpack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously a short read (truncated WCP, partial download, etc.) would silently write the partial bytes that were read and report success — leaving the consumer with a half-extracted zone that would fail in confusing ways at runtime. Check gcount and return false so the caller can refuse the broken pack. --- tools/editor/content_pack.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tools/editor/content_pack.cpp b/tools/editor/content_pack.cpp index 6870e86f..cc841e2e 100644 --- a/tools/editor/content_pack.cpp +++ b/tools/editor/content_pack.cpp @@ -208,10 +208,24 @@ bool ContentPacker::unpackZone(const std::string& wcpPath, const std::string& de std::vector data(dataSize); in.read(data.data(), dataSize); + // Detect short reads — indicates the WCP was truncated mid-file. + // gcount() reflects the actual bytes read; if it's less than dataSize + // we'd write a partial file silently and the consumer would think + // the zone is intact. + auto bytesRead = in.gcount(); + if (bytesRead != static_cast(dataSize)) { + LOG_ERROR("WCP file ", path, " truncated: expected ", dataSize, + " got ", bytesRead); + return false; + } std::string fullPath = zoneDir + "/" + path; fs::create_directories(fs::path(fullPath).parent_path()); std::ofstream fout(fullPath, std::ios::binary); + if (!fout) { + LOG_ERROR("WCP could not open output file: ", fullPath); + return false; + } fout.write(data.data(), dataSize); }