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
}