111 lines
4.8 KiB
JavaScript
111 lines
4.8 KiB
JavaScript
/**
|
|
* ICD Test Runner — CRUD Helpers
|
|
* Shared utilities for CRUD tier tests (ZIP builder, etc.).
|
|
*/
|
|
(function () {
|
|
'use strict';
|
|
var T = window.ICD;
|
|
if (!T) return;
|
|
if (!T.crud) T.crud = {};
|
|
|
|
// ── Minimal ZIP builder (no dependencies) ──
|
|
// Builds a valid ZIP archive from { filename: content } pairs.
|
|
// Content is UTF-8 strings. Returns a Blob suitable for FormData upload.
|
|
var crc32Table = null;
|
|
|
|
function crc32(bytes) {
|
|
if (!crc32Table) {
|
|
crc32Table = new Uint32Array(256);
|
|
for (var i = 0; i < 256; i++) {
|
|
var c = i;
|
|
for (var j = 0; j < 8; j++) {
|
|
c = (c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1);
|
|
}
|
|
crc32Table[i] = c;
|
|
}
|
|
}
|
|
var crc = 0xFFFFFFFF;
|
|
for (var k = 0; k < bytes.length; k++) {
|
|
crc = crc32Table[(crc ^ bytes[k]) & 0xFF] ^ (crc >>> 8);
|
|
}
|
|
return (crc ^ 0xFFFFFFFF) >>> 0;
|
|
}
|
|
|
|
T.crud.buildTestZip = function (files) {
|
|
var encoder = new TextEncoder();
|
|
var entries = [];
|
|
var offset = 0;
|
|
|
|
// Build file entries
|
|
Object.keys(files).forEach(function (name) {
|
|
var nameBytes = encoder.encode(name);
|
|
var dataBytes = encoder.encode(files[name]);
|
|
var c = crc32(dataBytes);
|
|
entries.push({ name: nameBytes, data: dataBytes, crc: c, offset: offset });
|
|
// Local file header (30) + name + data
|
|
offset += 30 + nameBytes.length + dataBytes.length;
|
|
});
|
|
|
|
// Calculate central directory
|
|
var cdOffset = offset;
|
|
var cdSize = 0;
|
|
entries.forEach(function (e) { cdSize += 46 + e.name.length; });
|
|
|
|
var totalSize = cdOffset + cdSize + 22; // + EOCD
|
|
var buf = new ArrayBuffer(totalSize);
|
|
var view = new DataView(buf);
|
|
var pos = 0;
|
|
|
|
// Write local file headers + data
|
|
entries.forEach(function (e) {
|
|
view.setUint32(pos, 0x04034b50, true); pos += 4; // signature
|
|
view.setUint16(pos, 20, true); pos += 2; // version needed
|
|
view.setUint16(pos, 0, true); pos += 2; // flags
|
|
view.setUint16(pos, 0, true); pos += 2; // compression (store)
|
|
view.setUint16(pos, 0, true); pos += 2; // mod time
|
|
view.setUint16(pos, 0, true); pos += 2; // mod date
|
|
view.setUint32(pos, e.crc, true); pos += 4; // crc32
|
|
view.setUint32(pos, e.data.length, true); pos += 4; // compressed size
|
|
view.setUint32(pos, e.data.length, true); pos += 4; // uncompressed size
|
|
view.setUint16(pos, e.name.length, true); pos += 2; // name length
|
|
view.setUint16(pos, 0, true); pos += 2; // extra length
|
|
new Uint8Array(buf, pos, e.name.length).set(e.name); pos += e.name.length;
|
|
new Uint8Array(buf, pos, e.data.length).set(e.data); pos += e.data.length;
|
|
});
|
|
|
|
// Write central directory
|
|
entries.forEach(function (e) {
|
|
view.setUint32(pos, 0x02014b50, true); pos += 4; // signature
|
|
view.setUint16(pos, 20, true); pos += 2; // version made by
|
|
view.setUint16(pos, 20, true); pos += 2; // version needed
|
|
view.setUint16(pos, 0, true); pos += 2; // flags
|
|
view.setUint16(pos, 0, true); pos += 2; // compression
|
|
view.setUint16(pos, 0, true); pos += 2; // mod time
|
|
view.setUint16(pos, 0, true); pos += 2; // mod date
|
|
view.setUint32(pos, e.crc, true); pos += 4; // crc32
|
|
view.setUint32(pos, e.data.length, true); pos += 4; // compressed size
|
|
view.setUint32(pos, e.data.length, true); pos += 4; // uncompressed size
|
|
view.setUint16(pos, e.name.length, true); pos += 2; // name length
|
|
view.setUint16(pos, 0, true); pos += 2; // extra length
|
|
view.setUint16(pos, 0, true); pos += 2; // comment length
|
|
view.setUint16(pos, 0, true); pos += 2; // disk number
|
|
view.setUint16(pos, 0, true); pos += 2; // internal attrs
|
|
view.setUint32(pos, 0, true); pos += 4; // external attrs
|
|
view.setUint32(pos, e.offset, true); pos += 4; // local header offset
|
|
new Uint8Array(buf, pos, e.name.length).set(e.name); pos += e.name.length;
|
|
});
|
|
|
|
// Write EOCD
|
|
view.setUint32(pos, 0x06054b50, true); pos += 4; // signature
|
|
view.setUint16(pos, 0, true); pos += 2; // disk number
|
|
view.setUint16(pos, 0, true); pos += 2; // cd start disk
|
|
view.setUint16(pos, entries.length, true); pos += 2; // entries on disk
|
|
view.setUint16(pos, entries.length, true); pos += 2; // total entries
|
|
view.setUint32(pos, cdSize, true); pos += 4; // cd size
|
|
view.setUint32(pos, cdOffset, true); pos += 4; // cd offset
|
|
view.setUint16(pos, 0, true); // comment length
|
|
|
|
return new Blob([buf], { type: 'application/zip' });
|
|
};
|
|
})();
|