101arrowz / fflate

High performance (de)compression in an 8kB package

Home Page:https://101arrowz.github.io/fflate

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`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.