Skip to content

Commit

Permalink
Merge pull request #488 from BlackAsLight/master
Browse files Browse the repository at this point in the history
Added ZipCompressionStream & ZipDecompressionStream
  • Loading branch information
gildas-lormeau authored Feb 24, 2024
2 parents 58c13f1 + 6e4b9ec commit 4149806
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 20 deletions.
128 changes: 121 additions & 7 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ declare class SyncCodec {
}

/**
* Represents an intance used to compress data.
* Represents an instance used to compress data.
*/
declare class ZipDeflate extends SyncCodec {
/**
Expand Down Expand Up @@ -599,7 +599,7 @@ export class SplitDataWriter implements Initializable, WritableWriter {
/**
* Creates the {@link SplitDataWriter} instance
*
* @param writerGenerator A generator of Writer isntances.
* @param writerGenerator A generator of Writer instances.
* @param maxSize The maximum size of the data written into {@link Writer} instances (default: 4GB).
*/
constructor(
Expand All @@ -616,6 +616,40 @@ export class SplitDataWriter implements Initializable, WritableWriter {
*/
export class Uint8ArrayWriter extends Writer<Uint8Array> {}

/**
* Represents an instance used to create an unzipped stream.
*
* @example
* This example will take a zip file, decompress it and then recompress each file in it, saving it to disk.
* ```
* for await (const entry of (await fetch(urlToZippedFile)).body.pipeThrough(new ZipWriterStream()))
* if (entry.readable) {
* console.log(entry.filename)
* entry.readable
* .pipeThrough(ZipReaderStream().transform(entry.filename))
* .pipeTo((await Deno.create(entry.filename + '.zip')).writable)
* }
* ```
*/
export class ZipReaderStream<T> {
/**
* Creates the stream.
*
* @param options The options.
*/
constructor (options?: ZipReaderConstructorOptions);

/**
* The readable stream.
*/
readable: ReadableStream<Omit<Entry, 'getData'> & { readable?: ReadableStream<Uint8Array>; }>;

/**
* The writable stream.
*/
writable: WritableStream<T>;
}

/**
* Represents an instance used to read a zip file.
*
Expand Down Expand Up @@ -688,7 +722,7 @@ export class ZipReader<Type> {
* Returns a generator used to iterate on all the entries in the zip file
*
* @param options The options.
* @returns An asynchrounous generator of {@link Entry} instances.
* @returns An asynchronous generator of {@link Entry} instances.
*/
getEntriesGenerator(
options?: ZipReaderGetEntriesOptions,
Expand Down Expand Up @@ -947,6 +981,86 @@ interface EntryGetDataOptions
interface EntryGetDataCheckPasswordOptions
extends EntryGetDataOptions, ZipReaderCheckPasswordOptions {}

/**
* Represents an instance used to create a zipped stream.
*
* @example
* This example creates a zipped file called numbers.txt.zip containing the numbers 0 - 1000 each on their own line.
* ```
* const readable = ReadableStream.from((function* () {
* for (let i = 0; i < 1000; ++i)
* yield i + '\n'
* })())
*
* readable
* .pipeThrough(new ZipWriterStream().transform('numbers.txt'))
* .pipeTo((await Deno.create('numbers.txt.zip')).writable)
* ```
*
* @example
* This example creates a zipped file called Archive.zip containing two files called numbers.txt and letters.txt
* ```
* const readable1 = ReadableStream.from((function* () {
* for (let i = 0; i < 1000; ++i)
* yield i + '\n'
* })())
* const readable2 = ReadableStream.from((function* () {
* const letters = 'abcdefghijklmnopqrstuvwxyz'.split('')
* while (letters.length)
* yield letters.shift() + '\n'
* })())
*
* const zipper = new ZipWriterStream()
* zipper.readable.pipeTo((await Deno.create('Archive.zip')).writable)
* readable1.pipeTo(zipper.writable('numbers.txt'))
* readable2.pipeTo(zipper.writable('letters.txt'))
* zipper.close()
* ```
*/
export class ZipWriterStream {
/**
* Creates the stream.
*
* @param options The options.
*/
constructor (options?: ZipWriterConstructorOptions);

/**
* The readable stream.
*/
readable: ReadableStream<Uint8Array>;

/**
* The ZipWriter property.
*/
zipWriter: ZipWriter<unknown>

/**
* Returns an object containing a readable and writable property for the .pipeThrough method
*
* @param path The name of the stream when unzipped.
* @returns An object containing readable and writable properties
*/
transform<T>(path: string): { readable: ReadableStream<T>, writable: WritableStream<T>; };

/**
* Returns a WritableStream for the .pipeTo method
*
* @param path The directory path of where the stream should exist in the zipped stream.
* @returns A WritableStream.
*/
writable<T>(path: string): WritableStream<T>;

/**
* Writes the entries directory, writes the global comment, and returns the content of the zipped file.
*
* @param comment The global comment of the zip file.
* @param options The options.
* @returns The content of the zip file.
*/
close(comment?: Uint8Array, options?: ZipWriterCloseOptions): Promise<unknown>;
}

/**
* Represents an instance used to create a zip file.
*
Expand Down Expand Up @@ -1324,7 +1438,7 @@ declare class ZipEntry {
/**
* Set the name of the entry
*
* @param name The new name of the netry.
* @param name The new name of the entry.
*/
rename(name: string): void;
}
Expand Down Expand Up @@ -1487,7 +1601,7 @@ export class ZipDirectoryEntry extends ZipEntry {
options?: ZipWriterAddDataOptions,
): ZipFileEntry<string, string>;
/**
* Adds aentry entry with content provided as a `Blob` instance
* Adds a entry entry with content provided as a `Blob` instance
*
* @param name The relative filename of the entry.
* @param blob The `Blob` instance.
Expand All @@ -1500,7 +1614,7 @@ export class ZipDirectoryEntry extends ZipEntry {
options?: ZipWriterAddDataOptions,
): ZipFileEntry<Blob, Blob>;
/**
* Adds aentry entry with content provided as a Data URI `string` encoded in Base64
* Adds a entry entry with content provided as a Data URI `string` encoded in Base64
*
* @param name The relative filename of the entry.
* @param dataURI The Data URI `string` encoded in Base64.
Expand Down Expand Up @@ -1539,7 +1653,7 @@ export class ZipDirectoryEntry extends ZipEntry {
options?: HttpOptions & ZipWriterAddDataOptions,
): ZipFileEntry<string, void>;
/**
* Adds aentry entry with content provided via a `ReadableStream` instance
* Adds a entry entry with content provided via a `ReadableStream` instance
*
* @param name The relative filename of the entry.
* @param readable The `ReadableStream` instance.
Expand Down
8 changes: 5 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
3. The names of the authors may not be used to endorse or promote products
Expand Down Expand Up @@ -42,6 +42,8 @@ export {
initShimAsyncCodec,
ZipReader,
ZipWriter,
ZipReaderStream,
ZipWriterStream,
Reader,
Writer,
TextReader,
Expand Down Expand Up @@ -83,4 +85,4 @@ export {
ERR_SPLIT_ZIP_FILE,
ERR_ITERATOR_COMPLETED_TOO_SOON
} from "./lib/zip-fs.js";
export { getMimeType, terminateWorkers };
export { getMimeType, terminateWorkers };
38 changes: 34 additions & 4 deletions lib/core/zip-reader.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
3. The names of the authors may not be used to endorse or promote products
Expand Down Expand Up @@ -209,7 +209,7 @@ class ZipReader {
}
if (directoryDataOffset >= reader.size) {
prependedDataLength = reader.size - directoryDataOffset - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
directoryDataOffset = reader.size - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
directoryDataOffset = reader.size - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
}
if (expectedLastDiskNumber != lastDiskNumber) {
throw new Error(ERR_SPLIT_ZIP_FILE);
Expand Down Expand Up @@ -326,8 +326,38 @@ class ZipReader {
}
}

class ZipReaderStream {
readable;
writable;
constructor (options = {}) {
const { readable, writable } = new TransformStream();
const gen = new ZipReader(readable, options).getEntriesGenerator();
this.readable = new ReadableStream({
async pull(controller) {
const { done, value } = await gen.next();
if (done)
return controller.close();
const chunk = {
...value,
readable: (function () {
const { readable, writable } = new TransformStream();
if (value.getData) {
value.getData(writable);
return readable;
}
})()
};
delete chunk.getData;
controller.enqueue(chunk);
}
});
this.writable = writable;
}
}

export {
ZipReader,
ZipReaderStream,
ERR_BAD_FORMAT,
ERR_EOCDR_NOT_FOUND,
ERR_EOCDR_ZIP64_NOT_FOUND,
Expand Down Expand Up @@ -721,4 +751,4 @@ function setUint32(view, offset, value) {

function getDataView(array) {
return new DataView(array.buffer);
}
}
35 changes: 32 additions & 3 deletions lib/core/zip-writer.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
3. The names of the authors may not be used to endorse or promote products
Expand Down Expand Up @@ -176,8 +176,37 @@ class ZipWriter {
}
}

class ZipWriterStream {
readable;
zipWriter;
constructor (options = {}) {
const { readable, writable } = new TransformStream();
this.readable = readable;
this.zipWriter = new ZipWriter(writable, options);
}

transform(path) {
const { readable, writable } = new TransformStream({
flush: () => { this.zipWriter.close(); }
});
this.zipWriter.add(path, readable);
return { readable: this.readable, writable };
}

writable(path) {
const { readable, writable } = new TransformStream();
this.zipWriter.add(path, readable);
return writable;
}

close(comment = undefined, options = {}) {
return this.zipWriter.close(comment, options);
}
}

export {
ZipWriter,
ZipWriterStream,
ERR_DUPLICATED_NAME,
ERR_INVALID_COMMENT,
ERR_INVALID_ENTRY_NAME,
Expand Down Expand Up @@ -1148,4 +1177,4 @@ function getLength(...arrayLikes) {
let result = 0;
arrayLikes.forEach(arrayLike => arrayLike && (result += arrayLike.length));
return result;
}
}
6 changes: 3 additions & 3 deletions lib/zip-fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
3. The names of the authors may not be used to endorse or promote products
Expand Down Expand Up @@ -50,4 +50,4 @@ export {
getMimeType,
initShimAsyncCodec,
terminateWorkers
};
};

0 comments on commit 4149806

Please sign in to comment.