mirror of
https://github.com/codedread/bitjs
synced 2025-10-03 17:49:16 +02:00
Fix issue #38: Use runtime's native DecompressionStream to inflate zip streams.
This commit is contained in:
parent
5bf583c617
commit
4ca68bd336
4 changed files with 48 additions and 15 deletions
|
@ -7,9 +7,16 @@ All notable changes to this project will be documented in this file.
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- archive: Support DEFLATE in Zipper where JS implementations support it in CompressionStream.
|
- archive: Support DEFLATE in Zipper where JS implementations support it in CompressionStream.
|
||||||
|
[Issue #40](https://github.com/codedread/bitjs/issues/40)
|
||||||
|
- archive: Support DEFLATE in Unzipper where JS implementations support it in DecompressionStream.
|
||||||
|
[Issue #38](https://github.com/codedread/bitjs/issues/38)
|
||||||
- file: Added detection of GZIP files.
|
- file: Added detection of GZIP files.
|
||||||
- io: Added a skip() method to BitStream to match ByteStream.
|
- io: Added a skip() method to BitStream to match ByteStream.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed a benign JS error in the Web Worker wrapper
|
||||||
|
|
||||||
## [1.2.1] - 2024-01-19
|
## [1.2.1] - 2024-01-19
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
12
README.md
12
README.md
|
@ -8,15 +8,13 @@ A set of dependency-free JavaScript modules to handle binary data in JS (using
|
||||||
[Typed Arrays](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray)).
|
[Typed Arrays](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray)).
|
||||||
Includes:
|
Includes:
|
||||||
|
|
||||||
* bitjs/archive: Unarchiving files (unzip, unrar, untar) in JavaScript,
|
* bitjs/archive: Decompressing files (unzip, unrar, untar) in JavaScript, implemented as Web
|
||||||
implemented as Web Workers where supported, and allowing progressive
|
Workers where supported, and allowing progressive unarchiving while streaming.
|
||||||
unarchiving while streaming.
|
* bitjs/codecs: Get the codec info of media containers in a ISO RFC6381 MIME type string.
|
||||||
* bitjs/codecs: Get the codec info of media containers in a ISO RFC6381
|
|
||||||
MIME type string
|
|
||||||
* bitjs/file: Detect the type of file from its binary signature.
|
* bitjs/file: Detect the type of file from its binary signature.
|
||||||
* bitjs/image: Parsing GIF, JPEG, PNG. Conversion of WebP to PNG or JPEG.
|
* bitjs/image: Parsing GIF, JPEG, PNG. Conversion of WebP to PNG or JPEG.
|
||||||
* bitjs/io: Low-level classes for interpreting binary data (BitStream
|
* bitjs/io: Low-level classes for interpreting binary data (BitStream, ByteStream). For example,
|
||||||
ByteStream). For example, reading or peeking at N bits at a time.
|
reading or peeking at N bits at a time.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
|
|
@ -316,3 +316,22 @@ export function getUnarchiver(ab, options = {}) {
|
||||||
}
|
}
|
||||||
return unarchiver;
|
return unarchiver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// import * as fs from 'node:fs';
|
||||||
|
// async function main() {
|
||||||
|
// const nodeBuf = fs.readFileSync(`./action-1.cbz`);
|
||||||
|
// const ab = nodeBuf.buffer.slice(nodeBuf.byteOffset, nodeBuf.byteOffset + nodeBuf.length);
|
||||||
|
// const then = Date.now();
|
||||||
|
// const zipper = new Unzipper(ab, {debug: true});
|
||||||
|
// zipper.addEventListener('extract', evt => {
|
||||||
|
// const f = evt.unarchivedFile;
|
||||||
|
// fs.writeFileSync(f.filename, Buffer.from(f.fileData));
|
||||||
|
// });
|
||||||
|
// zipper.addEventListener('finish', evt => {
|
||||||
|
// console.dir(evt);
|
||||||
|
// console.log(`Took ${(Date.now() - then)}ms`);
|
||||||
|
// });
|
||||||
|
// await zipper.start();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// main();
|
||||||
|
|
|
@ -178,7 +178,7 @@ class ZipLocalFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine what kind of compressed data we have and decompress
|
// determine what kind of compressed data we have and decompress
|
||||||
unzip() {
|
async unzip() {
|
||||||
if (!this.fileData) {
|
if (!this.fileData) {
|
||||||
err('unzip() called on a file with out compressed file data');
|
err('unzip() called on a file with out compressed file data');
|
||||||
}
|
}
|
||||||
|
@ -196,7 +196,7 @@ class ZipLocalFile {
|
||||||
if (logToConsole) {
|
if (logToConsole) {
|
||||||
info(`ZIP v2.0, DEFLATE: ${this.filename} (${this.compressedSize} bytes)`);
|
info(`ZIP v2.0, DEFLATE: ${this.filename} (${this.compressedSize} bytes)`);
|
||||||
}
|
}
|
||||||
this.fileData = inflate(this.fileData, this.uncompressedSize);
|
this.fileData = await inflate(this.fileData, this.uncompressedSize);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
err(`UNSUPPORTED VERSION/FORMAT: ZIP v${this.version}, ` +
|
err(`UNSUPPORTED VERSION/FORMAT: ZIP v${this.version}, ` +
|
||||||
|
@ -483,9 +483,18 @@ function inflateBlockData(bstream, hcLiteralTable, hcDistanceTable, buffer) {
|
||||||
* Compression method 8. Deflate: http://tools.ietf.org/html/rfc1951
|
* Compression method 8. Deflate: http://tools.ietf.org/html/rfc1951
|
||||||
* @param {Uint8Array} compressedData A Uint8Array of the compressed file data.
|
* @param {Uint8Array} compressedData A Uint8Array of the compressed file data.
|
||||||
* @param {number} numDecompressedBytes
|
* @param {number} numDecompressedBytes
|
||||||
* @returns {Uint8Array} The decompressed array.
|
* @returns {Promise<Uint8Array>} The decompressed array.
|
||||||
*/
|
*/
|
||||||
function inflate(compressedData, numDecompressedBytes) {
|
async function inflate(compressedData, numDecompressedBytes) {
|
||||||
|
// Try to use native implementation of DEFLATE if it exists.
|
||||||
|
try {
|
||||||
|
const blob = new Blob([compressedData.buffer]);
|
||||||
|
const decompressedStream = blob.stream().pipeThrough(new DecompressionStream('deflate-raw'));
|
||||||
|
return new Uint8Array(await new Response(decompressedStream).arrayBuffer());
|
||||||
|
} catch (err) {
|
||||||
|
// Fall through to non-native implementation of DEFLATE.
|
||||||
|
}
|
||||||
|
|
||||||
// Bit stream representing the compressed data.
|
// Bit stream representing the compressed data.
|
||||||
/** @type {BitStream} */
|
/** @type {BitStream} */
|
||||||
const bstream = new BitStream(compressedData.buffer,
|
const bstream = new BitStream(compressedData.buffer,
|
||||||
|
@ -596,7 +605,7 @@ function inflate(compressedData, numDecompressedBytes) {
|
||||||
return buffer.data;
|
return buffer.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
function archiveUnzip() {
|
async function archiveUnzip() {
|
||||||
let bstream = bytestream.tee();
|
let bstream = bytestream.tee();
|
||||||
|
|
||||||
// loop until we don't see any more local files or we find a data descriptor.
|
// loop until we don't see any more local files or we find a data descriptor.
|
||||||
|
@ -619,7 +628,7 @@ function archiveUnzip() {
|
||||||
currentBytesUnarchivedInFile = 0;
|
currentBytesUnarchivedInFile = 0;
|
||||||
|
|
||||||
// Actually do the unzipping.
|
// Actually do the unzipping.
|
||||||
oneLocalFile.unzip();
|
await oneLocalFile.unzip();
|
||||||
|
|
||||||
if (oneLocalFile.fileData != null) {
|
if (oneLocalFile.fileData != null) {
|
||||||
hostPort.postMessage({ type: 'extract', unarchivedFile: oneLocalFile }, [oneLocalFile.fileData.buffer]);
|
hostPort.postMessage({ type: 'extract', unarchivedFile: oneLocalFile }, [oneLocalFile.fileData.buffer]);
|
||||||
|
@ -724,7 +733,7 @@ function archiveUnzip() {
|
||||||
|
|
||||||
// event.data.file has the first ArrayBuffer.
|
// event.data.file has the first ArrayBuffer.
|
||||||
// event.data.bytes has all subsequent ArrayBuffers.
|
// event.data.bytes has all subsequent ArrayBuffers.
|
||||||
const onmessage = function (event) {
|
const onmessage = async function (event) {
|
||||||
const bytes = event.data.file || event.data.bytes;
|
const bytes = event.data.file || event.data.bytes;
|
||||||
logToConsole = !!event.data.logToConsole;
|
logToConsole = !!event.data.logToConsole;
|
||||||
|
|
||||||
|
@ -755,7 +764,7 @@ const onmessage = function (event) {
|
||||||
if (unarchiveState === UnarchiveState.UNARCHIVING ||
|
if (unarchiveState === UnarchiveState.UNARCHIVING ||
|
||||||
unarchiveState === UnarchiveState.WAITING) {
|
unarchiveState === UnarchiveState.WAITING) {
|
||||||
try {
|
try {
|
||||||
archiveUnzip();
|
await archiveUnzip();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (typeof e === 'string' && e.startsWith('Error! Overflowed')) {
|
if (typeof e === 'string' && e.startsWith('Error! Overflowed')) {
|
||||||
// Overrun the buffer.
|
// Overrun the buffer.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue