|
|
|
|
@ -1,320 +1,421 @@
|
|
|
|
|
'use strict'
|
|
|
|
|
|
|
|
|
|
const assert = require('assert')
|
|
|
|
|
const Buffer = require('buffer').Buffer
|
|
|
|
|
const realZlib = require('zlib')
|
|
|
|
|
|
|
|
|
|
const constants = exports.constants = require('./constants.js')
|
|
|
|
|
const Minipass = require('minipass')
|
|
|
|
|
|
|
|
|
|
const OriginalBufferConcat = Buffer.concat
|
|
|
|
|
|
|
|
|
|
// 引入Node.js的内置断言模块,用于编写测试用例时进行各种断言检查,确保代码符合预期的行为
|
|
|
|
|
const assert = require('assert');
|
|
|
|
|
// 引入Node.js的Buffer模块,用于处理二进制数据,如创建、操作字节缓冲区等
|
|
|
|
|
const Buffer = require('buffer').Buffer;
|
|
|
|
|
// 引入Node.js的zlib模块,用于进行数据的压缩和解压缩操作
|
|
|
|
|
const realZlib = require('zlib');
|
|
|
|
|
|
|
|
|
|
// 引入自定义的常量模块(./constants.js),并将其赋值给当前模块的exports.constants,方便其他模块使用这些常量
|
|
|
|
|
const constants = exports.constants = require('./constants.js');
|
|
|
|
|
// 引入Minipass模块,Minipass可能是一个实现了流相关功能的基础类,用于构建自定义的流对象(此处为推测,具体功能依赖其自身实现)
|
|
|
|
|
const Minipass = require('minipass');
|
|
|
|
|
|
|
|
|
|
// 保存原始的Buffer.concat方法,后续代码中会对Buffer.concat进行临时修改,这里先保存以便恢复
|
|
|
|
|
const OriginalBufferConcat = Buffer.concat;
|
|
|
|
|
|
|
|
|
|
// 自定义的错误类ZlibError,继承自Error类,用于包装zlib相关操作出现的错误,提供更详细和统一的错误信息格式
|
|
|
|
|
class ZlibError extends Error {
|
|
|
|
|
constructor (err) {
|
|
|
|
|
super('zlib: ' + err.message)
|
|
|
|
|
this.code = err.code
|
|
|
|
|
this.errno = err.errno
|
|
|
|
|
// 调用父类(Error)的构造函数,传入格式化后的错误消息,消息前缀为 'zlib: ',后面跟上原始错误的消息内容
|
|
|
|
|
super('zlib: ' + err.message);
|
|
|
|
|
// 将原始错误的错误码赋值给当前错误对象的code属性,方便外部根据错误码判断具体错误类型
|
|
|
|
|
this.code = err.code;
|
|
|
|
|
// 将原始错误的系统错误号(errno)赋值给当前错误对象的errno属性,用于更底层的错误追踪和处理(如果适用)
|
|
|
|
|
this.errno = err.errno;
|
|
|
|
|
/* istanbul ignore if */
|
|
|
|
|
// 以下代码块在测试覆盖时可能会被忽略(通常是一些特殊情况或者难以触发的逻辑),
|
|
|
|
|
// 如果当前错误对象没有设置错误码(code属性为空),则将错误码默认设置为 'ZLIB_ERROR'
|
|
|
|
|
if (!this.code)
|
|
|
|
|
this.code = 'ZLIB_ERROR'
|
|
|
|
|
this.code = 'ZLIB_ERROR';
|
|
|
|
|
|
|
|
|
|
this.message = 'zlib: ' + err.message
|
|
|
|
|
Error.captureStackTrace(this, this.constructor)
|
|
|
|
|
// 再次设置错误消息,确保消息格式符合预期,这里与构造函数开头设置的消息内容一致,可能是为了代码的清晰性和一致性
|
|
|
|
|
this.message = 'zlib: ' + err.message;
|
|
|
|
|
// 捕获当前错误对象的堆栈信息,方便在调试时查看错误发生的调用栈情况,第二个参数指定了构造函数作为起始位置
|
|
|
|
|
Error.captureStackTrace(this, this.constructor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 重写name属性的访问器,返回自定义的错误名称 'ZlibError',用于更清晰地标识错误类型
|
|
|
|
|
get name () {
|
|
|
|
|
return 'ZlibError'
|
|
|
|
|
return 'ZlibError';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// the Zlib class they all inherit from
|
|
|
|
|
// This thing manages the queue of requests, and returns
|
|
|
|
|
// true or false if there is anything in the queue when
|
|
|
|
|
// you call the .write() method.
|
|
|
|
|
const _opts = Symbol('opts')
|
|
|
|
|
const _flushFlag = Symbol('flushFlag')
|
|
|
|
|
const _finishFlushFlag = Symbol('finishFlushFlag')
|
|
|
|
|
const _fullFlushFlag = Symbol('fullFlushFlag')
|
|
|
|
|
const _handle = Symbol('handle')
|
|
|
|
|
const _onError = Symbol('onError')
|
|
|
|
|
const _sawError = Symbol('sawError')
|
|
|
|
|
const _level = Symbol('level')
|
|
|
|
|
const _strategy = Symbol('strategy')
|
|
|
|
|
const _ended = Symbol('ended')
|
|
|
|
|
const _defaultFullFlush = Symbol('_defaultFullFlush')
|
|
|
|
|
|
|
|
|
|
// 以下定义了一系列Symbol类型的私有属性名,用于在ZlibBase类中标记一些内部使用的属性,
|
|
|
|
|
// 通过Symbol可以创建唯一的标识符,避免属性名冲突,实现一定程度的封装和数据隐藏
|
|
|
|
|
const _opts = Symbol('opts');
|
|
|
|
|
const _flushFlag = Symbol('flushFlag');
|
|
|
|
|
const _finishFlushFlag = Symbol('finishFlushFlag');
|
|
|
|
|
const _fullFlushFlag = Symbol('fullFlushFlag');
|
|
|
|
|
const _handle = Symbol('handle');
|
|
|
|
|
const _onError = Symbol('onError');
|
|
|
|
|
const _sawError = Symbol('sawError');
|
|
|
|
|
const _level = Symbol('level');
|
|
|
|
|
const _strategy = Symbol('strategy');
|
|
|
|
|
const _ended = Symbol('ended');
|
|
|
|
|
const _defaultFullFlush = Symbol('_defaultFullFlush');
|
|
|
|
|
|
|
|
|
|
// ZlibBase类,继承自Minipass类,作为其他与zlib相关的类的基类,用于管理压缩/解压操作的请求队列等功能
|
|
|
|
|
class ZlibBase extends Minipass {
|
|
|
|
|
constructor (opts, mode) {
|
|
|
|
|
if (!opts || typeof opts !== 'object')
|
|
|
|
|
throw new TypeError('invalid options for ZlibBase constructor')
|
|
|
|
|
|
|
|
|
|
super(opts)
|
|
|
|
|
this[_ended] = false
|
|
|
|
|
this[_opts] = opts
|
|
|
|
|
|
|
|
|
|
this[_flushFlag] = opts.flush
|
|
|
|
|
this[_finishFlushFlag] = opts.finishFlush
|
|
|
|
|
// this will throw if any options are invalid for the class selected
|
|
|
|
|
// 首先检查传入的opts参数,如果不存在或者不是对象类型,抛出TypeError异常,提示传入的ZlibBase构造函数参数无效
|
|
|
|
|
if (!opts || typeof opts!== 'object')
|
|
|
|
|
throw new TypeError('invalid options for ZlibBase constructor');
|
|
|
|
|
|
|
|
|
|
// 调用父类(Minipass)的构造函数,传入opts参数,完成父类的初始化操作
|
|
|
|
|
super(opts);
|
|
|
|
|
// 标记当前对象是否已经结束(初始化为false,表示尚未结束),通过私有属性 _ended 来记录
|
|
|
|
|
this[_ended] = false;
|
|
|
|
|
// 将传入的opts参数保存到私有属性 _opts 中,方便后续在类中使用这些配置选项
|
|
|
|
|
this[_opts] = opts;
|
|
|
|
|
|
|
|
|
|
// 将opts中的flush属性值赋给私有属性 _flushFlag,可能用于控制数据的刷新方式(具体依赖zlib相关逻辑)
|
|
|
|
|
this[_flushFlag] = opts.flush;
|
|
|
|
|
// 将opts中的finishFlush属性值赋给私有属性 _finishFlushFlag,可能与结束时的刷新操作相关(同样依赖具体逻辑)
|
|
|
|
|
this[_finishFlushFlag] = opts.finishFlush;
|
|
|
|
|
|
|
|
|
|
// 尝试根据传入的mode创建对应的zlib实例(通过realZlib[mode],这里假设realZlib对象有根据不同模式创建实例的功能),
|
|
|
|
|
// 如果创建过程中出现错误,捕获异常并抛出一个经过包装的ZlibError错误对象,确保错误信息符合自定义的格式和处理逻辑
|
|
|
|
|
try {
|
|
|
|
|
this[_handle] = new realZlib[mode](opts)
|
|
|
|
|
this[_handle] = new realZlib[mode](opts);
|
|
|
|
|
} catch (er) {
|
|
|
|
|
// make sure that all errors get decorated properly
|
|
|
|
|
throw new ZlibError(er)
|
|
|
|
|
throw new ZlibError(er);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 定义一个内部的错误处理函数 _onError,用于处理zlib实例触发的错误事件
|
|
|
|
|
this[_onError] = (err) => {
|
|
|
|
|
this[_sawError] = true
|
|
|
|
|
// there is no way to cleanly recover.
|
|
|
|
|
// continuing only obscures problems.
|
|
|
|
|
this.close()
|
|
|
|
|
this.emit('error', err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this[_handle].on('error', er => this[_onError](new ZlibError(er)))
|
|
|
|
|
this.once('end', () => this.close)
|
|
|
|
|
// 标记已经出现错误,通过私有属性 _sawError 记录,后续可以根据此标记进行相应的处理判断
|
|
|
|
|
this[_sawError] = true;
|
|
|
|
|
// 在出现错误的情况下,认为无法进行干净的恢复操作,直接关闭相关资源(调用close方法)
|
|
|
|
|
// 继续执行可能会掩盖问题,所以选择关闭并触发 'error' 事件向外传递错误信息
|
|
|
|
|
this.close();
|
|
|
|
|
this.emit('error', err);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 监听zlib实例的 'error' 事件,当触发时调用内部的 _onError 函数来处理错误,将原始错误包装为ZlibError类型后再处理
|
|
|
|
|
this[_handle].on('error', er => this[_onError](new ZlibError(er)));
|
|
|
|
|
// 监听当前对象(继承自Minipass,可能是流相关的结束事件)的 'end' 事件,当触发时调用close方法进行关闭相关操作
|
|
|
|
|
this.once('end', () => this.close);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// close方法,用于关闭与zlib相关的资源(可能是释放底层的句柄等操作)
|
|
|
|
|
close () {
|
|
|
|
|
// 如果存在zlib实例的句柄(_handle属性不为null),则调用其close方法进行关闭操作,
|
|
|
|
|
// 然后将 _handle 属性设置为null,表示已经关闭,最后触发 'close' 事件通知外部相关操作已完成
|
|
|
|
|
if (this[_handle]) {
|
|
|
|
|
this[_handle].close()
|
|
|
|
|
this[_handle] = null
|
|
|
|
|
this.emit('close')
|
|
|
|
|
this[_handle].close();
|
|
|
|
|
this[_handle] = null;
|
|
|
|
|
this.emit('close');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// reset方法,用于重置zlib相关的状态(前提是没有出现过错误,通过 _sawError 属性判断),
|
|
|
|
|
// 如果没有错误且存在zlib实例的句柄,调用句柄的reset方法进行重置操作(具体重置的内容依赖zlib底层实现)
|
|
|
|
|
reset () {
|
|
|
|
|
if (!this[_sawError]) {
|
|
|
|
|
assert(this[_handle], 'zlib binding closed')
|
|
|
|
|
return this[_handle].reset()
|
|
|
|
|
assert(this[_handle], 'zlib binding closed');
|
|
|
|
|
return this[_handle].reset();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// flush方法,用于执行数据的刷新操作,根据传入的参数或默认的刷新标志来决定刷新方式
|
|
|
|
|
flush (flushFlag) {
|
|
|
|
|
// 如果已经标记为结束状态(ended为真),则直接返回,不进行刷新操作
|
|
|
|
|
if (this.ended)
|
|
|
|
|
return
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (typeof flushFlag !== 'number')
|
|
|
|
|
flushFlag = this[_fullFlushFlag]
|
|
|
|
|
this.write(Object.assign(Buffer.alloc(0), { [_flushFlag]: flushFlag }))
|
|
|
|
|
// 如果传入的flushFlag参数不是数字类型,使用默认的完全刷新标志(_fullFlushFlag,具体值应在类的其他地方定义或初始化)
|
|
|
|
|
if (typeof flushFlag!== 'number')
|
|
|
|
|
flushFlag = this[_fullFlushFlag];
|
|
|
|
|
// 创建一个空的Buffer对象,并将刷新标志(_flushFlag)作为属性添加到该对象上,然后调用write方法将其写入流中进行刷新操作
|
|
|
|
|
this.write(Object.assign(Buffer.alloc(0), { [_flushFlag]: flushFlag }));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// end方法,用于标记流的结束操作,并进行一些相关的清理和刷新操作
|
|
|
|
|
end (chunk, encoding, cb) {
|
|
|
|
|
// 如果传入了数据chunk,先调用write方法将其写入流中(进行相应的编码转换等处理,后面的代码会实现)
|
|
|
|
|
if (chunk)
|
|
|
|
|
this.write(chunk, encoding)
|
|
|
|
|
this.flush(this[_finishFlushFlag])
|
|
|
|
|
this[_ended] = true
|
|
|
|
|
return super.end(null, null, cb)
|
|
|
|
|
this.write(chunk, encoding);
|
|
|
|
|
// 调用flush方法进行结束时的刷新操作,使用 _finishFlushFlag 作为刷新标志
|
|
|
|
|
this.flush(this[_finishFlushFlag]);
|
|
|
|
|
// 标记当前对象已经结束(通过私有属性 _ended 设置为true)
|
|
|
|
|
this[_ended] = true;
|
|
|
|
|
// 调用父类(Minipass)的end方法,传入null表示没有额外的数据要写入,结束流操作,并传递回调函数cb(如果有的话)
|
|
|
|
|
return super.end(null, null, cb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ended属性访问器,用于获取当前对象是否已经结束的状态,返回存储在 _ended 属性中的值
|
|
|
|
|
get ended () {
|
|
|
|
|
return this[_ended]
|
|
|
|
|
return this[_ended];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// write方法,用于向流中写入数据,涉及到对数据的处理、调用zlib实例进行压缩/解压操作以及将结果写入父类流等复杂逻辑
|
|
|
|
|
write (chunk, encoding, cb) {
|
|
|
|
|
// process the chunk using the sync process
|
|
|
|
|
// then super.write() all the outputted chunks
|
|
|
|
|
// 如果传入的第二个参数encoding是函数类型,将其作为回调函数cb,同时将encoding默认设置为 'utf8',
|
|
|
|
|
// 这是一种常见的参数处理方式,用于统一参数格式,方便后续对数据进行处理
|
|
|
|
|
if (typeof encoding === 'function')
|
|
|
|
|
cb = encoding, encoding = 'utf8'
|
|
|
|
|
cb = encoding, encoding = 'utf8';
|
|
|
|
|
|
|
|
|
|
if (typeof chunk === 'string')
|
|
|
|
|
chunk = Buffer.from(chunk, encoding)
|
|
|
|
|
// 如果传入的第一个参数chunk是字符串类型,将其转换为Buffer类型,使用指定的encoding进行编码转换
|
|
|
|
|
if (typeof chunk ==='string')
|
|
|
|
|
chunk = Buffer.from(chunk, encoding);
|
|
|
|
|
|
|
|
|
|
// 如果已经出现过错误(_sawError为真),直接返回,不再进行写入操作
|
|
|
|
|
if (this[_sawError])
|
|
|
|
|
return
|
|
|
|
|
assert(this[_handle], 'zlib binding closed')
|
|
|
|
|
|
|
|
|
|
// _processChunk tries to .close() the native handle after it's done, so we
|
|
|
|
|
// intercept that by temporarily making it a no-op.
|
|
|
|
|
const nativeHandle = this[_handle]._handle
|
|
|
|
|
const originalNativeClose = nativeHandle.close
|
|
|
|
|
nativeHandle.close = () => {}
|
|
|
|
|
const originalClose = this[_handle].close
|
|
|
|
|
this[_handle].close = () => {}
|
|
|
|
|
// It also calls `Buffer.concat()` at the end, which may be convenient
|
|
|
|
|
// for some, but which we are not interested in as it slows us down.
|
|
|
|
|
Buffer.concat = (args) => args
|
|
|
|
|
let result
|
|
|
|
|
return;
|
|
|
|
|
// 通过断言确保存在zlib实例的句柄,如果不存在则抛出异常,提示zlib绑定已关闭,无法进行写入操作
|
|
|
|
|
assert(this[_handle], 'zlib binding closed');
|
|
|
|
|
|
|
|
|
|
// 以下代码块对zlib实例的原生句柄(_handle._handle)进行一些临时操作,主要是拦截其close方法使其变为空操作(noop),
|
|
|
|
|
// 目的是避免在处理数据过程中意外关闭句柄,同时也保存了原始的close方法,方便后续恢复
|
|
|
|
|
const nativeHandle = this[_handle]._handle;
|
|
|
|
|
const originalNativeClose = nativeHandle.close;
|
|
|
|
|
nativeHandle.close = () => {};
|
|
|
|
|
const originalClose = this[_handle].close;
|
|
|
|
|
this[_handle].close = () => {};
|
|
|
|
|
|
|
|
|
|
// 临时修改Buffer.concat方法为一个简单返回参数的函数(这里修改的目的可能是为了优化性能或者避免一些不必要的操作,
|
|
|
|
|
// 因为原有的Buffer.concat可能会有一些额外的逻辑,如合并缓冲区等,而此处不需要这些功能)
|
|
|
|
|
Buffer.concat = (args) => args;
|
|
|
|
|
|
|
|
|
|
let result;
|
|
|
|
|
try {
|
|
|
|
|
// 根据传入的chunk数据是否包含 _flushFlag 属性以及其值来确定刷新标志,如果没有则使用类中保存的 _flushFlag 属性值
|
|
|
|
|
const flushFlag = typeof chunk[_flushFlag] === 'number'
|
|
|
|
|
? chunk[_flushFlag] : this[_flushFlag]
|
|
|
|
|
result = this[_handle]._processChunk(chunk, flushFlag)
|
|
|
|
|
// if we don't throw, reset it back how it was
|
|
|
|
|
Buffer.concat = OriginalBufferConcat
|
|
|
|
|
? chunk[_flushFlag] : this[_flushFlag];
|
|
|
|
|
// 调用zlib实例的 _processChunk方法处理数据chunk,传入数据和刷新标志,获取处理结果(可能是经过压缩/解压后的缓冲区数据等)
|
|
|
|
|
result = this[_handle]._processChunk(chunk, flushFlag);
|
|
|
|
|
// 如果没有抛出异常,说明处理成功,将Buffer.concat方法恢复为原始的方法(之前保存的OriginalBufferConcat)
|
|
|
|
|
Buffer.concat = OriginalBufferConcat;
|
|
|
|
|
} catch (err) {
|
|
|
|
|
// or if we do, put Buffer.concat() back before we emit error
|
|
|
|
|
// Error events call into user code, which may call Buffer.concat()
|
|
|
|
|
Buffer.concat = OriginalBufferConcat
|
|
|
|
|
this[_onError](new ZlibError(err))
|
|
|
|
|
// 如果在处理过程中抛出异常,先将Buffer.concat方法恢复为原始的方法,
|
|
|
|
|
// 然后调用内部的 _onError 方法处理错误,将原始错误包装为ZlibError类型并触发 'error' 事件向外通知错误情况
|
|
|
|
|
// 之所以要先恢复Buffer.concat方法,是因为后续的错误处理可能会涉及到用户代码调用Buffer.concat方法,如果不恢复可能导致错误
|
|
|
|
|
Buffer.concat = OriginalBufferConcat;
|
|
|
|
|
this[_onError](new ZlibError(err));
|
|
|
|
|
} finally {
|
|
|
|
|
if (this[_handle]) {
|
|
|
|
|
// Core zlib resets `_handle` to null after attempting to close the
|
|
|
|
|
// native handle. Our no-op handler prevented actual closure, but we
|
|
|
|
|
// need to restore the `._handle` property.
|
|
|
|
|
this[_handle]._handle = nativeHandle
|
|
|
|
|
nativeHandle.close = originalNativeClose
|
|
|
|
|
this[_handle].close = originalClose
|
|
|
|
|
// `_processChunk()` adds an 'error' listener. If we don't remove it
|
|
|
|
|
// after each call, these handlers start piling up.
|
|
|
|
|
this[_handle].removeAllListeners('error')
|
|
|
|
|
// 在finally块中,确保无论是否出现异常,都要进行一些清理和恢复操作
|
|
|
|
|
// 将zlib实例的 _handle 属性重新指向原始的原生句柄(之前保存的nativeHandle),恢复原生句柄的close方法为原始的方法
|
|
|
|
|
this[_handle]._handle = nativeHandle;
|
|
|
|
|
nativeHandle.close = originalNativeClose;
|
|
|
|
|
this[_handle].close = originalClose;
|
|
|
|
|
// 移除zlib实例对 'error' 事件的所有监听器,因为 _processChunk方法每次调用可能会添加 'error' 监听器,
|
|
|
|
|
// 如果不及时移除,这些监听器会不断累积,导致意外的行为
|
|
|
|
|
this[_handle].removeAllListeners('error');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let writeReturn
|
|
|
|
|
let writeReturn;
|
|
|
|
|
// 如果有处理结果result,进行后续的写入操作
|
|
|
|
|
if (result) {
|
|
|
|
|
// 如果处理结果是数组且长度大于0,说明可能有多个缓冲区数据需要写入
|
|
|
|
|
// 先将第一个缓冲区(通常是zlib实例内部的输出缓冲区,可能会被复用,所以需要复制一份)通过父类的write方法写入流中,
|
|
|
|
|
// 然后遍历数组的其余元素,依次调用父类的write方法将数据写入流中
|
|
|
|
|
if (Array.isArray(result) && result.length > 0) {
|
|
|
|
|
// The first buffer is always `handle._outBuffer`, which would be
|
|
|
|
|
// re-used for later invocations; so, we always have to copy that one.
|
|
|
|
|
writeReturn = super.write(Buffer.from(result[0]))
|
|
|
|
|
writeReturn = super.write(Buffer.from(result[0]));
|
|
|
|
|
for (let i = 1; i < result.length; i++) {
|
|
|
|
|
writeReturn = super.write(result[i])
|
|
|
|
|
writeReturn = super.write(result[i]);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
writeReturn = super.write(Buffer.from(result))
|
|
|
|
|
// 如果结果不是数组或者数组长度为0,直接将结果(单个缓冲区数据)通过父类的write方法写入流中
|
|
|
|
|
writeReturn = super.write(Buffer.from(result));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果有回调函数cb,执行回调函数(通常用于通知写入操作完成等情况)
|
|
|
|
|
if (cb)
|
|
|
|
|
cb()
|
|
|
|
|
return writeReturn
|
|
|
|
|
cb();
|
|
|
|
|
// 返回写入操作的返回值(可能是父类write方法的返回值,具体含义依赖父类的实现逻辑)
|
|
|
|
|
return writeReturn;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Zlib类,继承自ZlibBase类,用于进一步定制基于zlib库的压缩/解压相关操作,添加特定的默认参数设置等功能
|
|
|
|
|
class Zlib extends ZlibBase {
|
|
|
|
|
constructor (opts, mode) {
|
|
|
|
|
opts = opts || {}
|
|
|
|
|
|
|
|
|
|
opts.flush = opts.flush || constants.Z_NO_FLUSH
|
|
|
|
|
opts.finishFlush = opts.finishFlush || constants.Z_FINISH
|
|
|
|
|
super(opts, mode)
|
|
|
|
|
|
|
|
|
|
this[_fullFlushFlag] = constants.Z_FULL_FLUSH
|
|
|
|
|
this[_level] = opts.level
|
|
|
|
|
this[_strategy] = opts.strategy
|
|
|
|
|
// 如果没有传入opts参数,则创建一个空对象作为默认值,确保后续对opts属性的访问不会出现问题
|
|
|
|
|
opts = opts || {};
|
|
|
|
|
|
|
|
|
|
// 如果opts中没有设置flush属性,将其默认设置为 constants.Z_NO_FLUSH(从之前引入的常量模块中获取,可能表示不进行刷新操作的常量值)
|
|
|
|
|
opts.flush = opts.flush || constants.Z_NO_FLUSH;
|
|
|
|
|
// 如果opts中没有设置finishFlush属性,将其默认设置为 constants.Z_FINISH(可能表示完成时的刷新操作相关常量值)
|
|
|
|
|
opts.finishFlush = opts.finishFlush || constants.Z_FINISH;
|
|
|
|
|
|
|
|
|
|
// 调用父类(ZlibBase)的构造函数,传入处理后的opts参数和mode参数,完成父类的初始化以及与zlib底层实例的创建等操作
|
|
|
|
|
super(opts, mode);
|
|
|
|
|
|
|
|
|
|
// 设置完全刷新标志(_fullFlushFlag)为 constants.Z_FULL_FLUSH(具体含义与zlib的刷新机制相关,可能是一种较为彻底的刷新方式对应的常量值)
|
|
|
|
|
this[_fullFlushFlag] = constants.Z_FULL_FLUSH;
|
|
|
|
|
// 将opts中的level属性值保存到私有属性 _level 中,可能用于记录当前压缩/解压操作的级别设置(具体依赖zlib相关逻辑)
|
|
|
|
|
this[_level] = opts.level;
|
|
|
|
|
// 将opts中的strategy属性值保存到私有属性 _strategy 中,可能用于记录当前采用的压缩/解压策略(同样依赖具体逻辑)
|
|
|
|
|
this[_strategy] = opts.strategy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// params方法,用于修改当前zlib实例的参数(如压缩级别、策略等),但需要满足一定条件并进行一些复杂的内部处理
|
|
|
|
|
params (level, strategy) {
|
|
|
|
|
// 如果已经出现过错误(_sawError为真),直接返回,不进行参数修改操作,可能是在出现错误后认为当前状态不适合修改参数
|
|
|
|
|
if (this[_sawError])
|
|
|
|
|
return
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// 如果不存在zlib实例的句柄(_handle为null),抛出一个错误,提示在绑定已关闭的情况下无法切换参数
|
|
|
|
|
if (!this[_handle])
|
|
|
|
|
throw new Error('cannot switch params when binding is closed')
|
|
|
|
|
throw new Error('cannot switch params when binding is closed');
|
|
|
|
|
|
|
|
|
|
// 以下代码块在测试覆盖时可能会被忽略(通常是一些难以触发或者不适合在常规测试中执行的逻辑),
|
|
|
|
|
// 如果当前zlib实例不支持params方法(即 _handle.params不存在),抛出一个错误,提示在当前实现中不支持此操作
|
|
|
|
|
// 这里可能是因为不同版本或者不同底层实现对参数修改的支持情况不一致导致的判断
|
|
|
|
|
// no way to test this without also not supporting params at all
|
|
|
|
|
/* istanbul ignore if */
|
|
|
|
|
if (!this[_handle].params)
|
|
|
|
|
throw new Error('not supported in this implementation')
|
|
|
|
|
|
|
|
|
|
if (this[_level] !== level || this[_strategy] !== strategy) {
|
|
|
|
|
this.flush(constants.Z_SYNC_FLUSH)
|
|
|
|
|
assert(this[_handle], 'zlib binding closed')
|
|
|
|
|
// .params() calls .flush(), but the latter is always async in the
|
|
|
|
|
// core zlib. We override .flush() temporarily to intercept that and
|
|
|
|
|
// flush synchronously.
|
|
|
|
|
const origFlush = this[_handle].flush
|
|
|
|
|
throw new Error('not supported in this implementation');
|
|
|
|
|
|
|
|
|
|
// 如果传入的新参数level或strategy与当前保存的参数(_level、_strategy)不一致,进行参数修改操作
|
|
|
|
|
if (this[_level]!== level || this[_strategy]!== strategy) {
|
|
|
|
|
// 先调用flush方法进行同步刷新操作,使用 constants.Z_SYNC_FLUSH 作为刷新标志,确保数据处于合适的状态以便修改参数
|
|
|
|
|
this.flush(constants.Z_SYNC_FLUSH);
|
|
|
|
|
// 通过断言确保存在zlib实例的句柄,如果不存在则抛出异常,提示zlib绑定已关闭,无法进行参数修改操作
|
|
|
|
|
assert(this[_handle], 'zlib binding closed');
|
|
|
|
|
|
|
|
|
|
// 以下代码是为了处理核心zlib库中.params() 方法调用.flush() 方法且后者是异步的情况,
|
|
|
|
|
// 在这里临时重写zlib实例的.flush() 方法,使其在内部调用当前类的flush方法(实现同步刷新)并执行传入的回调函数cb,
|
|
|
|
|
// 这样可以拦截并改变原本异步的刷新行为,使其符合当前参数修改时的同步需求
|
|
|
|
|
const origFlush = this[_handle].flush;
|
|
|
|
|
this[_handle].flush = (flushFlag, cb) => {
|
|
|
|
|
this.flush(flushFlag)
|
|
|
|
|
cb()
|
|
|
|
|
}
|
|
|
|
|
this.flush(flushFlag);
|
|
|
|
|
cb();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
this[_handle].params(level, strategy)
|
|
|
|
|
// 调用zlib实例的.params() 方法,传入新的参数level和strategy,实际执行参数修改操作(具体修改的内容依赖zlib底层实现)
|
|
|
|
|
this[_handle].params(level, strategy);
|
|
|
|
|
} finally {
|
|
|
|
|
this[_handle].flush = origFlush
|
|
|
|
|
// 在无论是否出现异常的情况下,都要将zlib实例的.flush() 方法恢复为原始的方法(之前保存的origFlush),确保后续操作不受影响
|
|
|
|
|
this[_handle].flush = origFlush;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* istanbul ignore else */
|
|
|
|
|
// 以下代码块在测试覆盖时可能会被默认忽略(可能是一些正常流程下必然会执行的逻辑),
|
|
|
|
|
// 如果zlib实例的句柄仍然存在(即没有在参数修改过程中出现意外关闭等情况),更新当前对象保存的参数(_level和 _strategy)为新传入的值
|
|
|
|
|
if (this[_handle]) {
|
|
|
|
|
this[_level] = level
|
|
|
|
|
this[_strategy] = strategy
|
|
|
|
|
this[_level] = level;
|
|
|
|
|
this[_strategy] = strategy;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// minimal 2-byte header
|
|
|
|
|
// Deflate类,继承自Zlib类,代表使用deflate压缩算法的相关操作,构造函数中传入opts参数并调用父类(Zlib)的构造函数,指定模式为 'Deflate'
|
|
|
|
|
// 它可能会在创建实例时根据Zlib类以及更上层的ZlibBase类的逻辑,初始化与deflate算法相关的配置和底层zlib实例等内容
|
|
|
|
|
class Deflate extends Zlib {
|
|
|
|
|
constructor (opts) {
|
|
|
|
|
super(opts, 'Deflate')
|
|
|
|
|
super(opts, 'Deflate');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Inflate类,继承自Zlib类,代表使用inflate解压算法的相关操作,构造函数中传入opts参数并调用父类(Zlib)的构造函数,指定模式为 'Inflate'
|
|
|
|
|
// 用于初始化与inflate算法相关的配置和底层zlib实例等,以便后续进行解压相关的操作
|
|
|
|
|
class Inflate extends Zlib {
|
|
|
|
|
constructor (opts) {
|
|
|
|
|
super(opts, 'Inflate')
|
|
|
|
|
super(opts, 'Inflate');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// gzip - bigger header, same deflate compression
|
|
|
|
|
// Gzip类,继承自Zlib类,用于处理gzip格式的压缩/解压相关操作,构造函数中传入opts参数并调用父类(Zlib)的构造函数,指定模式为 'Gzip'
|
|
|
|
|
// gzip是一种常见的带有特定头部格式的压缩文件格式,该类在初始化时会基于Zlib类的基础配置和对应模式来准备相关操作
|
|
|
|
|
class Gzip extends Zlib {
|
|
|
|
|
constructor (opts) {
|
|
|
|
|
super(opts, 'Gzip')
|
|
|
|
|
super(opts, 'Gzip');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Gunzip类,继承自Zlib类,主要用于对gzip格式文件进行解压操作,构造函数中传入opts参数并调用父类(Zlib)的构造函数,指定模式为 'Gunzip'
|
|
|
|
|
class Gunzip extends Zlib {
|
|
|
|
|
constructor (opts) {
|
|
|
|
|
super(opts, 'Gunzip')
|
|
|
|
|
super(opts, 'Gunzip');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// raw - no header
|
|
|
|
|
// DeflateRaw类,继承自Zlib类,用于使用原始的deflate算法进行操作(可能不包含像gzip等格式那样的额外头部信息),
|
|
|
|
|
// 构造函数传入opts参数并调用父类(Zlib)的构造函数,指定模式为 'DeflateRaw',以便初始化相关配置和底层实例
|
|
|
|
|
class DeflateRaw extends Zlib {
|
|
|
|
|
constructor (opts) {
|
|
|
|
|
super(opts, 'DeflateRaw')
|
|
|
|
|
super(opts, 'DeflateRaw');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// InflateRaw类,继承自Zlib类,用于使用原始的inflate算法进行解压操作(对应前面的DeflateRaw,去除格式头部等信息的解压情况),
|
|
|
|
|
// 构造函数传入opts参数并调用父类(Zlib)的构造函数,指定模式为 'InflateRaw',来初始化相应的配置和底层实例
|
|
|
|
|
class InflateRaw extends Zlib {
|
|
|
|
|
constructor (opts) {
|
|
|
|
|
super(opts, 'InflateRaw')
|
|
|
|
|
super(opts, 'InflateRaw');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// auto-detect header.
|
|
|
|
|
// Unzip类,继承自Zlib类,用于自动检测文件头部并进行相应的解压操作(可以处理多种格式,通过自动识别头部来确定解压方式),
|
|
|
|
|
// 构造函数传入opts参数并调用父类(Zlib)的构造函数,指定模式为 'Unzip',以此来初始化相关配置和底层实例
|
|
|
|
|
class Unzip extends Zlib {
|
|
|
|
|
constructor (opts) {
|
|
|
|
|
super(opts, 'Unzip')
|
|
|
|
|
super(opts, 'Unzip');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Brotli类,继承自ZlibBase类,用于基于Brotli压缩算法进行相关操作,和Zlib类类似,不过是针对Brotli算法的特定处理
|
|
|
|
|
class Brotli extends ZlibBase {
|
|
|
|
|
constructor (opts, mode) {
|
|
|
|
|
opts = opts || {}
|
|
|
|
|
opts = opts || {};
|
|
|
|
|
|
|
|
|
|
opts.flush = opts.flush || constants.BROTLI_OPERATION_PROCESS
|
|
|
|
|
opts.finishFlush = opts.finishFlush || constants.BROTLI_OPERATION_FINISH
|
|
|
|
|
// 如果opts中没有设置flush属性,将其默认设置为 constants.BROTLI_OPERATION_PROCESS(与Brotli算法的操作类型相关的常量,可能表示常规处理阶段的刷新方式)
|
|
|
|
|
opts.flush = opts.flush || constants.BROTLI_OPERATION_PROCESS;
|
|
|
|
|
// 如果opts中没有设置finishFlush属性,将其默认设置为 constants.BROTLI_OPERATION_FINISH(可能表示Brotli算法完成操作时的刷新方式相关常量值)
|
|
|
|
|
opts.finishFlush = opts.finishFlush || constants.BROTLI_OPERATION_FINISH;
|
|
|
|
|
|
|
|
|
|
super(opts, mode)
|
|
|
|
|
// 调用父类(ZlibBase)的构造函数,传入处理后的opts参数和mode参数,完成父类的初始化以及与Brotli相关的底层实例创建等操作
|
|
|
|
|
super(opts, mode);
|
|
|
|
|
|
|
|
|
|
this[_fullFlushFlag] = constants.BROTLI_OPERATION_FLUSH
|
|
|
|
|
// 设置完全刷新标志(_fullFlushFlag)为 constants.BROTLI_OPERATION_FLUSH(与Brotli算法的刷新操作类型相关的常量值)
|
|
|
|
|
this[_fullFlushFlag] = constants.BROTLI_OPERATION_FLUSH;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// BrotliCompress类,继承自Brotli类,专门用于使用Brotli算法进行压缩操作,构造函数传入opts参数并调用父类(Brotli)的构造函数,指定模式为 'BrotliCompress',
|
|
|
|
|
// 以此来初始化与Brotli压缩相关的配置和底层实例等内容
|
|
|
|
|
class BrotliCompress extends Brotli {
|
|
|
|
|
constructor (opts) {
|
|
|
|
|
super(opts, 'BrotliCompress')
|
|
|
|
|
super(opts, 'BrotliCompress');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// BrotliDecompress类,继承自Brotli类,专门用于使用Brotli算法进行解压操作,构造函数传入opts参数并调用父类(Brotli)的构造函数,指定模式为 'BrotliDecompress',
|
|
|
|
|
// 用于初始化与Brotli解压相关的配置和底层实例等,以便后续进行解压相关的操作
|
|
|
|
|
class BrotliDecompress extends Brotli {
|
|
|
|
|
constructor (opts) {
|
|
|
|
|
super(opts, 'BrotliDecompress')
|
|
|
|
|
super(opts, 'BrotliDecompress');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
exports.Deflate = Deflate
|
|
|
|
|
exports.Inflate = Inflate
|
|
|
|
|
exports.Gzip = Gzip
|
|
|
|
|
exports.Gunzip = Gunzip
|
|
|
|
|
exports.DeflateRaw = DeflateRaw
|
|
|
|
|
exports.InflateRaw = InflateRaw
|
|
|
|
|
exports.Unzip = Unzip
|
|
|
|
|
// 将上述定义的各个类作为模块的导出内容,方便其他模块引入并使用这些类来进行相应的压缩、解压等操作
|
|
|
|
|
exports.Deflate = Deflate;
|
|
|
|
|
exports.Inflate = Inflate;
|
|
|
|
|
exports.Gzip = Gzip;
|
|
|
|
|
exports.Gunzip = Gunzip;
|
|
|
|
|
exports.DeflateRaw = DeflateRaw;
|
|
|
|
|
exports.InflateRaw = InflateRaw;
|
|
|
|
|
exports.Unzip = Unzip;
|
|
|
|
|
|
|
|
|
|
/* istanbul ignore else */
|
|
|
|
|
// 以下代码块在测试覆盖时可能会被默认忽略(可能是根据不同Node.js版本的兼容性判断等情况),
|
|
|
|
|
// 如果Node.js的 realZlib 模块中存在 BrotliCompress 函数(即支持Brotli压缩算法),则将 BrotliCompress 和 BrotliDecompress 类作为模块导出内容,
|
|
|
|
|
// 否则创建一个在构造函数中抛出错误的类作为它们的导出内容,提示在当前版本的Node.js中不支持Brotli算法
|
|
|
|
|
if (typeof realZlib.BrotliCompress === 'function') {
|
|
|
|
|
exports.BrotliCompress = BrotliCompress
|
|
|
|
|
exports.BrotliDecompress = BrotliDecompress
|
|
|
|
|
exports.BrotliCompress = BrotliCompress;
|
|
|
|
|
exports.BrotliDecompress = BrotliDecompress;
|
|
|
|
|
} else {
|
|
|
|
|
exports.BrotliCompress = exports.BrotliDecompress = class {
|
|
|
|
|
constructor () {
|
|
|
|
|
throw new Error('Brotli is not supported in this version of Node.js')
|
|
|
|
|
throw new Error('Brotli is not supported in this version of Node.js');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|