UNPKG

molstar

Version:

A comprehensive macromolecular library.

293 lines (292 loc) 9.34 kB
"use strict"; /** * Copyright (c) 2020-2024 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> * * ported from https://github.com/photopea/UZIP.js/blob/master/UZIP.js * MIT License, Copyright (c) 2018 Photopea * * - added `ungzip` */ Object.defineProperty(exports, "__esModule", { value: true }); exports.Unzip = Unzip; exports.unzip = unzip; exports.inflateRaw = inflateRaw; exports.inflate = inflate; exports.ungzip = ungzip; exports.deflate = deflate; exports.Zip = Zip; exports.zip = zip; const bin_1 = require("./bin"); const checksum_1 = require("./checksum"); const inflate_1 = require("./inflate"); const deflate_1 = require("./deflate"); const mol_task_1 = require("../../mol-task"); function Unzip(buf, onlyNames = false) { return mol_task_1.Task.create('Unzip', ctx => unzip(ctx, buf, onlyNames)); } async function unzip(runtime, buf, onlyNames = false) { const out = Object.create(null); const data = new Uint8Array(buf); if ((0, bin_1.readUshort)(data, 0) !== 0x4b50) { throw new Error('Invalid ZIP file. A valid ZIP file must start with two magic bytes \\x50\\x4b ("PK" in ASCII).'); } let eocd = data.length - 4; while ((0, bin_1.readUint)(data, eocd) !== 0x06054b50) eocd--; let o = eocd; o += 4; // sign = 0x06054b50 o += 4; // disks = 0; const cnu = (0, bin_1.readUshort)(data, o); o += 2; // const cnt = readUshort(data, o); o += 2; // const csize = readUint(data, o); o += 4; const coffs = (0, bin_1.readUint)(data, o); o += 4; o = coffs; for (let i = 0; i < cnu; i++) { // const sign = readUint(data, o); o += 4; o += 4; // versions; o += 4; // flag + compr o += 4; // time // const crc32 = readUint(data, o); o += 4; // const csize = readUint(data, o); o += 4; // const usize = readUint(data, o); o += 4; const nl = (0, bin_1.readUshort)(data, o); const el = (0, bin_1.readUshort)(data, o + 2); const cl = (0, bin_1.readUshort)(data, o + 4); o += 6; // name, extra, comment o += 8; // disk, attribs const roff = (0, bin_1.readUint)(data, o); o += 4; o += nl + el + cl; await _readLocal(runtime, data, roff, out, onlyNames); } // console.log(out); return out; } async function _readLocal(runtime, data, o, out, onlyNames) { // const sign = readUint(data, o); o += 4; // const ver = readUshort(data, o); o += 2; // const gpflg = readUshort(data, o); o += 2; // if((gpflg&8)!=0) throw "unknown sizes"; const cmpr = (0, bin_1.readUshort)(data, o); o += 2; // const time = readUint(data, o); o += 4; // const crc32 = readUint(data, o); o += 4; const csize = (0, bin_1.readUint)(data, o); o += 4; const usize = (0, bin_1.readUint)(data, o); o += 4; const nlen = (0, bin_1.readUshort)(data, o); o += 2; const elen = (0, bin_1.readUshort)(data, o); o += 2; const name = (0, bin_1.readUTF8)(data, o, nlen); // console.log({ name, nlen, elen }); o += nlen; o += elen; if (onlyNames) { out[name] = { size: usize, csize }; return; } const file = new Uint8Array(data.buffer, o, csize); if (cmpr === 0) { out[name] = file; } else if (cmpr === 8) { const buf = new Uint8Array(usize); await inflateRaw(runtime, file, buf); out[name] = buf; } else { throw new Error(`unknown compression method: ${cmpr}`); } } async function inflateRaw(runtime, file, buf) { return (0, inflate_1._inflate)(runtime, file, buf); } function inflate(runtime, file, buf) { // const CMF = file[0] // const FLG = file[1] // const CM = (CMF&15) // const CINFO = (CMF>>>4); // console.log(CM, CINFO,CMF,FLG); return inflateRaw(runtime, new Uint8Array(file.buffer, file.byteOffset + 2, file.length - 6), buf); } // https://tools.ietf.org/html/rfc1952 async function ungzip(runtime, file, buf) { // const id1 = file[0] // const id2 = file[1] // const cm = file[2] const flg = file[3]; // const mtime = readUint(file, 4) // const xfl = file[8] // const os = file[9] let o = 10; if (flg & 4) { // FEXTRA const xlen = (0, bin_1.readUshort)(file, o); // console.log('FEXTRA', xlen) o += xlen; } if (flg & 8) { // FNAME let zero = o; while (file[zero] !== 0) ++zero; // const name = readUTF8(file, o, zero - o) // console.log('FNAME', name, zero - o) o = zero + 1; } if (flg & 16) { // FCOMMENT let zero = o; while (file[zero] !== 0) ++zero; // const comment = readUTF8(file, o, zero - o) // console.log('FCOMMENT', comment) o = zero + 1; } if (flg & 1) { // FHCRC // const hcrc = readUshort(file, o) // console.log('FHCRC', hcrc) o += 2; } const crc32 = (0, bin_1.toInt32)((0, bin_1.readUint)(file, file.length - 8)); const isize = (0, bin_1.readUint)(file, file.length - 4); if (buf === undefined) buf = new Uint8Array(isize); const blocks = new Uint8Array(file.buffer, file.byteOffset + o, file.length - o - 8); const inflated = await inflateRaw(runtime, blocks, buf); const crcValue = (0, checksum_1.crc)(inflated, 0, inflated.length); if (crc32 !== crcValue) { console.error("ungzip: checksums don't match"); } return inflated; } async function deflate(runtime, data, opts /* , buf, off*/) { if (opts === undefined) opts = { level: 6 }; let off = 0; const buf = new Uint8Array(50 + Math.floor(data.length * 1.1)); buf[off] = 120; buf[off + 1] = 156; off += 2; off = await (0, deflate_1._deflateRaw)(runtime, data, buf, off, opts.level); const crcValue = (0, checksum_1.adler)(data, 0, data.length); buf[off + 0] = ((crcValue >>> 24) & 255); buf[off + 1] = ((crcValue >>> 16) & 255); buf[off + 2] = ((crcValue >>> 8) & 255); buf[off + 3] = ((crcValue >>> 0) & 255); return new Uint8Array(buf.buffer, 0, off + 4); } async function deflateRaw(runtime, data, opts) { if (opts === undefined) opts = { level: 6 }; const buf = new Uint8Array(50 + Math.floor(data.length * 1.1)); const off = await (0, deflate_1._deflateRaw)(runtime, data, buf, 0, opts.level); return new Uint8Array(buf.buffer, 0, off); } function Zip(obj, noCmpr = false) { return mol_task_1.Task.create('Zip', ctx => zip(ctx, obj, noCmpr)); } async function zip(runtime, obj, noCmpr = false) { let tot = 0; const zpd = {}; for (const p in obj) { const cpr = !_noNeed(p) && !noCmpr, buf = obj[p]; const crcValue = (0, checksum_1.crc)(buf, 0, buf.length); zpd[p] = { cpr, usize: buf.length, crc: crcValue, file: (cpr ? await deflateRaw(runtime, buf) : buf) }; } for (const p in zpd) tot += zpd[p].file.length + 30 + 46 + 2 * (0, bin_1.sizeUTF8)(p); tot += 22; const data = new Uint8Array(tot); let o = 0; const fof = []; for (const p in zpd) { const file = zpd[p]; fof.push(o); o = _writeHeader(data, o, p, file, 0); } let i = 0; const ioff = o; for (const p in zpd) { const file = zpd[p]; fof.push(o); o = _writeHeader(data, o, p, file, 1, fof[i++]); } const csize = o - ioff; (0, bin_1.writeUint)(data, o, 0x06054b50); o += 4; o += 4; // disks (0, bin_1.writeUshort)(data, o, i); o += 2; (0, bin_1.writeUshort)(data, o, i); o += 2; // number of c d records (0, bin_1.writeUint)(data, o, csize); o += 4; (0, bin_1.writeUint)(data, o, ioff); o += 4; o += 2; return data.buffer; } // no need to compress .PNG, .ZIP, .JPEG .... function _noNeed(fn) { const ext = fn.split('.').pop().toLowerCase(); return 'png,jpg,jpeg,zip'.indexOf(ext) !== -1; } function _writeHeader(data, o, p, obj, t, roff = 0) { const file = obj.file; (0, bin_1.writeUint)(data, o, t === 0 ? 0x04034b50 : 0x02014b50); o += 4; // sign if (t === 1) o += 2; // ver made by (0, bin_1.writeUshort)(data, o, 20); o += 2; // ver (0, bin_1.writeUshort)(data, o, 0); o += 2; // gflip (0, bin_1.writeUshort)(data, o, obj.cpr ? 8 : 0); o += 2; // cmpr (0, bin_1.writeUint)(data, o, 0); o += 4; // time (0, bin_1.writeUint)(data, o, obj.crc); o += 4; // crc32 (0, bin_1.writeUint)(data, o, file.length); o += 4; // csize (0, bin_1.writeUint)(data, o, obj.usize); o += 4; // usize (0, bin_1.writeUshort)(data, o, (0, bin_1.sizeUTF8)(p)); o += 2; // nlen (0, bin_1.writeUshort)(data, o, 0); o += 2; // elen if (t === 1) { o += 2; // comment length o += 2; // disk number o += 6; // attributes (0, bin_1.writeUint)(data, o, roff); o += 4; // usize } const nlen = (0, bin_1.writeUTF8)(data, o, p); o += nlen; if (t === 0) { data.set(file, o); o += file.length; } return o; }