b54a3139c7
Includes QWB, Qortal Web, and Q-Shops Q-Apps with shared packages and build scripts. Co-authored-by: Cursor <cursoragent@cursor.com>
145 lines
4.4 KiB
JavaScript
145 lines
4.4 KiB
JavaScript
/**
|
|
* Minimal ZIP (STORE / no compression) for browser — one dependency-free helper
|
|
* so PUBLISH_QDN_RESOURCE can ship WEBSITE/APP archives from this Q-App.
|
|
*/
|
|
(function (global) {
|
|
'use strict';
|
|
|
|
const crcTable = (function makeTable() {
|
|
const t = new Uint32Array(256);
|
|
for (let i = 0; i < 256; i++) {
|
|
let c = i;
|
|
for (let k = 0; k < 8; k++) c = (c & 1) ? (0xedb88320 ^ (c >>> 1)) : (c >>> 1);
|
|
t[i] = c >>> 0;
|
|
}
|
|
return t;
|
|
})();
|
|
|
|
function crc32(buf) {
|
|
let c = 0xffffffff;
|
|
for (let i = 0; i < buf.length; i++) c = crcTable[(c ^ buf[i]) & 0xff] ^ (c >>> 8);
|
|
return (c ^ 0xffffffff) >>> 0;
|
|
}
|
|
|
|
function strToUtf8(s) {
|
|
return new TextEncoder().encode(String(s));
|
|
}
|
|
|
|
/** @param {Record<string, Uint8Array|string>} files map path -> bytes or utf8 string */
|
|
function buildZipStore(files) {
|
|
const entries = Object.keys(files).map((name) => {
|
|
const raw = files[name];
|
|
const data = raw instanceof Uint8Array ? raw : strToUtf8(raw);
|
|
return { name, data };
|
|
});
|
|
|
|
let offset = 0;
|
|
const parts = [];
|
|
const central = [];
|
|
|
|
for (const e of entries) {
|
|
const nameBytes = strToUtf8(e.name);
|
|
const nameLen = nameBytes.length;
|
|
const data = e.data;
|
|
const size = data.length;
|
|
const crc = crc32(data);
|
|
const sig = 0x04034b50;
|
|
const ver = 20;
|
|
const flags = 0;
|
|
const method = 0;
|
|
const time = 0;
|
|
const date = 0;
|
|
const csize = size;
|
|
const hlen = 30 + nameLen;
|
|
|
|
const local = new DataView(new ArrayBuffer(hlen + size));
|
|
let p = 0;
|
|
local.setUint32(p, sig, true); p += 4;
|
|
local.setUint16(p, ver, true); p += 2;
|
|
local.setUint16(p, flags, true); p += 2;
|
|
local.setUint16(p, method, true); p += 2;
|
|
local.setUint16(p, time, true); p += 2;
|
|
local.setUint16(p, date, true); p += 2;
|
|
local.setUint32(p, crc, true); p += 4;
|
|
local.setUint32(p, csize, true); p += 4;
|
|
local.setUint32(p, size, true); p += 4;
|
|
local.setUint16(p, nameLen, true); p += 2;
|
|
local.setUint16(p, 0, true); p += 2;
|
|
new Uint8Array(local.buffer).set(nameBytes, p);
|
|
p += nameLen;
|
|
new Uint8Array(local.buffer).set(data, p);
|
|
|
|
parts.push(new Uint8Array(local.buffer));
|
|
central.push({
|
|
nameBytes,
|
|
crc,
|
|
size,
|
|
csize,
|
|
localOffset: offset,
|
|
});
|
|
offset += local.buffer.byteLength;
|
|
}
|
|
|
|
const cdParts = [];
|
|
let cdSize = 0;
|
|
let cdOffset = offset;
|
|
for (let i = 0; i < central.length; i++) {
|
|
const c = central[i];
|
|
const nameLen = c.nameBytes.length;
|
|
const hlen = 46 + nameLen;
|
|
const buf = new DataView(new ArrayBuffer(46));
|
|
let q = 0;
|
|
buf.setUint32(q, 0x02014b50, true); q += 4;
|
|
buf.setUint16(q, 20, true); q += 2;
|
|
buf.setUint16(q, 20, true); q += 2;
|
|
buf.setUint16(q, 0, true); q += 2;
|
|
buf.setUint16(q, 0, true); q += 2;
|
|
buf.setUint16(q, 0, true); q += 2;
|
|
buf.setUint16(q, 0, true); q += 2;
|
|
buf.setUint32(q, c.crc, true); q += 4;
|
|
buf.setUint32(q, c.csize, true); q += 4;
|
|
buf.setUint32(q, c.size, true); q += 4;
|
|
buf.setUint16(q, nameLen, true); q += 2;
|
|
buf.setUint16(q, 0, true); q += 2;
|
|
buf.setUint16(q, 0, true); q += 2;
|
|
buf.setUint16(q, 0, true); q += 2;
|
|
buf.setUint16(q, 0, true); q += 2;
|
|
buf.setUint32(q, 0, true); q += 4;
|
|
buf.setUint32(q, c.localOffset, true); q += 4;
|
|
const header = new Uint8Array(buf.buffer);
|
|
const merged = new Uint8Array(hlen);
|
|
merged.set(header, 0);
|
|
merged.set(c.nameBytes, 46);
|
|
cdParts.push(merged);
|
|
cdSize += merged.length;
|
|
}
|
|
|
|
const eoc = new DataView(new ArrayBuffer(22));
|
|
eoc.setUint32(0, 0x06054b50, true);
|
|
eoc.setUint16(4, 0, true);
|
|
eoc.setUint16(6, 0, true);
|
|
eoc.setUint16(8, entries.length, true);
|
|
eoc.setUint16(10, entries.length, true);
|
|
eoc.setUint32(12, cdSize, true);
|
|
eoc.setUint32(16, cdOffset, true);
|
|
eoc.setUint16(20, 0, true);
|
|
|
|
const totalLen = offset + cdSize + 22;
|
|
const out = new Uint8Array(totalLen);
|
|
let o = 0;
|
|
for (const part of parts) {
|
|
out.set(part, o);
|
|
o += part.length;
|
|
}
|
|
for (const part of cdParts) {
|
|
out.set(part, o);
|
|
o += part.length;
|
|
}
|
|
out.set(new Uint8Array(eoc.buffer), o);
|
|
|
|
return out;
|
|
}
|
|
|
|
global.buildZipStore = buildZipStore;
|
|
})(typeof window !== 'undefined' ? window : globalThis);
|