zlib.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635
  1. // Copyright Joyent, Inc. and other Node contributors.
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a
  4. // copy of this software and associated documentation files (the
  5. // "Software"), to deal in the Software without restriction, including
  6. // without limitation the rights to use, copy, modify, merge, publish,
  7. // distribute, sublicense, and/or sell copies of the Software, and to permit
  8. // persons to whom the Software is furnished to do so, subject to the
  9. // following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included
  12. // in all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  15. // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  16. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
  17. // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  18. // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  19. // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  20. // USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. import {Transform} from 'stream';
  22. import * as _binding from './zlib-lib/binding';
  23. import {inherits} from 'util';
  24. function assert (a, msg) {
  25. if (!a) {
  26. throw new Error(msg);
  27. }
  28. }
  29. var binding = {};
  30. Object.keys(_binding).forEach(function (key) {
  31. binding[key] = _binding[key];
  32. });
  33. // zlib doesn't provide these, so kludge them in following the same
  34. // const naming scheme zlib uses.
  35. binding.Z_MIN_WINDOWBITS = 8;
  36. binding.Z_MAX_WINDOWBITS = 15;
  37. binding.Z_DEFAULT_WINDOWBITS = 15;
  38. // fewer than 64 bytes per chunk is stupid.
  39. // technically it could work with as few as 8, but even 64 bytes
  40. // is absurdly low. Usually a MB or more is best.
  41. binding.Z_MIN_CHUNK = 64;
  42. binding.Z_MAX_CHUNK = Infinity;
  43. binding.Z_DEFAULT_CHUNK = (16 * 1024);
  44. binding.Z_MIN_MEMLEVEL = 1;
  45. binding.Z_MAX_MEMLEVEL = 9;
  46. binding.Z_DEFAULT_MEMLEVEL = 8;
  47. binding.Z_MIN_LEVEL = -1;
  48. binding.Z_MAX_LEVEL = 9;
  49. binding.Z_DEFAULT_LEVEL = binding.Z_DEFAULT_COMPRESSION;
  50. // translation table for return codes.
  51. export var codes = {
  52. Z_OK: binding.Z_OK,
  53. Z_STREAM_END: binding.Z_STREAM_END,
  54. Z_NEED_DICT: binding.Z_NEED_DICT,
  55. Z_ERRNO: binding.Z_ERRNO,
  56. Z_STREAM_ERROR: binding.Z_STREAM_ERROR,
  57. Z_DATA_ERROR: binding.Z_DATA_ERROR,
  58. Z_MEM_ERROR: binding.Z_MEM_ERROR,
  59. Z_BUF_ERROR: binding.Z_BUF_ERROR,
  60. Z_VERSION_ERROR: binding.Z_VERSION_ERROR
  61. };
  62. Object.keys(codes).forEach(function(k) {
  63. codes[codes[k]] = k;
  64. });
  65. export function createDeflate(o) {
  66. return new Deflate(o);
  67. }
  68. export function createInflate(o) {
  69. return new Inflate(o);
  70. }
  71. export function createDeflateRaw(o) {
  72. return new DeflateRaw(o);
  73. }
  74. export function createInflateRaw(o) {
  75. return new InflateRaw(o);
  76. }
  77. export function createGzip(o) {
  78. return new Gzip(o);
  79. }
  80. export function createGunzip(o) {
  81. return new Gunzip(o);
  82. }
  83. export function createUnzip(o) {
  84. return new Unzip(o);
  85. }
  86. // Convenience methods.
  87. // compress/decompress a string or buffer in one step.
  88. export function deflate(buffer, opts, callback) {
  89. if (typeof opts === 'function') {
  90. callback = opts;
  91. opts = {};
  92. }
  93. return zlibBuffer(new Deflate(opts), buffer, callback);
  94. }
  95. export function deflateSync(buffer, opts) {
  96. return zlibBufferSync(new Deflate(opts), buffer);
  97. }
  98. export function gzip(buffer, opts, callback) {
  99. if (typeof opts === 'function') {
  100. callback = opts;
  101. opts = {};
  102. }
  103. return zlibBuffer(new Gzip(opts), buffer, callback);
  104. }
  105. export function gzipSync(buffer, opts) {
  106. return zlibBufferSync(new Gzip(opts), buffer);
  107. }
  108. export function deflateRaw(buffer, opts, callback) {
  109. if (typeof opts === 'function') {
  110. callback = opts;
  111. opts = {};
  112. }
  113. return zlibBuffer(new DeflateRaw(opts), buffer, callback);
  114. }
  115. export function deflateRawSync(buffer, opts) {
  116. return zlibBufferSync(new DeflateRaw(opts), buffer);
  117. }
  118. export function unzip(buffer, opts, callback) {
  119. if (typeof opts === 'function') {
  120. callback = opts;
  121. opts = {};
  122. }
  123. return zlibBuffer(new Unzip(opts), buffer, callback);
  124. }
  125. export function unzipSync(buffer, opts) {
  126. return zlibBufferSync(new Unzip(opts), buffer);
  127. }
  128. export function inflate(buffer, opts, callback) {
  129. if (typeof opts === 'function') {
  130. callback = opts;
  131. opts = {};
  132. }
  133. return zlibBuffer(new Inflate(opts), buffer, callback);
  134. }
  135. export function inflateSync(buffer, opts) {
  136. return zlibBufferSync(new Inflate(opts), buffer);
  137. }
  138. export function gunzip(buffer, opts, callback) {
  139. if (typeof opts === 'function') {
  140. callback = opts;
  141. opts = {};
  142. }
  143. return zlibBuffer(new Gunzip(opts), buffer, callback);
  144. }
  145. export function gunzipSync(buffer, opts) {
  146. return zlibBufferSync(new Gunzip(opts), buffer);
  147. }
  148. export function inflateRaw(buffer, opts, callback) {
  149. if (typeof opts === 'function') {
  150. callback = opts;
  151. opts = {};
  152. }
  153. return zlibBuffer(new InflateRaw(opts), buffer, callback);
  154. }
  155. export function inflateRawSync(buffer, opts) {
  156. return zlibBufferSync(new InflateRaw(opts), buffer);
  157. }
  158. function zlibBuffer(engine, buffer, callback) {
  159. var buffers = [];
  160. var nread = 0;
  161. engine.on('error', onError);
  162. engine.on('end', onEnd);
  163. engine.end(buffer);
  164. flow();
  165. function flow() {
  166. var chunk;
  167. while (null !== (chunk = engine.read())) {
  168. buffers.push(chunk);
  169. nread += chunk.length;
  170. }
  171. engine.once('readable', flow);
  172. }
  173. function onError(err) {
  174. engine.removeListener('end', onEnd);
  175. engine.removeListener('readable', flow);
  176. callback(err);
  177. }
  178. function onEnd() {
  179. var buf = Buffer.concat(buffers, nread);
  180. buffers = [];
  181. callback(null, buf);
  182. engine.close();
  183. }
  184. }
  185. function zlibBufferSync(engine, buffer) {
  186. if (typeof buffer === 'string')
  187. buffer = new Buffer(buffer);
  188. if (!Buffer.isBuffer(buffer))
  189. throw new TypeError('Not a string or buffer');
  190. var flushFlag = binding.Z_FINISH;
  191. return engine._processChunk(buffer, flushFlag);
  192. }
  193. // generic zlib
  194. // minimal 2-byte header
  195. export function Deflate(opts) {
  196. if (!(this instanceof Deflate)) return new Deflate(opts);
  197. Zlib.call(this, opts, binding.DEFLATE);
  198. }
  199. export function Inflate(opts) {
  200. if (!(this instanceof Inflate)) return new Inflate(opts);
  201. Zlib.call(this, opts, binding.INFLATE);
  202. }
  203. // gzip - bigger header, same deflate compression
  204. export function Gzip(opts) {
  205. if (!(this instanceof Gzip)) return new Gzip(opts);
  206. Zlib.call(this, opts, binding.GZIP);
  207. }
  208. export function Gunzip(opts) {
  209. if (!(this instanceof Gunzip)) return new Gunzip(opts);
  210. Zlib.call(this, opts, binding.GUNZIP);
  211. }
  212. // raw - no header
  213. export function DeflateRaw(opts) {
  214. if (!(this instanceof DeflateRaw)) return new DeflateRaw(opts);
  215. Zlib.call(this, opts, binding.DEFLATERAW);
  216. }
  217. export function InflateRaw(opts) {
  218. if (!(this instanceof InflateRaw)) return new InflateRaw(opts);
  219. Zlib.call(this, opts, binding.INFLATERAW);
  220. }
  221. // auto-detect header.
  222. export function Unzip(opts) {
  223. if (!(this instanceof Unzip)) return new Unzip(opts);
  224. Zlib.call(this, opts, binding.UNZIP);
  225. }
  226. // the Zlib class they all inherit from
  227. // This thing manages the queue of requests, and returns
  228. // true or false if there is anything in the queue when
  229. // you call the .write() method.
  230. export function Zlib(opts, mode) {
  231. this._opts = opts = opts || {};
  232. this._chunkSize = opts.chunkSize || binding.Z_DEFAULT_CHUNK;
  233. Transform.call(this, opts);
  234. if (opts.flush) {
  235. if (opts.flush !== binding.Z_NO_FLUSH &&
  236. opts.flush !== binding.Z_PARTIAL_FLUSH &&
  237. opts.flush !== binding.Z_SYNC_FLUSH &&
  238. opts.flush !== binding.Z_FULL_FLUSH &&
  239. opts.flush !== binding.Z_FINISH &&
  240. opts.flush !== binding.Z_BLOCK) {
  241. throw new Error('Invalid flush flag: ' + opts.flush);
  242. }
  243. }
  244. this._flushFlag = opts.flush || binding.Z_NO_FLUSH;
  245. if (opts.chunkSize) {
  246. if (opts.chunkSize < binding.Z_MIN_CHUNK ||
  247. opts.chunkSize > binding.Z_MAX_CHUNK) {
  248. throw new Error('Invalid chunk size: ' + opts.chunkSize);
  249. }
  250. }
  251. if (opts.windowBits) {
  252. if (opts.windowBits < binding.Z_MIN_WINDOWBITS ||
  253. opts.windowBits > binding.Z_MAX_WINDOWBITS) {
  254. throw new Error('Invalid windowBits: ' + opts.windowBits);
  255. }
  256. }
  257. if (opts.level) {
  258. if (opts.level < binding.Z_MIN_LEVEL ||
  259. opts.level > binding.Z_MAX_LEVEL) {
  260. throw new Error('Invalid compression level: ' + opts.level);
  261. }
  262. }
  263. if (opts.memLevel) {
  264. if (opts.memLevel < binding.Z_MIN_MEMLEVEL ||
  265. opts.memLevel > binding.Z_MAX_MEMLEVEL) {
  266. throw new Error('Invalid memLevel: ' + opts.memLevel);
  267. }
  268. }
  269. if (opts.strategy) {
  270. if (opts.strategy != binding.Z_FILTERED &&
  271. opts.strategy != binding.Z_HUFFMAN_ONLY &&
  272. opts.strategy != binding.Z_RLE &&
  273. opts.strategy != binding.Z_FIXED &&
  274. opts.strategy != binding.Z_DEFAULT_STRATEGY) {
  275. throw new Error('Invalid strategy: ' + opts.strategy);
  276. }
  277. }
  278. if (opts.dictionary) {
  279. if (!Buffer.isBuffer(opts.dictionary)) {
  280. throw new Error('Invalid dictionary: it should be a Buffer instance');
  281. }
  282. }
  283. this._binding = new binding.Zlib(mode);
  284. var self = this;
  285. this._hadError = false;
  286. this._binding.onerror = function(message, errno) {
  287. // there is no way to cleanly recover.
  288. // continuing only obscures problems.
  289. self._binding = null;
  290. self._hadError = true;
  291. var error = new Error(message);
  292. error.errno = errno;
  293. error.code = binding.codes[errno];
  294. self.emit('error', error);
  295. };
  296. var level = binding.Z_DEFAULT_COMPRESSION;
  297. if (typeof opts.level === 'number') level = opts.level;
  298. var strategy = binding.Z_DEFAULT_STRATEGY;
  299. if (typeof opts.strategy === 'number') strategy = opts.strategy;
  300. this._binding.init(opts.windowBits || binding.Z_DEFAULT_WINDOWBITS,
  301. level,
  302. opts.memLevel || binding.Z_DEFAULT_MEMLEVEL,
  303. strategy,
  304. opts.dictionary);
  305. this._buffer = new Buffer(this._chunkSize);
  306. this._offset = 0;
  307. this._closed = false;
  308. this._level = level;
  309. this._strategy = strategy;
  310. this.once('end', this.close);
  311. }
  312. inherits(Zlib, Transform);
  313. Zlib.prototype.params = function(level, strategy, callback) {
  314. if (level < binding.Z_MIN_LEVEL ||
  315. level > binding.Z_MAX_LEVEL) {
  316. throw new RangeError('Invalid compression level: ' + level);
  317. }
  318. if (strategy != binding.Z_FILTERED &&
  319. strategy != binding.Z_HUFFMAN_ONLY &&
  320. strategy != binding.Z_RLE &&
  321. strategy != binding.Z_FIXED &&
  322. strategy != binding.Z_DEFAULT_STRATEGY) {
  323. throw new TypeError('Invalid strategy: ' + strategy);
  324. }
  325. if (this._level !== level || this._strategy !== strategy) {
  326. var self = this;
  327. this.flush(binding.Z_SYNC_FLUSH, function() {
  328. self._binding.params(level, strategy);
  329. if (!self._hadError) {
  330. self._level = level;
  331. self._strategy = strategy;
  332. if (callback) callback();
  333. }
  334. });
  335. } else {
  336. process.nextTick(callback);
  337. }
  338. };
  339. Zlib.prototype.reset = function() {
  340. return this._binding.reset();
  341. };
  342. // This is the _flush function called by the transform class,
  343. // internally, when the last chunk has been written.
  344. Zlib.prototype._flush = function(callback) {
  345. this._transform(new Buffer(0), '', callback);
  346. };
  347. Zlib.prototype.flush = function(kind, callback) {
  348. var ws = this._writableState;
  349. if (typeof kind === 'function' || (kind === void 0 && !callback)) {
  350. callback = kind;
  351. kind = binding.Z_FULL_FLUSH;
  352. }
  353. if (ws.ended) {
  354. if (callback)
  355. process.nextTick(callback);
  356. } else if (ws.ending) {
  357. if (callback)
  358. this.once('end', callback);
  359. } else if (ws.needDrain) {
  360. var self = this;
  361. this.once('drain', function() {
  362. self.flush(callback);
  363. });
  364. } else {
  365. this._flushFlag = kind;
  366. this.write(new Buffer(0), '', callback);
  367. }
  368. };
  369. Zlib.prototype.close = function(callback) {
  370. if (callback)
  371. process.nextTick(callback);
  372. if (this._closed)
  373. return;
  374. this._closed = true;
  375. this._binding.close();
  376. var self = this;
  377. process.nextTick(function() {
  378. self.emit('close');
  379. });
  380. };
  381. Zlib.prototype._transform = function(chunk, encoding, cb) {
  382. var flushFlag;
  383. var ws = this._writableState;
  384. var ending = ws.ending || ws.ended;
  385. var last = ending && (!chunk || ws.length === chunk.length);
  386. if (!chunk === null && !Buffer.isBuffer(chunk))
  387. return cb(new Error('invalid input'));
  388. // If it's the last chunk, or a final flush, we use the Z_FINISH flush flag.
  389. // If it's explicitly flushing at some other time, then we use
  390. // Z_FULL_FLUSH. Otherwise, use Z_NO_FLUSH for maximum compression
  391. // goodness.
  392. if (last)
  393. flushFlag = binding.Z_FINISH;
  394. else {
  395. flushFlag = this._flushFlag;
  396. // once we've flushed the last of the queue, stop flushing and
  397. // go back to the normal behavior.
  398. if (chunk.length >= ws.length) {
  399. this._flushFlag = this._opts.flush || binding.Z_NO_FLUSH;
  400. }
  401. }
  402. this._processChunk(chunk, flushFlag, cb);
  403. };
  404. Zlib.prototype._processChunk = function(chunk, flushFlag, cb) {
  405. var availInBefore = chunk && chunk.length;
  406. var availOutBefore = this._chunkSize - this._offset;
  407. var inOff = 0;
  408. var self = this;
  409. var async = typeof cb === 'function';
  410. if (!async) {
  411. var buffers = [];
  412. var nread = 0;
  413. var error;
  414. this.on('error', function(er) {
  415. error = er;
  416. });
  417. do {
  418. var res = this._binding.writeSync(flushFlag,
  419. chunk, // in
  420. inOff, // in_off
  421. availInBefore, // in_len
  422. this._buffer, // out
  423. this._offset, //out_off
  424. availOutBefore); // out_len
  425. } while (!this._hadError && callback(res[0], res[1]));
  426. if (this._hadError) {
  427. throw error;
  428. }
  429. var buf = Buffer.concat(buffers, nread);
  430. this.close();
  431. return buf;
  432. }
  433. var req = this._binding.write(flushFlag,
  434. chunk, // in
  435. inOff, // in_off
  436. availInBefore, // in_len
  437. this._buffer, // out
  438. this._offset, //out_off
  439. availOutBefore); // out_len
  440. req.buffer = chunk;
  441. req.callback = callback;
  442. function callback(availInAfter, availOutAfter) {
  443. if (self._hadError)
  444. return;
  445. var have = availOutBefore - availOutAfter;
  446. assert(have >= 0, 'have should not go down');
  447. if (have > 0) {
  448. var out = self._buffer.slice(self._offset, self._offset + have);
  449. self._offset += have;
  450. // serve some output to the consumer.
  451. if (async) {
  452. self.push(out);
  453. } else {
  454. buffers.push(out);
  455. nread += out.length;
  456. }
  457. }
  458. // exhausted the output buffer, or used all the input create a new one.
  459. if (availOutAfter === 0 || self._offset >= self._chunkSize) {
  460. availOutBefore = self._chunkSize;
  461. self._offset = 0;
  462. self._buffer = new Buffer(self._chunkSize);
  463. }
  464. if (availOutAfter === 0) {
  465. // Not actually done. Need to reprocess.
  466. // Also, update the availInBefore to the availInAfter value,
  467. // so that if we have to hit it a third (fourth, etc.) time,
  468. // it'll have the correct byte counts.
  469. inOff += (availInBefore - availInAfter);
  470. availInBefore = availInAfter;
  471. if (!async)
  472. return true;
  473. var newReq = self._binding.write(flushFlag,
  474. chunk,
  475. inOff,
  476. availInBefore,
  477. self._buffer,
  478. self._offset,
  479. self._chunkSize);
  480. newReq.callback = callback; // this same function
  481. newReq.buffer = chunk;
  482. return;
  483. }
  484. if (!async)
  485. return false;
  486. // finished with the chunk.
  487. cb();
  488. }
  489. };
  490. inherits(Deflate, Zlib);
  491. inherits(Inflate, Zlib);
  492. inherits(Gzip, Zlib);
  493. inherits(Gunzip, Zlib);
  494. inherits(DeflateRaw, Zlib);
  495. inherits(InflateRaw, Zlib);
  496. inherits(Unzip, Zlib);
  497. export default {
  498. codes: codes,
  499. createDeflate: createDeflate,
  500. createInflate: createInflate,
  501. createDeflateRaw: createDeflateRaw,
  502. createInflateRaw: createInflateRaw,
  503. createGzip: createGzip,
  504. createGunzip: createGunzip,
  505. createUnzip: createUnzip,
  506. deflate: deflate,
  507. deflateSync: deflateSync,
  508. gzip: gzip,
  509. gzipSync: gzipSync,
  510. deflateRaw: deflateRaw,
  511. deflateRawSync: deflateRawSync,
  512. unzip: unzip,
  513. unzipSync: unzipSync,
  514. inflate: inflate,
  515. inflateSync: inflateSync,
  516. gunzip: gunzip,
  517. gunzipSync: gunzipSync,
  518. inflateRaw: inflateRaw,
  519. inflateRawSync: inflateRawSync,
  520. Deflate: Deflate,
  521. Inflate: Inflate,
  522. Gzip: Gzip,
  523. Gunzip: Gunzip,
  524. DeflateRaw: DeflateRaw,
  525. InflateRaw: InflateRaw,
  526. Unzip: Unzip,
  527. Zlib: Zlib
  528. };