Skip to content

Commit

Permalink
zlib: Add support for info: true option
Browse files Browse the repository at this point in the history
  • Loading branch information
npaun committed Sep 11, 2024
1 parent 57d205c commit 6f7deda
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 123 deletions.
195 changes: 118 additions & 77 deletions src/node/internal/internal_zlib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@
// Copyright Joyent and Node contributors. All rights reserved. MIT license.

import {
ZlibMode,
default as zlibUtil,
type ZlibOptions,
type CompressCallback,
type InternalCompressCallback,
type BrotliOptions,
} from 'node-internal:zlib';
import { Buffer } from 'node-internal:internal_buffer';
import { validateUint32 } from 'node-internal:validators';
import { ERR_INVALID_ARG_TYPE } from 'node-internal:internal_errors';
import { Zlib, Brotli } from 'node-internal:internal_zlib_base';
import { Zlib, Brotli, type ZlibBase } from 'node-internal:internal_zlib_base';

type ZlibResult = Buffer | { buffer: Buffer; engine: ZlibBase };
type CompressCallback = (err: Error | null, result?: ZlibResult) => void;

const {
CONST_DEFLATE,
Expand All @@ -35,71 +37,93 @@ export function crc32(
return zlibUtil.crc32(data, value);
}

function zlibSyncImpl(
data: ArrayBufferView | string,
options: ZlibOptions,
mode: ZlibMode
): ZlibResult {
const buffer = Buffer.from(zlibUtil.zlibSync(data, options, mode));

if (options.info) {
return { buffer, engine: new CLASS_BY_MODE[mode](options) };
} else {
return buffer;
}
}

export function inflateSync(
data: ArrayBufferView | string,
options: ZlibOptions = {}
): Buffer {
return Buffer.from(zlibUtil.zlibSync(data, options, zlibUtil.CONST_INFLATE));
): ZlibResult {
return zlibSyncImpl(data, options, CONST_INFLATE);
}

export function deflateSync(
data: ArrayBufferView | string,
options: ZlibOptions = {}
): Buffer {
return Buffer.from(zlibUtil.zlibSync(data, options, zlibUtil.CONST_DEFLATE));
): ZlibResult {
return zlibSyncImpl(data, options, CONST_DEFLATE);
}

export function gunzipSync(
data: ArrayBufferView | string,
options: ZlibOptions = {}
): Buffer {
return Buffer.from(zlibUtil.zlibSync(data, options, zlibUtil.CONST_GUNZIP));
): ZlibResult {
return zlibSyncImpl(data, options, CONST_GUNZIP);
}

export function gzipSync(
data: ArrayBufferView | string,
options: ZlibOptions = {}
): Buffer {
return Buffer.from(zlibUtil.zlibSync(data, options, zlibUtil.CONST_GZIP));
): ZlibResult {
return zlibSyncImpl(data, options, CONST_GZIP);
}

export function inflateRawSync(
data: ArrayBufferView | string,
options: ZlibOptions = {}
): Buffer {
return Buffer.from(
zlibUtil.zlibSync(data, options, zlibUtil.CONST_INFLATERAW)
);
): ZlibResult {
return zlibSyncImpl(data, options, CONST_INFLATERAW);
}

export function deflateRawSync(
data: ArrayBufferView | string,
options: ZlibOptions = {}
): Buffer {
return Buffer.from(
zlibUtil.zlibSync(data, options, zlibUtil.CONST_DEFLATERAW)
);
): ZlibResult {
return zlibSyncImpl(data, options, CONST_DEFLATERAW);
}

export function unzipSync(
data: ArrayBufferView | string,
options: ZlibOptions = {}
): Buffer {
return Buffer.from(zlibUtil.zlibSync(data, options, zlibUtil.CONST_UNZIP));
): ZlibResult {
return zlibSyncImpl(data, options, CONST_UNZIP);
}

export function brotliDecompressSync(
data: ArrayBufferView | string,
options: BrotliOptions = {}
): Buffer {
return Buffer.from(zlibUtil.brotliDecompressSync(data, options));
): ZlibResult {
const buffer = Buffer.from(zlibUtil.brotliDecompressSync(data, options));

if (options.info) {
return { buffer, engine: new BrotliDecompress(options) };
} else {
return buffer;
}
}

export function brotliCompressSync(
data: ArrayBufferView | string,
options: BrotliOptions = {}
): Buffer {
return Buffer.from(zlibUtil.brotliCompressSync(data, options));
): ZlibResult {
const buffer = Buffer.from(zlibUtil.brotliCompressSync(data, options));

if (options.info) {
return { buffer, engine: new BrotliCompress(options) };
} else {
return buffer;
}
}

function normalizeArgs(
Expand All @@ -115,110 +139,88 @@ function normalizeArgs(
throw new ERR_INVALID_ARG_TYPE('callback', 'Function', callbackOrUndefined);
}

function wrapCallback(callback: CompressCallback): InternalCompressCallback {
return (res: Error | ArrayBuffer) => {
function zlibImpl(
mode: ZlibMode,
data: ArrayBufferView | string,
optionsOrCallback: ZlibOptions | CompressCallback,
callbackOrUndefined?: CompressCallback
): void {
const [options, callback] = normalizeArgs(
optionsOrCallback,
callbackOrUndefined
);

zlibUtil.zlib(data, options, mode, (res) => {
queueMicrotask(() => {
if (res instanceof Error) {
callback(res);
} else {
callback(null, Buffer.from(res));
const buffer = Buffer.from(res);
callback(
null,
options.info
? { buffer, engine: new CLASS_BY_MODE[mode](options) }
: buffer
);
}
});
};
});
}

export function inflate(
data: ArrayBufferView | string,
optionsOrCallback: ZlibOptions | CompressCallback,
callbackOrUndefined?: CompressCallback
): void {
const [options, callback] = normalizeArgs(
optionsOrCallback,
callbackOrUndefined
);
zlibUtil.zlib(data, options, zlibUtil.CONST_INFLATE, wrapCallback(callback));
zlibImpl(CONST_INFLATE, data, optionsOrCallback, callbackOrUndefined);
}

export function unzip(
data: ArrayBufferView | string,
optionsOrCallback: ZlibOptions | CompressCallback,
callbackOrUndefined?: CompressCallback
): void {
const [options, callback] = normalizeArgs(
optionsOrCallback,
callbackOrUndefined
);
zlibUtil.zlib(data, options, zlibUtil.CONST_UNZIP, wrapCallback(callback));
zlibImpl(CONST_UNZIP, data, optionsOrCallback, callbackOrUndefined);
}

export function inflateRaw(
data: ArrayBufferView | string,
optionsOrCallback: ZlibOptions | CompressCallback,
callbackOrUndefined?: CompressCallback
): void {
const [options, callback] = normalizeArgs(
optionsOrCallback,
callbackOrUndefined
);
zlibUtil.zlib(
data,
options,
zlibUtil.CONST_INFLATERAW,
wrapCallback(callback)
);
zlibImpl(CONST_INFLATERAW, data, optionsOrCallback, callbackOrUndefined);
}

export function gunzip(
data: ArrayBufferView | string,
optionsOrCallback: ZlibOptions | CompressCallback,
callbackOrUndefined?: CompressCallback
): void {
const [options, callback] = normalizeArgs(
optionsOrCallback,
callbackOrUndefined
);
zlibUtil.zlib(data, options, zlibUtil.CONST_GUNZIP, wrapCallback(callback));
zlibImpl(CONST_GUNZIP, data, optionsOrCallback, callbackOrUndefined);
}

export function deflate(
data: ArrayBufferView | string,
optionsOrCallback: ZlibOptions | CompressCallback,
callbackOrUndefined?: CompressCallback
): void {
const [options, callback] = normalizeArgs(
optionsOrCallback,
callbackOrUndefined
);
zlibUtil.zlib(data, options, zlibUtil.CONST_DEFLATE, wrapCallback(callback));
zlibImpl(CONST_DEFLATE, data, optionsOrCallback, callbackOrUndefined);
}

export function deflateRaw(
data: ArrayBufferView | string,
optionsOrCallback: ZlibOptions | CompressCallback,
callbackOrUndefined?: CompressCallback
): void {
const [options, callback] = normalizeArgs(
optionsOrCallback,
callbackOrUndefined
);
zlibUtil.zlib(
data,
options,
zlibUtil.CONST_DEFLATERAW,
wrapCallback(callback)
);
zlibImpl(CONST_DEFLATERAW, data, optionsOrCallback, callbackOrUndefined);
}

export function gzip(
data: ArrayBufferView | string,
optionsOrCallback: ZlibOptions | CompressCallback,
callbackOrUndefined?: CompressCallback
): void {
const [options, callback] = normalizeArgs(
optionsOrCallback,
callbackOrUndefined
);
zlibUtil.zlib(data, options, zlibUtil.CONST_GZIP, wrapCallback(callback));
zlibImpl(CONST_GZIP, data, optionsOrCallback, callbackOrUndefined);
}

export function brotliDecompress(
Expand All @@ -230,7 +232,22 @@ export function brotliDecompress(
optionsOrCallback,
callbackOrUndefined
);
zlibUtil.brotliDecompress(data, options, wrapCallback(callback));

zlibUtil.brotliDecompress(data, options, (res) => {
queueMicrotask(() => {
if (res instanceof Error) {
callback(res);
} else {
const buffer = Buffer.from(res);
callback(
null,
options.info
? { engine: new BrotliDecompress(options), buffer }
: buffer
);
}
});
});
}

export function brotliCompress(
Expand All @@ -242,9 +259,23 @@ export function brotliCompress(
optionsOrCallback,
callbackOrUndefined
);
zlibUtil.brotliCompress(data, options, wrapCallback(callback));
}

zlibUtil.brotliCompress(data, options, (res) => {
queueMicrotask(() => {
if (res instanceof Error) {
callback(res);
} else {
const buffer = Buffer.from(res);
callback(
null,
options.info
? { engine: new BrotliCompress(options), buffer }
: buffer
);
}
});
});
}
export class Gzip extends Zlib {
public constructor(options: ZlibOptions) {
super(options, CONST_GZIP);
Expand Down Expand Up @@ -302,6 +333,16 @@ export class BrotliDecompress extends Brotli {
}
}

const CLASS_BY_MODE = {
[ZlibMode.DEFLATE]: Deflate,
[ZlibMode.INFLATE]: Inflate,
[ZlibMode.DEFLATERAW]: DeflateRaw,
[ZlibMode.INFLATERAW]: InflateRaw,
[ZlibMode.GZIP]: Gzip,
[ZlibMode.GUNZIP]: Gunzip,
[ZlibMode.UNZIP]: Unzip,
};

export function createGzip(options: ZlibOptions): Gzip {
return new Gzip(options);
}
Expand Down
22 changes: 15 additions & 7 deletions src/node/internal/zlib.d.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import { owner_symbol, type Zlib } from 'node-internal:internal_zlib_base';

export function crc32(data: ArrayBufferView, value: number): number;

export type CompressCallback = (
err: Error | null,
buffer?: ArrayBuffer
) => void;
export type InternalCompressCallback = (res: Error | ArrayBuffer) => void;
type InternalCompressCallback = (res: Error | ArrayBuffer) => void;

export function crc32(data: ArrayBufferView, value: number): number;
export function crc32(data: ArrayBufferView | string, value: number): number;

export function zlibSync(
data: ArrayBufferView | string,
options: ZlibOptions,
Expand Down Expand Up @@ -178,6 +174,8 @@ export interface BrotliOptions {
}
| undefined;
maxOutputLength?: number | undefined;
// Not specified in NodeJS docs but the tests expect it
info?: boolean | undefined;
}

type ErrorHandler = (errno: number, code: string, message: string) => void;
Expand Down Expand Up @@ -250,3 +248,13 @@ export class BrotliEncoder extends CompressionStream {
): boolean;
public params(): void;
}

export const enum ZlibMode {
DEFLATE = 1,
INFLATE = 2,
GZIP = 3,
GUNZIP = 4,
DEFLATERAW = 5,
INFLATERAW = 6,
UNZIP = 7,
}
Loading

0 comments on commit 6f7deda

Please sign in to comment.