34bool extractZip(
const std::string& zipData,
const std::filesystem::path& destDir)
36 namespace fs = std::filesystem;
38 const auto* data =
reinterpret_cast<const unsigned char*
>(zipData.data());
39 const size_t dataSize = zipData.size();
42 while (offset + 30 <= dataSize)
44 const uint32_t sig = readU32(data + offset);
45 if (sig != LOCAL_FILE_HEADER_SIG)
48 const uint16_t method = readU16(data + offset + 8);
49 const uint32_t compressedSize = readU32(data + offset + 18);
50 const uint32_t uncompressedSize = readU32(data + offset + 22);
51 const uint16_t nameLen = readU16(data + offset + 26);
52 const uint16_t extraLen = readU16(data + offset + 28);
54 if (offset + 30 + nameLen + extraLen > dataSize)
56 LOG_ERROR <<
"ZIP: truncated local file header at offset" << offset;
60 std::string fileName(
reinterpret_cast<const char*
>(data + offset + 30), nameLen);
61 const size_t dataStart = offset + 30 + nameLen + extraLen;
63 if (dataStart + compressedSize > dataSize)
65 LOG_ERROR <<
"ZIP: truncated file data for" << fileName;
70 if (!fileName.empty() && fileName.back() !=
'/' && fileName.back() !=
'\\')
73 std::replace(fileName.begin(), fileName.end(),
'/',
'\\');
75 const fs::path outPath = destDir / fileName;
79 fs::create_directories(outPath.parent_path(), ec);
81 std::vector<unsigned char> outBuf;
85 outBuf.assign(data + dataStart, data + dataStart + compressedSize);
89 outBuf.resize(uncompressedSize);
92 strm.next_in =
const_cast<unsigned char*
>(data + dataStart);
93 strm.avail_in = compressedSize;
94 strm.next_out = outBuf.data();
95 strm.avail_out = uncompressedSize;
98 if (inflateInit2(&strm, -MAX_WBITS) != Z_OK)
100 LOG_ERROR <<
"ZIP: inflateInit2 failed for" << fileName;
104 const int ret = inflate(&strm, Z_FINISH);
107 if (ret != Z_STREAM_END)
109 LOG_ERROR <<
"ZIP: inflate failed for" << fileName <<
"ret=" << ret;
115 LOG_ERROR <<
"ZIP: unsupported compression method" << method <<
"for" << fileName;
116 offset = dataStart + compressedSize;
120 std::ofstream out(outPath, std::ios::binary);
123 LOG_ERROR <<
"ZIP: failed to create file" << outPath.string();
126 out.write(
reinterpret_cast<const char*
>(outBuf.data()), outBuf.size());
129 offset = dataStart + compressedSize;