Skip to content

Commit

Permalink
MXML.zip()
Browse files Browse the repository at this point in the history
  • Loading branch information
jazz-soft committed Nov 3, 2024
1 parent 9cb441f commit 1cb2000
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 20 deletions.
2 changes: 1 addition & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default [
},
{
languageOptions: {
ecmaVersion: 2015,
ecmaVersion: 8,
globals: {
...globals.node
}
Expand Down
103 changes: 86 additions & 17 deletions jazz-mxml.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,40 +37,44 @@ if (typeof DOMParser != 'undefined') {
};
}

var tostring, inflate;
if (typeof DecompressionStream != 'undefined') {
inflate = async function(b) {
const ds = new DecompressionStream('deflate-raw');
const writer = ds.writable.getWriter();
writer.write(b);
writer.close();
return await new Response(ds.readable).arrayBuffer();
};
tostring = function(x) { return new TextDecoder().decode(x); };
}
else {
const zlib = require('zlib');
inflate = function(b) { return zlib.inflateRawSync(b); };
tostring = function(x) { return String(x); };
async function inflate(b) {
const ds = new DecompressionStream('deflate-raw');
const writer = ds.writable.getWriter();
writer.write(b);
writer.close();
return await new Response(ds.readable).arrayBuffer();
}

async function deflate(b) {
const ds = new CompressionStream('deflate-raw');
const writer = ds.writable.getWriter();
writer.write(b);
writer.close();
return await new Response(ds.readable).arrayBuffer();
};
function tostring(x) { return new TextDecoder().decode(x); }
function tobuffer(x) { return new TextEncoder().encode(x); }
function n2(b, n) { return b[n] + b[n + 1] * 0x100; }
function n4(b, n) { return b[n] + b[n + 1] * 0x100 + b[n + 2] * 0x10000 + b[n + 3] * 0x1000000; }
function ww(b, n, x, w) { for (var i = 0; i < w; i++) { b[n + i] = x & 255; x >>= 8; } }
function w2(b, n, x) { ww(b, n, x, 2); }
function w4(b, n, x) { ww(b, n, x, 4); }
function wb(b, n, x) { for (var i = 0; i < x.length; i++) b[n + i] = x[i]; }
function dos2date(n) {
return new Date((n >> 25) + 1980, ((n >> 21) & 15) - 1, (n >> 16) & 31, (n >> 11) & 31, (n >> 5) & 63, (n & 31) << 1);
}
function date2dos(d) {
return (d.getSeconds() >> 1) + (d.getMinutes() << 5) + (d.getHours() << 11) + (d.getDate() << 16) + ((d.getMonth() + 1) << 21) + ((d.getFullYear() - 1980) << 25);
}
const meta_inf = 'META-INF/container.xml';
const meta_xml = '<?xml version="1.0" encoding="UTF-8"?><container><rootfiles><rootfile full-path="data.xml"></rootfile></rootfiles></container>';
MXML.zipInfo = function(data) {
const inf = zipInfo(data);
if (inf) {
var a = [];
for (var k of inf.FFF) a.push({ name: k, size: inf.FF[k].size, date: inf.FF[k].date });
return a;
}
}
};
MXML.unzip = async function(data) {
const inf = zipInfo(data);
if (!inf) return;
Expand All @@ -97,6 +101,71 @@ MXML.unzip = async function(data) {
}
return s2 || s1 || s0;
}
MXML.zip = async function(data, name) {
var x;
var date = date2dos(new Date());
var A = name ? [{ data: data, name: tobuffer(name) }] : [{ data: tobuffer(meta_xml), name: tobuffer(meta_inf) }, { data: data, name: tobuffer('data.xml') }];
var n = 0;
for (x of A) {
x.off = n;
x.crc = crc(x.data);
x.buff = await deflate(x.data);
if (x.buff.length < x.data.length) x.comp = 8;
else {
x.buff = x.data;
x.comp = 0;
}
n += 30 + x.name.length + x.buff.length;
}
var m = n;
for (x of A) n += 46 + x.name.length;
var B = new Uint8Array(n + 22);
n = 0;
for (x of A) {
w4(B, n, 0x04034b50);
w2(B, n + 4, 20);
w2(B, n + 6, 0);
w2(B, n + 8, x.comp);
w4(B, n + 10, date);
w4(B, n + 14, x.crc);
w4(B, n + 18, x.buff.length);
w4(B, n + 22, x.data.length);
w2(B, n + 26, x.name.length);
w2(B, n + 28, 0);
wb(B, n + 30, x.name);
wb(B, n + 30 + x.name.length, x.buff);
n += 30 + x.name.length + x.buff.length;
}
for (x of A) {
w4(B, n, 0x02014b50);
w2(B, n + 4, 20);
w2(B, n + 6, 20);
w2(B, n + 8, 0);
w2(B, n + 10, x.comp);
w4(B, n + 12, date);
w4(B, n + 16, x.crc);
w4(B, n + 20, x.buff.length);
w4(B, n + 24, x.data.length);
w2(B, n + 28, x.name.length);
w2(B, n + 30, 0);
w2(B, n + 32, 0);
w2(B, n + 34, 0);
w2(B, n + 36, 0);
w4(B, n + 38, 0);
w4(B, n + 42, x.off);
wb(B, n + 46, x.name);
n += 46 + x.name.length;
}
w4(B, n, 0x06054b50);
w2(B, n + 4, 0);
w2(B, n + 6, 0);
w2(B, n + 8, A.length);
w2(B, n + 10, A.length);
w4(B, n + 12, n - m);
w4(B, n + 16, m);
w2(B, n + 20, 0);
return B;
}
function zipInfo(data) {
var i, m, n;
var nrec, fnlen, exlen, cmlen, fname;
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "jazz-mxml",
"version": "0.0.1",
"version": "0.0.2",
"description": "coming soon...",
"main": "jazz-mxml.js",
"scripts": {
Expand All @@ -19,7 +19,7 @@
"jzz-midi-smf": "^1.9.5"
},
"devDependencies": {
"eslint": "^9.13.0",
"eslint": "^9.14.0",
"mocha": "^10.8.2",
"nyc": "^17.1.0"
},
Expand Down
11 changes: 11 additions & 0 deletions test/mocha.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,17 @@ describe('files', function() {
var X = new MXML(await MXML.unzip(data));
assert.equal(X.isValid(), true);
});
it('xml -> mxl', async function() {
var X = MXML.zipInfo(await MXML.zip(partwise));
assert.equal(X.length, 2);
assert.equal(X[0].name, 'META-INF/container.xml');
assert.equal(X[1].name, 'data.xml');
});
it('xml -> zip', async function() {
var X = MXML.zipInfo(await MXML.zip('dummy', 'dummy.txt'));
assert.equal(X.length, 1);
assert.equal(X[0].name, 'dummy.txt');
});
});

describe('utils', function() {
Expand Down

0 comments on commit 1cb2000

Please sign in to comment.