gildas-lormeau / zip.js

JavaScript library to zip and unzip files supporting multi-core compression, compression streams, zip64, split files and encryption.
https://gildas-lormeau.github.io/zip.js
BSD 3-Clause "New" or "Revised" License
3.4k stars 510 forks source link

Archive differ when using and not using the web walker in deno #466

Closed vi117 closed 10 months ago

vi117 commented 10 months ago

Reproduce

Reproduce the problem with the following code.

Deno version is

deno 1.38.4 (release, x86_64-pc-windows-msvc)
v8 12.0.267.1
typescript 5.2.2

The content of test.txt is "asdfz".

import * as zip from "https://deno.land/x/zipjs@v2.7.31/index.js";

async function testZipInDeno(useWebWorkers: boolean) {
    const blobWriter = new zip.BlobWriter("application/zip");
    const zipFile = new zip.ZipWriter(blobWriter, {
        bufferedWrite: true,
        dataDescriptor: false,
    });
    const filepath = "test.txt";

    const [file, stat] = await Promise.all([
        await Deno.open(filepath, { read: true }),
        await Deno.stat(filepath)]);

        const reader = {
        readable: file.readable
            // .pipeThrough(new TransformStream({
                // transform(chunk, controller) {
                    // console.log("read", chunk.length, "bytes", chunk.byteLength, "buffer", chunk.buffer);
                    // controller.enqueue(chunk);
                // }
            // }))
            ,
        size: stat.size,
    };

    await zipFile.add(
        filepath,
        reader,
        {
            useWebWorkers: useWebWorkers,
            useCompressionStream: true,
        }
    );

    await zipFile.close();

    const blob = await blobWriter.getData();
    console.log(blob.size);
}

await testZipInDeno(true);
await testZipInDeno(false);

The result is

image

It's the same problem as issue #453.

If you uncomment it and run it, it will output something like this:

read 5 bytes 5 buffer ArrayBuffer {
  [Uint8Contents]: <61 73 64 66 7a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... 65436 more bytes>,    
  byteLength: 65536
}
297
read 5 bytes 5 buffer ArrayBuffer {
  [Uint8Contents]: <61 73 64 66 7a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... 65436 more bytes>,    
  byteLength: 65536
}
217

Cause

https://github.com/gildas-lormeau/zip.js/blob/e0a277fc2dfe469f50e86b55101816a235d38b1a/lib/core/codec-worker.js#L237-L274

The problem is caused at line 242 message.value = value.buffer; The size of 'Uint8Array' and 'ArrayBuffer' of 'Uint8Array.buffer' may differ when reading files from Deno.

The simple solution I think is the following code.

if (value.byteLength < value.buffer.byteLength) {
    message.value = value.buffer.slice(0, chunk.byteLength);
}
else {
    message.value = value.buffer;
}

Thanks for the work you do.

gildas-lormeau commented 10 months ago

Thank you very much for the detailed bug report and the fix proposal. I've just published the version 2.7.32 which includes the fix.