You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

608 lines
16 KiB

4 years ago
  1. 'use strict';
  2. var Buffer = require('buffer').Buffer;
  3. var Transform = require('stream').Transform;
  4. var binding = require('./binding');
  5. var util = require('util');
  6. var assert = require('assert').ok;
  7. var kMaxLength = require('buffer').kMaxLength;
  8. var kRangeErrorMessage = 'Cannot create final Buffer. It would be larger ' + 'than 0x' + kMaxLength.toString(16) + ' bytes';
  9. // zlib doesn't provide these, so kludge them in following the same
  10. // const naming scheme zlib uses.
  11. binding.Z_MIN_WINDOWBITS = 8;
  12. binding.Z_MAX_WINDOWBITS = 15;
  13. binding.Z_DEFAULT_WINDOWBITS = 15;
  14. // fewer than 64 bytes per chunk is stupid.
  15. // technically it could work with as few as 8, but even 64 bytes
  16. // is absurdly low. Usually a MB or more is best.
  17. binding.Z_MIN_CHUNK = 64;
  18. binding.Z_MAX_CHUNK = Infinity;
  19. binding.Z_DEFAULT_CHUNK = 16 * 1024;
  20. binding.Z_MIN_MEMLEVEL = 1;
  21. binding.Z_MAX_MEMLEVEL = 9;
  22. binding.Z_DEFAULT_MEMLEVEL = 8;
  23. binding.Z_MIN_LEVEL = -1;
  24. binding.Z_MAX_LEVEL = 9;
  25. binding.Z_DEFAULT_LEVEL = binding.Z_DEFAULT_COMPRESSION;
  26. // expose all the zlib constants
  27. var bkeys = Object.keys(binding);
  28. for (var bk = 0; bk < bkeys.length; bk++) {
  29. var bkey = bkeys[bk];
  30. if (bkey.match(/^Z/)) {
  31. Object.defineProperty(exports, bkey, {
  32. enumerable: true, value: binding[bkey], writable: false
  33. });
  34. }
  35. }
  36. // translation table for return codes.
  37. var codes = {
  38. Z_OK: binding.Z_OK,
  39. Z_STREAM_END: binding.Z_STREAM_END,
  40. Z_NEED_DICT: binding.Z_NEED_DICT,
  41. Z_ERRNO: binding.Z_ERRNO,
  42. Z_STREAM_ERROR: binding.Z_STREAM_ERROR,
  43. Z_DATA_ERROR: binding.Z_DATA_ERROR,
  44. Z_MEM_ERROR: binding.Z_MEM_ERROR,
  45. Z_BUF_ERROR: binding.Z_BUF_ERROR,
  46. Z_VERSION_ERROR: binding.Z_VERSION_ERROR
  47. };
  48. var ckeys = Object.keys(codes);
  49. for (var ck = 0; ck < ckeys.length; ck++) {
  50. var ckey = ckeys[ck];
  51. codes[codes[ckey]] = ckey;
  52. }
  53. Object.defineProperty(exports, 'codes', {
  54. enumerable: true, value: Object.freeze(codes), writable: false
  55. });
  56. exports.Deflate = Deflate;
  57. exports.Inflate = Inflate;
  58. exports.Gzip = Gzip;
  59. exports.Gunzip = Gunzip;
  60. exports.DeflateRaw = DeflateRaw;
  61. exports.InflateRaw = InflateRaw;
  62. exports.Unzip = Unzip;
  63. exports.createDeflate = function (o) {
  64. return new Deflate(o);
  65. };
  66. exports.createInflate = function (o) {
  67. return new Inflate(o);
  68. };
  69. exports.createDeflateRaw = function (o) {
  70. return new DeflateRaw(o);
  71. };
  72. exports.createInflateRaw = function (o) {
  73. return new InflateRaw(o);
  74. };
  75. exports.createGzip = function (o) {
  76. return new Gzip(o);
  77. };
  78. exports.createGunzip = function (o) {
  79. return new Gunzip(o);
  80. };
  81. exports.createUnzip = function (o) {
  82. return new Unzip(o);
  83. };
  84. // Convenience methods.
  85. // compress/decompress a string or buffer in one step.
  86. exports.deflate = function (buffer, opts, callback) {
  87. if (typeof opts === 'function') {
  88. callback = opts;
  89. opts = {};
  90. }
  91. return zlibBuffer(new Deflate(opts), buffer, callback);
  92. };
  93. exports.deflateSync = function (buffer, opts) {
  94. return zlibBufferSync(new Deflate(opts), buffer);
  95. };
  96. exports.gzip = function (buffer, opts, callback) {
  97. if (typeof opts === 'function') {
  98. callback = opts;
  99. opts = {};
  100. }
  101. return zlibBuffer(new Gzip(opts), buffer, callback);
  102. };
  103. exports.gzipSync = function (buffer, opts) {
  104. return zlibBufferSync(new Gzip(opts), buffer);
  105. };
  106. exports.deflateRaw = function (buffer, opts, callback) {
  107. if (typeof opts === 'function') {
  108. callback = opts;
  109. opts = {};
  110. }
  111. return zlibBuffer(new DeflateRaw(opts), buffer, callback);
  112. };
  113. exports.deflateRawSync = function (buffer, opts) {
  114. return zlibBufferSync(new DeflateRaw(opts), buffer);
  115. };
  116. exports.unzip = function (buffer, opts, callback) {
  117. if (typeof opts === 'function') {
  118. callback = opts;
  119. opts = {};
  120. }
  121. return zlibBuffer(new Unzip(opts), buffer, callback);
  122. };
  123. exports.unzipSync = function (buffer, opts) {
  124. return zlibBufferSync(new Unzip(opts), buffer);
  125. };
  126. exports.inflate = function (buffer, opts, callback) {
  127. if (typeof opts === 'function') {
  128. callback = opts;
  129. opts = {};
  130. }
  131. return zlibBuffer(new Inflate(opts), buffer, callback);
  132. };
  133. exports.inflateSync = function (buffer, opts) {
  134. return zlibBufferSync(new Inflate(opts), buffer);
  135. };
  136. exports.gunzip = function (buffer, opts, callback) {
  137. if (typeof opts === 'function') {
  138. callback = opts;
  139. opts = {};
  140. }
  141. return zlibBuffer(new Gunzip(opts), buffer, callback);
  142. };
  143. exports.gunzipSync = function (buffer, opts) {
  144. return zlibBufferSync(new Gunzip(opts), buffer);
  145. };
  146. exports.inflateRaw = function (buffer, opts, callback) {
  147. if (typeof opts === 'function') {
  148. callback = opts;
  149. opts = {};
  150. }
  151. return zlibBuffer(new InflateRaw(opts), buffer, callback);
  152. };
  153. exports.inflateRawSync = function (buffer, opts) {
  154. return zlibBufferSync(new InflateRaw(opts), buffer);
  155. };
  156. function zlibBuffer(engine, buffer, callback) {
  157. var buffers = [];
  158. var nread = 0;
  159. engine.on('error', onError);
  160. engine.on('end', onEnd);
  161. engine.end(buffer);
  162. flow();
  163. function flow() {
  164. var chunk;
  165. while (null !== (chunk = engine.read())) {
  166. buffers.push(chunk);
  167. nread += chunk.length;
  168. }
  169. engine.once('readable', flow);
  170. }
  171. function onError(err) {
  172. engine.removeListener('end', onEnd);
  173. engine.removeListener('readable', flow);
  174. callback(err);
  175. }
  176. function onEnd() {
  177. var buf;
  178. var err = null;
  179. if (nread >= kMaxLength) {
  180. err = new RangeError(kRangeErrorMessage);
  181. } else {
  182. buf = Buffer.concat(buffers, nread);
  183. }
  184. buffers = [];
  185. engine.close();
  186. callback(err, buf);
  187. }
  188. }
  189. function zlibBufferSync(engine, buffer) {
  190. if (typeof buffer === 'string') buffer = Buffer.from(buffer);
  191. if (!Buffer.isBuffer(buffer)) throw new TypeError('Not a string or buffer');
  192. var flushFlag = engine._finishFlushFlag;
  193. return engine._processChunk(buffer, flushFlag);
  194. }
  195. // generic zlib
  196. // minimal 2-byte header
  197. function Deflate(opts) {
  198. if (!(this instanceof Deflate)) return new Deflate(opts);
  199. Zlib.call(this, opts, binding.DEFLATE);
  200. }
  201. function Inflate(opts) {
  202. if (!(this instanceof Inflate)) return new Inflate(opts);
  203. Zlib.call(this, opts, binding.INFLATE);
  204. }
  205. // gzip - bigger header, same deflate compression
  206. function Gzip(opts) {
  207. if (!(this instanceof Gzip)) return new Gzip(opts);
  208. Zlib.call(this, opts, binding.GZIP);
  209. }
  210. function Gunzip(opts) {
  211. if (!(this instanceof Gunzip)) return new Gunzip(opts);
  212. Zlib.call(this, opts, binding.GUNZIP);
  213. }
  214. // raw - no header
  215. function DeflateRaw(opts) {
  216. if (!(this instanceof DeflateRaw)) return new DeflateRaw(opts);
  217. Zlib.call(this, opts, binding.DEFLATERAW);
  218. }
  219. function InflateRaw(opts) {
  220. if (!(this instanceof InflateRaw)) return new InflateRaw(opts);
  221. Zlib.call(this, opts, binding.INFLATERAW);
  222. }
  223. // auto-detect header.
  224. function Unzip(opts) {
  225. if (!(this instanceof Unzip)) return new Unzip(opts);
  226. Zlib.call(this, opts, binding.UNZIP);
  227. }
  228. function isValidFlushFlag(flag) {
  229. return flag === binding.Z_NO_FLUSH || flag === binding.Z_PARTIAL_FLUSH || flag === binding.Z_SYNC_FLUSH || flag === binding.Z_FULL_FLUSH || flag === binding.Z_FINISH || flag === binding.Z_BLOCK;
  230. }
  231. // the Zlib class they all inherit from
  232. // This thing manages the queue of requests, and returns
  233. // true or false if there is anything in the queue when
  234. // you call the .write() method.
  235. function Zlib(opts, mode) {
  236. var _this = this;
  237. this._opts = opts = opts || {};
  238. this._chunkSize = opts.chunkSize || exports.Z_DEFAULT_CHUNK;
  239. Transform.call(this, opts);
  240. if (opts.flush && !isValidFlushFlag(opts.flush)) {
  241. throw new Error('Invalid flush flag: ' + opts.flush);
  242. }
  243. if (opts.finishFlush && !isValidFlushFlag(opts.finishFlush)) {
  244. throw new Error('Invalid flush flag: ' + opts.finishFlush);
  245. }
  246. this._flushFlag = opts.flush || binding.Z_NO_FLUSH;
  247. this._finishFlushFlag = typeof opts.finishFlush !== 'undefined' ? opts.finishFlush : binding.Z_FINISH;
  248. if (opts.chunkSize) {
  249. if (opts.chunkSize < exports.Z_MIN_CHUNK || opts.chunkSize > exports.Z_MAX_CHUNK) {
  250. throw new Error('Invalid chunk size: ' + opts.chunkSize);
  251. }
  252. }
  253. if (opts.windowBits) {
  254. if (opts.windowBits < exports.Z_MIN_WINDOWBITS || opts.windowBits > exports.Z_MAX_WINDOWBITS) {
  255. throw new Error('Invalid windowBits: ' + opts.windowBits);
  256. }
  257. }
  258. if (opts.level) {
  259. if (opts.level < exports.Z_MIN_LEVEL || opts.level > exports.Z_MAX_LEVEL) {
  260. throw new Error('Invalid compression level: ' + opts.level);
  261. }
  262. }
  263. if (opts.memLevel) {
  264. if (opts.memLevel < exports.Z_MIN_MEMLEVEL || opts.memLevel > exports.Z_MAX_MEMLEVEL) {
  265. throw new Error('Invalid memLevel: ' + opts.memLevel);
  266. }
  267. }
  268. if (opts.strategy) {
  269. if (opts.strategy != exports.Z_FILTERED && opts.strategy != exports.Z_HUFFMAN_ONLY && opts.strategy != exports.Z_RLE && opts.strategy != exports.Z_FIXED && opts.strategy != exports.Z_DEFAULT_STRATEGY) {
  270. throw new Error('Invalid strategy: ' + opts.strategy);
  271. }
  272. }
  273. if (opts.dictionary) {
  274. if (!Buffer.isBuffer(opts.dictionary)) {
  275. throw new Error('Invalid dictionary: it should be a Buffer instance');
  276. }
  277. }
  278. this._handle = new binding.Zlib(mode);
  279. var self = this;
  280. this._hadError = false;
  281. this._handle.onerror = function (message, errno) {
  282. // there is no way to cleanly recover.
  283. // continuing only obscures problems.
  284. _close(self);
  285. self._hadError = true;
  286. var error = new Error(message);
  287. error.errno = errno;
  288. error.code = exports.codes[errno];
  289. self.emit('error', error);
  290. };
  291. var level = exports.Z_DEFAULT_COMPRESSION;
  292. if (typeof opts.level === 'number') level = opts.level;
  293. var strategy = exports.Z_DEFAULT_STRATEGY;
  294. if (typeof opts.strategy === 'number') strategy = opts.strategy;
  295. this._handle.init(opts.windowBits || exports.Z_DEFAULT_WINDOWBITS, level, opts.memLevel || exports.Z_DEFAULT_MEMLEVEL, strategy, opts.dictionary);
  296. this._buffer = Buffer.allocUnsafe(this._chunkSize);
  297. this._offset = 0;
  298. this._level = level;
  299. this._strategy = strategy;
  300. this.once('end', this.close);
  301. Object.defineProperty(this, '_closed', {
  302. get: function () {
  303. return !_this._handle;
  304. },
  305. configurable: true,
  306. enumerable: true
  307. });
  308. }
  309. util.inherits(Zlib, Transform);
  310. Zlib.prototype.params = function (level, strategy, callback) {
  311. if (level < exports.Z_MIN_LEVEL || level > exports.Z_MAX_LEVEL) {
  312. throw new RangeError('Invalid compression level: ' + level);
  313. }
  314. if (strategy != exports.Z_FILTERED && strategy != exports.Z_HUFFMAN_ONLY && strategy != exports.Z_RLE && strategy != exports.Z_FIXED && strategy != exports.Z_DEFAULT_STRATEGY) {
  315. throw new TypeError('Invalid strategy: ' + strategy);
  316. }
  317. if (this._level !== level || this._strategy !== strategy) {
  318. var self = this;
  319. this.flush(binding.Z_SYNC_FLUSH, function () {
  320. assert(self._handle, 'zlib binding closed');
  321. self._handle.params(level, strategy);
  322. if (!self._hadError) {
  323. self._level = level;
  324. self._strategy = strategy;
  325. if (callback) callback();
  326. }
  327. });
  328. } else {
  329. process.nextTick(callback);
  330. }
  331. };
  332. Zlib.prototype.reset = function () {
  333. assert(this._handle, 'zlib binding closed');
  334. return this._handle.reset();
  335. };
  336. // This is the _flush function called by the transform class,
  337. // internally, when the last chunk has been written.
  338. Zlib.prototype._flush = function (callback) {
  339. this._transform(Buffer.alloc(0), '', callback);
  340. };
  341. Zlib.prototype.flush = function (kind, callback) {
  342. var _this2 = this;
  343. var ws = this._writableState;
  344. if (typeof kind === 'function' || kind === undefined && !callback) {
  345. callback = kind;
  346. kind = binding.Z_FULL_FLUSH;
  347. }
  348. if (ws.ended) {
  349. if (callback) process.nextTick(callback);
  350. } else if (ws.ending) {
  351. if (callback) this.once('end', callback);
  352. } else if (ws.needDrain) {
  353. if (callback) {
  354. this.once('drain', function () {
  355. return _this2.flush(kind, callback);
  356. });
  357. }
  358. } else {
  359. this._flushFlag = kind;
  360. this.write(Buffer.alloc(0), '', callback);
  361. }
  362. };
  363. Zlib.prototype.close = function (callback) {
  364. _close(this, callback);
  365. process.nextTick(emitCloseNT, this);
  366. };
  367. function _close(engine, callback) {
  368. if (callback) process.nextTick(callback);
  369. // Caller may invoke .close after a zlib error (which will null _handle).
  370. if (!engine._handle) return;
  371. engine._handle.close();
  372. engine._handle = null;
  373. }
  374. function emitCloseNT(self) {
  375. self.emit('close');
  376. }
  377. Zlib.prototype._transform = function (chunk, encoding, cb) {
  378. var flushFlag;
  379. var ws = this._writableState;
  380. var ending = ws.ending || ws.ended;
  381. var last = ending && (!chunk || ws.length === chunk.length);
  382. if (chunk !== null && !Buffer.isBuffer(chunk)) return cb(new Error('invalid input'));
  383. if (!this._handle) return cb(new Error('zlib binding closed'));
  384. // If it's the last chunk, or a final flush, we use the Z_FINISH flush flag
  385. // (or whatever flag was provided using opts.finishFlush).
  386. // If it's explicitly flushing at some other time, then we use
  387. // Z_FULL_FLUSH. Otherwise, use Z_NO_FLUSH for maximum compression
  388. // goodness.
  389. if (last) flushFlag = this._finishFlushFlag;else {
  390. flushFlag = this._flushFlag;
  391. // once we've flushed the last of the queue, stop flushing and
  392. // go back to the normal behavior.
  393. if (chunk.length >= ws.length) {
  394. this._flushFlag = this._opts.flush || binding.Z_NO_FLUSH;
  395. }
  396. }
  397. this._processChunk(chunk, flushFlag, cb);
  398. };
  399. Zlib.prototype._processChunk = function (chunk, flushFlag, cb) {
  400. var availInBefore = chunk && chunk.length;
  401. var availOutBefore = this._chunkSize - this._offset;
  402. var inOff = 0;
  403. var self = this;
  404. var async = typeof cb === 'function';
  405. if (!async) {
  406. var buffers = [];
  407. var nread = 0;
  408. var error;
  409. this.on('error', function (er) {
  410. error = er;
  411. });
  412. assert(this._handle, 'zlib binding closed');
  413. do {
  414. var res = this._handle.writeSync(flushFlag, chunk, // in
  415. inOff, // in_off
  416. availInBefore, // in_len
  417. this._buffer, // out
  418. this._offset, //out_off
  419. availOutBefore); // out_len
  420. } while (!this._hadError && callback(res[0], res[1]));
  421. if (this._hadError) {
  422. throw error;
  423. }
  424. if (nread >= kMaxLength) {
  425. _close(this);
  426. throw new RangeError(kRangeErrorMessage);
  427. }
  428. var buf = Buffer.concat(buffers, nread);
  429. _close(this);
  430. return buf;
  431. }
  432. assert(this._handle, 'zlib binding closed');
  433. var req = this._handle.write(flushFlag, chunk, // in
  434. inOff, // in_off
  435. availInBefore, // in_len
  436. this._buffer, // out
  437. this._offset, //out_off
  438. availOutBefore); // out_len
  439. req.buffer = chunk;
  440. req.callback = callback;
  441. function callback(availInAfter, availOutAfter) {
  442. // When the callback is used in an async write, the callback's
  443. // context is the `req` object that was created. The req object
  444. // is === this._handle, and that's why it's important to null
  445. // out the values after they are done being used. `this._handle`
  446. // can stay in memory longer than the callback and buffer are needed.
  447. if (this) {
  448. this.buffer = null;
  449. this.callback = null;
  450. }
  451. if (self._hadError) return;
  452. var have = availOutBefore - availOutAfter;
  453. assert(have >= 0, 'have should not go down');
  454. if (have > 0) {
  455. var out = self._buffer.slice(self._offset, self._offset + have);
  456. self._offset += have;
  457. // serve some output to the consumer.
  458. if (async) {
  459. self.push(out);
  460. } else {
  461. buffers.push(out);
  462. nread += out.length;
  463. }
  464. }
  465. // exhausted the output buffer, or used all the input create a new one.
  466. if (availOutAfter === 0 || self._offset >= self._chunkSize) {
  467. availOutBefore = self._chunkSize;
  468. self._offset = 0;
  469. self._buffer = Buffer.allocUnsafe(self._chunkSize);
  470. }
  471. if (availOutAfter === 0) {
  472. // Not actually done. Need to reprocess.
  473. // Also, update the availInBefore to the availInAfter value,
  474. // so that if we have to hit it a third (fourth, etc.) time,
  475. // it'll have the correct byte counts.
  476. inOff += availInBefore - availInAfter;
  477. availInBefore = availInAfter;
  478. if (!async) return true;
  479. var newReq = self._handle.write(flushFlag, chunk, inOff, availInBefore, self._buffer, self._offset, self._chunkSize);
  480. newReq.callback = callback; // this same function
  481. newReq.buffer = chunk;
  482. return;
  483. }
  484. if (!async) return false;
  485. // finished with the chunk.
  486. cb();
  487. }
  488. };
  489. util.inherits(Deflate, Zlib);
  490. util.inherits(Inflate, Zlib);
  491. util.inherits(Gzip, Zlib);
  492. util.inherits(Gunzip, Zlib);
  493. util.inherits(DeflateRaw, Zlib);
  494. util.inherits(InflateRaw, Zlib);
  495. util.inherits(Unzip, Zlib);