ref: 81d1e4e01d7001e6a0107792e6167136787295d6
dir: /zip.js/
let encoder = new TextEncoder() let decoder = new TextDecoder() export async function zip(files) { let size = 0 let offset = 0 let main = [] let central = [] for (let file of files) { let info = await getInfo(file, offset) main.push(info.main) central.push(info.central) offset += info.main.size size += info.central.size } return new Blob([...main, ...central, new Uint8Array([0x50, 0x4B, 5, 6]), new Uint16Array([0, 0, files.length, files.length]), new Uint32Array([size, offset]), new Uint16Array([0])], {type: "application/zip"}) } async function getInfo(file, offset) { let bytes = new Uint8Array(await file.arrayBuffer()) let name = encoder.encode(file.name) let crc32 = CRC32(bytes) let main = new Blob([new Uint8Array([0x50, 0x4B, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), new Uint32Array([crc32, bytes.length, bytes.length]), new Uint16Array([name.length, 0]), name, file]) let central = new Blob([new Uint8Array([0x50, 0x4B, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), new Uint32Array([crc32, bytes.length, bytes.length]), new Uint16Array([name.length, 0, 0, 0, 0]), new Uint32Array([0, offset]), name]) return {main, central} } let table = [] for (let n = 0 ; n < 256 ; n++) { let c = n for (let k = 0 ; k < 8 ; k++) c = c & 1 ? 0xEDB88320 ^ (c >>> 1) : c >>> 1 table.push(c) } function CRC32(bytes) { let crc = 0 ^ -1 for (let i = 0 ; i < bytes.length ; i++) crc = (crc >>> 8) ^ table[(crc ^ bytes[i]) & 0xFF] return crc ^ -1 } export async function unzip(bytes) { let n = bytes.length - 22 while (true) { if (n < 0) return if (bytes[n] === 0x50 && bytes[n + 1] === 0x4B && bytes[n + 2] === 5 && bytes[n + 3] === 6) { break } n-- } let array = [] let uint let read = length => { array = [] uint = 0 for (let i = 0 ; i < length ; i++) { if (n > bytes.length - 1) return true uint += bytes[n] * 0x100 ** i array.push(bytes[n]) n++ } } if (read(4)) return if (read(2)) return let index = uint if (read(2)) return if (uint !== index) return if (read(2)) return let count = uint if (read(2)) return if (uint !== count) return if (read(4)) return if (read(4)) return let offset = uint if (read(2)) return if (uint !== bytes.length - n) return let files = new Map() let m = offset for (let i = 0 ; i < count ; i++) { n = m if (read(4)) return if (uint !== 0x02014B50) return if (read(2)) return if (read(2)) return if (read(2)) return let flags = uint if (read(2)) return let compression = uint if (compression !== 0 && compression !== 8) return if (read(2)) return if (read(2)) return if (read(4)) return if (read(4)) return let length = uint if (read(4)) return let totalLength = uint if (read(2)) return let nameLength = uint if (read(2)) return let extraLength = uint if (read(2)) return let commentLength = uint if (read(2)) return if (uint !== index) return if (read(2)) return if (read(4)) return if (read(4)) return let offset = uint if (read(nameLength)) return let name = decoder.decode(new Uint8Array(array)) if (read(extraLength)) return if (read(commentLength)) return m = n n = offset if (read(4)) return if (uint !== 0x04034B50) return if (read(2)) return if (read(2)) return if (uint !== flags) return if (read(2)) return if (uint !== compression) return if (read(2)) return if (read(2)) return if (read(4)) return if (read(4)) return if (uint !== length) if (read(4)) return if (read(4)) return if (uint !== totalLength) return if (read(2)) return if (uint !== nameLength) return if (read(2)) return let localExtraLength = uint if (read(nameLength)) return if (decoder.decode(new Uint8Array(array)) !== name) return if (read(localExtraLength)) return if (read(length)) return let bytes = new Uint8Array(array) if (compression) { try { bytes = new Uint8Array(await new Response(new Blob([bytes]).stream().pipeThrough(new DecompressionStream("deflate-raw"))).arrayBuffer()) } catch { return } } if (bytes.length !== totalLength) return files.set(name, bytes) } return files }