Files
codex-market-app/electron/lib/zip.js
T
2026-07-15 18:01:56 +08:00

51 lines
2.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// zip.js —— 零依赖 ZIP 解压(stored/deflate),供技能安装与热更新复用。
"use strict";
const fs = require("fs");
const path = require("path");
const zlib = require("zlib");
// 解析中央目录,把 zip 内容写入 destDir;返回写出的文件数。
function extractZip(buf, destDir) {
// 找 EOCD(0x06054b50),从尾部回扫
let eocd = -1;
for (let i = buf.length - 22; i >= 0 && i >= buf.length - 22 - 65536; i--) {
if (buf.readUInt32LE(i) === 0x06054b50) { eocd = i; break; }
}
if (eocd < 0) throw new Error("不是有效的 zip(找不到 EOCD)");
const count = buf.readUInt16LE(eocd + 10);
let ptr = buf.readUInt32LE(eocd + 16); // 中央目录起始偏移
let written = 0;
for (let n = 0; n < count; n++) {
if (buf.readUInt32LE(ptr) !== 0x02014b50) break;
const method = buf.readUInt16LE(ptr + 10);
const compSize = buf.readUInt32LE(ptr + 20);
const nameLen = buf.readUInt16LE(ptr + 28);
const extraLen = buf.readUInt16LE(ptr + 30);
const commentLen = buf.readUInt16LE(ptr + 32);
const localOff = buf.readUInt32LE(ptr + 42);
const name = buf.toString("utf8", ptr + 46, ptr + 46 + nameLen);
ptr += 46 + nameLen + extraLen + commentLen;
// 读本地头,定位数据
if (buf.readUInt32LE(localOff) !== 0x04034b50) continue;
const lNameLen = buf.readUInt16LE(localOff + 26);
const lExtraLen = buf.readUInt16LE(localOff + 28);
const dataStart = localOff + 30 + lNameLen + lExtraLen;
const comp = buf.subarray(dataStart, dataStart + compSize);
// 防目录穿越
const safe = name.replace(/\\/g, "/").replace(/^\/+/, "");
if (safe.includes("../")) continue;
const outPath = path.join(destDir, safe);
if (safe.endsWith("/")) { fs.mkdirSync(outPath, { recursive: true }); continue; }
fs.mkdirSync(path.dirname(outPath), { recursive: true });
let data;
if (method === 0) data = comp;
else if (method === 8) data = zlib.inflateRawSync(comp);
else throw new Error(`不支持的压缩方式 ${method}`);
fs.writeFileSync(outPath, data);
written++;
}
return written;
}
module.exports = { extractZip };