mirror of
https://github.com/codedread/bitjs
synced 2025-10-03 09:39:16 +02:00
Some minor API updates.
This commit is contained in:
parent
24b1603968
commit
cc59935e72
7 changed files with 139 additions and 10 deletions
|
@ -2,6 +2,7 @@
|
||||||
* archive.js
|
* archive.js
|
||||||
*
|
*
|
||||||
* Provides base functionality for unarchiving.
|
* Provides base functionality for unarchiving.
|
||||||
|
* DEPRECATED: Use decompress.js instead.
|
||||||
*
|
*
|
||||||
* Licensed under the MIT License
|
* Licensed under the MIT License
|
||||||
*
|
*
|
||||||
|
@ -12,7 +13,9 @@ import { UnarchiveAppendEvent, UnarchiveErrorEvent, UnarchiveEvent, UnarchiveEve
|
||||||
UnarchiveExtractEvent, UnarchiveFinishEvent, UnarchiveInfoEvent,
|
UnarchiveExtractEvent, UnarchiveFinishEvent, UnarchiveInfoEvent,
|
||||||
UnarchiveProgressEvent, UnarchiveStartEvent, Unarchiver,
|
UnarchiveProgressEvent, UnarchiveStartEvent, Unarchiver,
|
||||||
UnrarrerInternal, UntarrerInternal, UnzipperInternal,
|
UnrarrerInternal, UntarrerInternal, UnzipperInternal,
|
||||||
getUnarchiverInternal } from './archive-internal.js';
|
getUnarchiverInternal } from './decompress-internal.js';
|
||||||
|
|
||||||
|
console.warn(`Stop using archive.js and use decompress.js instead. This module will be removed.`);
|
||||||
|
|
||||||
export {
|
export {
|
||||||
UnarchiveAppendEvent,
|
UnarchiveAppendEvent,
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
|
|
||||||
import { ByteBuffer } from '../io/bytebuffer.js';
|
|
||||||
|
|
||||||
// NOTE: THIS IS A VERY HACKY WORK-IN-PROGRESS! THE API IS NOT FROZEN! USE AT YOUR OWN RISK!
|
// NOTE: THIS IS A VERY HACKY WORK-IN-PROGRESS! THE API IS NOT FROZEN! USE AT YOUR OWN RISK!
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10,9 +8,35 @@ import { ByteBuffer } from '../io/bytebuffer.js';
|
||||||
* @property {ArrayBuffer} fileData The bytes of the file.
|
* @property {ArrayBuffer} fileData The bytes of the file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @readonly
|
||||||
|
* @enum {number}
|
||||||
|
*/
|
||||||
|
export const ZipCompressionMethod = {
|
||||||
|
STORE: 0, // Default.
|
||||||
|
// DEFLATE: 8,
|
||||||
|
};
|
||||||
|
|
||||||
|
// export const DeflateCompressionMethod = {
|
||||||
|
// NO_COMPRESSION: 0,
|
||||||
|
// COMPRESSION_FIXED_HUFFMAN: 1,
|
||||||
|
// COMPRESSION_DYNAMIC_HUFFMAN: 2,
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data elements are packed into bytes in order of increasing bit number within the byte,
|
||||||
|
i.e., starting with the least-significant bit of the byte.
|
||||||
|
* Data elements other than Huffman codes are packed starting with the least-significant bit of the
|
||||||
|
data element.
|
||||||
|
* Huffman codes are packed starting with the most-significant bit of the code.
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef CompressorOptions
|
* @typedef CompressorOptions
|
||||||
* @property {string} pathToBitJS A string indicating where the BitJS files are located.
|
* @property {string} pathToBitJS A string indicating where the BitJS files are located.
|
||||||
|
* @property {ZipCompressionMethod} zipCompressionMethod
|
||||||
|
* @property {DeflateCompressionMethod=} deflateCompressionMethod Only present if
|
||||||
|
* zipCompressionMethod is set to DEFLATE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,6 +54,7 @@ export const CompressStatus = {
|
||||||
/**
|
/**
|
||||||
* A thing that zips files.
|
* A thing that zips files.
|
||||||
* NOTE: THIS IS A VERY HACKY WORK-IN-PROGRESS! THE API IS NOT FROZEN! USE AT YOUR OWN RISK!
|
* NOTE: THIS IS A VERY HACKY WORK-IN-PROGRESS! THE API IS NOT FROZEN! USE AT YOUR OWN RISK!
|
||||||
|
* TODO: Make a streaming / event-driven API.
|
||||||
*/
|
*/
|
||||||
export class Zipper {
|
export class Zipper {
|
||||||
/**
|
/**
|
||||||
|
@ -43,6 +68,12 @@ export class Zipper {
|
||||||
*/
|
*/
|
||||||
this.pathToBitJS = options.pathToBitJS || '/';
|
this.pathToBitJS = options.pathToBitJS || '/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {ZipCompressionMethod}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
this.zipCompressionMethod = options.zipCompressionMethod || ZipCompressionMethod.STORE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private web worker initialized during start().
|
* Private web worker initialized during start().
|
||||||
* @type {Worker}
|
* @type {Worker}
|
||||||
|
@ -80,9 +111,13 @@ export class Zipper {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Send in a set of files to be compressed. Set isLastFile to true if no more files are to added
|
||||||
|
* at some future state. The Promise will not resolve until isLastFile is set to true either in
|
||||||
|
* this method or in appendFiles().
|
||||||
* @param {FileInfo[]} files
|
* @param {FileInfo[]} files
|
||||||
* @param {boolean} isLastFile
|
* @param {boolean} isLastFile
|
||||||
* @returns {Promise<Uint8Array>} A Promise that contains the entire zipped archive.
|
* @returns {Promise<Uint8Array>} A Promise that will contain the entire zipped archive as an array
|
||||||
|
* of bytes.
|
||||||
*/
|
*/
|
||||||
start(files, isLastFile) {
|
start(files, isLastFile) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
|
@ -207,11 +207,15 @@ export class UnarchiveExtractEvent extends UnarchiveEvent {
|
||||||
*/
|
*/
|
||||||
this.pathToBitJS_ = options.pathToBitJS || '/';
|
this.pathToBitJS_ = options.pathToBitJS || '/';
|
||||||
|
|
||||||
/** @orivate {boolean} */
|
/**
|
||||||
|
* @orivate
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
this.debugMode_ = !!(options.debug);
|
this.debugMode_ = !!(options.debug);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A map from event type to an array of listeners.
|
* A map from event type to an array of listeners.
|
||||||
|
* @private
|
||||||
* @type {Map.<string, Array>}
|
* @type {Map.<string, Array>}
|
||||||
*/
|
*/
|
||||||
this.listeners_ = {};
|
this.listeners_ = {};
|
||||||
|
@ -221,8 +225,8 @@ export class UnarchiveExtractEvent extends UnarchiveEvent {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private web worker initialized during start().
|
* Private web worker initialized during start().
|
||||||
* @type {Worker}
|
|
||||||
* @private
|
* @private
|
||||||
|
* @type {Worker}
|
||||||
*/
|
*/
|
||||||
this.worker_ = null;
|
this.worker_ = null;
|
||||||
}
|
}
|
84
archive/decompress.js
Normal file
84
archive/decompress.js
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
/**
|
||||||
|
* decompress.js
|
||||||
|
*
|
||||||
|
* Provides base functionality for unarchiving/decompression.
|
||||||
|
*
|
||||||
|
* Licensed under the MIT License
|
||||||
|
*
|
||||||
|
* Copyright(c) 2021 Google Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { UnarchiveAppendEvent, UnarchiveErrorEvent, UnarchiveEvent, UnarchiveEventType,
|
||||||
|
UnarchiveExtractEvent, UnarchiveFinishEvent, UnarchiveInfoEvent,
|
||||||
|
UnarchiveProgressEvent, UnarchiveStartEvent, Unarchiver,
|
||||||
|
UnrarrerInternal, UntarrerInternal, UnzipperInternal,
|
||||||
|
getUnarchiverInternal } from './decompress-internal.js';
|
||||||
|
|
||||||
|
export {
|
||||||
|
UnarchiveAppendEvent,
|
||||||
|
UnarchiveErrorEvent,
|
||||||
|
UnarchiveEvent,
|
||||||
|
UnarchiveEventType,
|
||||||
|
UnarchiveExtractEvent,
|
||||||
|
UnarchiveFinishEvent,
|
||||||
|
UnarchiveInfoEvent,
|
||||||
|
UnarchiveProgressEvent,
|
||||||
|
UnarchiveStartEvent,
|
||||||
|
Unarchiver,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All extracted files returned by an Unarchiver will implement
|
||||||
|
* the following interface:
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef UnarchivedFile
|
||||||
|
* @property {string} filename
|
||||||
|
* @property {Uint8Array} fileData
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The goal is to make this testable - send getUnarchiver() an array buffer of
|
||||||
|
* an archive, call start on the unarchiver, expect the returned result.
|
||||||
|
*
|
||||||
|
* Problem: It relies on Web Workers, and that won't work in a nodejs context.
|
||||||
|
* Solution: Make archive.js very thin, have it feed web-specific things into
|
||||||
|
* an internal module that is isomorphic JavaScript.
|
||||||
|
*
|
||||||
|
* TODO:
|
||||||
|
* - write unit tests for archive-internal.js that use the nodejs Worker
|
||||||
|
* equivalent.
|
||||||
|
* - maybe use @pgriess/node-webworker or @audreyt/node-webworker-threads or
|
||||||
|
* just node's worker_threads ?
|
||||||
|
*/
|
||||||
|
|
||||||
|
const createWorkerFn = (scriptFilename) => new Worker(scriptFilename);
|
||||||
|
|
||||||
|
// Thin wrappers of compressors for clients who want to construct a specific
|
||||||
|
// unarchiver themselves rather than use getUnarchiver().
|
||||||
|
export class Unzipper extends UnzipperInternal {
|
||||||
|
constructor(ab, options) { super(ab, createWorkerFn, options); }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Unrarrer extends UnrarrerInternal {
|
||||||
|
constructor(ab, options) { super(ab, createWorkerFn, options); }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Untarrer extends UntarrerInternal {
|
||||||
|
constructor(ab, options) { super(ab, createWorkerFn, options); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory method that creates an unarchiver based on the byte signature found
|
||||||
|
* in the arrayBuffer.
|
||||||
|
* @param {ArrayBuffer} ab The ArrayBuffer to unarchive. Note that this ArrayBuffer
|
||||||
|
* must not be referenced after calling this method, as the ArrayBuffer is marked
|
||||||
|
* as Transferable and sent to a Worker thread once start() is called.
|
||||||
|
* @param {Object|string} options An optional object of options, or a string
|
||||||
|
* representing where the path to the unarchiver script files.
|
||||||
|
* @return {Unarchiver}
|
||||||
|
*/
|
||||||
|
export function getUnarchiver(ab, options = {}) {
|
||||||
|
return getUnarchiverInternal(ab, createWorkerFn, options);
|
||||||
|
}
|
|
@ -493,7 +493,7 @@ function inflate(compressedData, numDecompressedBytes) {
|
||||||
// Bit stream representing the compressed data.
|
// Bit stream representing the compressed data.
|
||||||
/** @type {bitjs.io.BitStream} */
|
/** @type {bitjs.io.BitStream} */
|
||||||
const bstream = new bitjs.io.BitStream(compressedData.buffer,
|
const bstream = new bitjs.io.BitStream(compressedData.buffer,
|
||||||
false /* rtl */,
|
false /* mtl */,
|
||||||
compressedData.byteOffset,
|
compressedData.byteOffset,
|
||||||
compressedData.byteLength);
|
compressedData.byteLength);
|
||||||
/** @type {bitjs.io.ByteBuffer} */
|
/** @type {bitjs.io.ByteBuffer} */
|
||||||
|
|
|
@ -2,4 +2,4 @@
|
||||||
|
|
||||||
1. Create a zip or rar file with just one file inside it.
|
1. Create a zip or rar file with just one file inside it.
|
||||||
2. Use test-uploader.html and choose the archived file and the unarchived file.
|
2. Use test-uploader.html and choose the archived file and the unarchived file.
|
||||||
3. Paste that jSON output into a test json file.
|
3. Paste that JSON output into a test json file.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
import { Zipper } from '../archive/compress.js';
|
import { Zipper, ZipCompressionMethod } from '../archive/compress.js';
|
||||||
|
|
||||||
const result = document.querySelector('#result');
|
const result = document.querySelector('#result');
|
||||||
const fileInputEl = document.querySelector('#zip-tester');
|
const fileInputEl = document.querySelector('#zip-tester');
|
||||||
|
@ -36,7 +36,10 @@ async function getFiles(fileChangeEvt) {
|
||||||
|
|
||||||
result.innerHTML = `Loaded files`;
|
result.innerHTML = `Loaded files`;
|
||||||
|
|
||||||
const zipper = new Zipper({ pathToBitJS: '../' });
|
const zipper = new Zipper({
|
||||||
|
pathToBitJS: '../',
|
||||||
|
zipCompressionMethod: ZipCompressionMethod.DEFLATE,
|
||||||
|
});
|
||||||
byteArray = await zipper.start(fileInfos, true);
|
byteArray = await zipper.start(fileInfos, true);
|
||||||
result.innerHTML = `Zipping done`;
|
result.innerHTML = `Zipping done`;
|
||||||
saveButtonEl.style.display = '';
|
saveButtonEl.style.display = '';
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue