`zipSync` can get order of ZIP entries wrong, due to how objects work
rauschma opened this issue · comments
It’s been a pleasure to use fflate! There is one small issue that may be too unimportant to fix, but I wanted to point it out anyway. Feel free to close this issue if you don’t think it matters enough.
Occasionally the order in which entries appear in a ZIP file matters – e.g., in EPUB files. Then zipSync
may not work as expected:
const entries = {
'first.xml': new Uint8Array(),
'123': new Uint8Array(),
};
fflate.zipSync(entries);
// In which order are the entries processed?
assert.deepEqual(
Object.keys(entries),
[ '123', 'first.xml' ]
);
Why is that? Object keys are listed in this order:
- First all “indices” (string keys that contain non-negative integers), sorted numerically
- Then all other string keys, in insertion order
- Then all symbol keys, in insertion order
Potential solutions:
- Accept an Array of entries:
fflate.zipSync([ ['first.xml', new Uint8Array()], ['123', new Uint8Array()], ]);
- Use a builder:
const zb = new fflate.ZipBuilder(); zb.addEntry('first.xml', new Uint8Array()); zb.addEntry('123', new Uint8Array());
This is technically avoidable using the streaming API. That being said it's definitely less convenient.
const chunks = [];
const zipper = new fflate.Zip((err, data, final) => {
chunks.push(data);
});
const file = new fflate.ZipDeflate('sample.txt', { level: 9 });
file.push(new Uint8Array([...]), true);
zipper.add(file);
zipper.end();
// since ZipDeflate is synchronous we're done here
const out = new Blob(chunks); // etc.
I might still try to make a nicer API for this but there are a few backlogged issues I need to get to first.
Ah, nice! I assumed that streaming meant “not synchronous”.
I might still try to make a nicer API for this but there are a few backlogged issues I need to get to first.
Sure! Many people are probably happy with the async API but I’d appreciate a way to synchronously and incrementally write a ZIP file to disk.
synchronously and incrementally write a ZIP file to disk.
That's what the streaming API does; if you stream data into ZipDeflate by pushing data in chunks, it comes out in chunks too, fully synchronously. For async streaming you use AsyncZipDeflate.