11cb0ef41Sopenharmony_ci// Copyright Joyent, Inc. and other Node contributors. 21cb0ef41Sopenharmony_ci// 31cb0ef41Sopenharmony_ci// Permission is hereby granted, free of charge, to any person obtaining a 41cb0ef41Sopenharmony_ci// copy of this software and associated documentation files (the 51cb0ef41Sopenharmony_ci// "Software"), to deal in the Software without restriction, including 61cb0ef41Sopenharmony_ci// without limitation the rights to use, copy, modify, merge, publish, 71cb0ef41Sopenharmony_ci// distribute, sublicense, and/or sell copies of the Software, and to permit 81cb0ef41Sopenharmony_ci// persons to whom the Software is furnished to do so, subject to the 91cb0ef41Sopenharmony_ci// following conditions: 101cb0ef41Sopenharmony_ci// 111cb0ef41Sopenharmony_ci// The above copyright notice and this permission notice shall be included 121cb0ef41Sopenharmony_ci// in all copies or substantial portions of the Software. 131cb0ef41Sopenharmony_ci// 141cb0ef41Sopenharmony_ci// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 151cb0ef41Sopenharmony_ci// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 161cb0ef41Sopenharmony_ci// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 171cb0ef41Sopenharmony_ci// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 181cb0ef41Sopenharmony_ci// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 191cb0ef41Sopenharmony_ci// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 201cb0ef41Sopenharmony_ci// USE OR OTHER DEALINGS IN THE SOFTWARE. 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ci'use strict'; 231cb0ef41Sopenharmony_ciconst common = require('../common'); 241cb0ef41Sopenharmony_ciconst assert = require('assert'); 251cb0ef41Sopenharmony_ciconst zlib = require('zlib'); 261cb0ef41Sopenharmony_ciconst stream = require('stream'); 271cb0ef41Sopenharmony_ciconst fs = require('fs'); 281cb0ef41Sopenharmony_ciconst fixtures = require('../common/fixtures'); 291cb0ef41Sopenharmony_ci 301cb0ef41Sopenharmony_ci// Should not segfault. 311cb0ef41Sopenharmony_ciassert.throws(() => zlib.gzipSync(Buffer.alloc(0), { windowBits: 8 }), { 321cb0ef41Sopenharmony_ci code: 'ERR_OUT_OF_RANGE', 331cb0ef41Sopenharmony_ci name: 'RangeError', 341cb0ef41Sopenharmony_ci message: 'The value of "options.windowBits" is out of range. ' + 351cb0ef41Sopenharmony_ci 'It must be >= 9 and <= 15. Received 8', 361cb0ef41Sopenharmony_ci}); 371cb0ef41Sopenharmony_ci 381cb0ef41Sopenharmony_cilet zlibPairs = [ 391cb0ef41Sopenharmony_ci [zlib.Deflate, zlib.Inflate], 401cb0ef41Sopenharmony_ci [zlib.Gzip, zlib.Gunzip], 411cb0ef41Sopenharmony_ci [zlib.Deflate, zlib.Unzip], 421cb0ef41Sopenharmony_ci [zlib.Gzip, zlib.Unzip], 431cb0ef41Sopenharmony_ci [zlib.DeflateRaw, zlib.InflateRaw], 441cb0ef41Sopenharmony_ci [zlib.BrotliCompress, zlib.BrotliDecompress], 451cb0ef41Sopenharmony_ci]; 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_ci// How fast to trickle through the slowstream 481cb0ef41Sopenharmony_cilet trickle = [128, 1024, 1024 * 1024]; 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_ci// Tunable options for zlib classes. 511cb0ef41Sopenharmony_ci 521cb0ef41Sopenharmony_ci// several different chunk sizes 531cb0ef41Sopenharmony_cilet chunkSize = [128, 1024, 1024 * 16, 1024 * 1024]; 541cb0ef41Sopenharmony_ci 551cb0ef41Sopenharmony_ci// This is every possible value. 561cb0ef41Sopenharmony_cilet level = [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 571cb0ef41Sopenharmony_cilet windowBits = [8, 9, 10, 11, 12, 13, 14, 15]; 581cb0ef41Sopenharmony_cilet memLevel = [1, 2, 3, 4, 5, 6, 7, 8, 9]; 591cb0ef41Sopenharmony_cilet strategy = [0, 1, 2, 3, 4]; 601cb0ef41Sopenharmony_ci 611cb0ef41Sopenharmony_ci// It's nice in theory to test every combination, but it 621cb0ef41Sopenharmony_ci// takes WAY too long. Maybe a pummel test could do this? 631cb0ef41Sopenharmony_ciif (!process.env.PUMMEL) { 641cb0ef41Sopenharmony_ci trickle = [1024]; 651cb0ef41Sopenharmony_ci chunkSize = [1024 * 16]; 661cb0ef41Sopenharmony_ci level = [6]; 671cb0ef41Sopenharmony_ci memLevel = [8]; 681cb0ef41Sopenharmony_ci windowBits = [15]; 691cb0ef41Sopenharmony_ci strategy = [0]; 701cb0ef41Sopenharmony_ci} 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_cilet testFiles = ['person.jpg', 'elipses.txt', 'empty.txt']; 731cb0ef41Sopenharmony_ci 741cb0ef41Sopenharmony_ciif (process.env.FAST) { 751cb0ef41Sopenharmony_ci zlibPairs = [[zlib.Gzip, zlib.Unzip]]; 761cb0ef41Sopenharmony_ci testFiles = ['person.jpg']; 771cb0ef41Sopenharmony_ci} 781cb0ef41Sopenharmony_ci 791cb0ef41Sopenharmony_ciconst tests = {}; 801cb0ef41Sopenharmony_citestFiles.forEach(common.mustCall((file) => { 811cb0ef41Sopenharmony_ci tests[file] = fixtures.readSync(file); 821cb0ef41Sopenharmony_ci}, testFiles.length)); 831cb0ef41Sopenharmony_ci 841cb0ef41Sopenharmony_ci 851cb0ef41Sopenharmony_ci// Stream that saves everything 861cb0ef41Sopenharmony_ciclass BufferStream extends stream.Stream { 871cb0ef41Sopenharmony_ci constructor() { 881cb0ef41Sopenharmony_ci super(); 891cb0ef41Sopenharmony_ci this.chunks = []; 901cb0ef41Sopenharmony_ci this.length = 0; 911cb0ef41Sopenharmony_ci this.writable = true; 921cb0ef41Sopenharmony_ci this.readable = true; 931cb0ef41Sopenharmony_ci } 941cb0ef41Sopenharmony_ci 951cb0ef41Sopenharmony_ci write(c) { 961cb0ef41Sopenharmony_ci this.chunks.push(c); 971cb0ef41Sopenharmony_ci this.length += c.length; 981cb0ef41Sopenharmony_ci return true; 991cb0ef41Sopenharmony_ci } 1001cb0ef41Sopenharmony_ci 1011cb0ef41Sopenharmony_ci end(c) { 1021cb0ef41Sopenharmony_ci if (c) this.write(c); 1031cb0ef41Sopenharmony_ci // flatten 1041cb0ef41Sopenharmony_ci const buf = Buffer.allocUnsafe(this.length); 1051cb0ef41Sopenharmony_ci let i = 0; 1061cb0ef41Sopenharmony_ci this.chunks.forEach((c) => { 1071cb0ef41Sopenharmony_ci c.copy(buf, i); 1081cb0ef41Sopenharmony_ci i += c.length; 1091cb0ef41Sopenharmony_ci }); 1101cb0ef41Sopenharmony_ci this.emit('data', buf); 1111cb0ef41Sopenharmony_ci this.emit('end'); 1121cb0ef41Sopenharmony_ci return true; 1131cb0ef41Sopenharmony_ci } 1141cb0ef41Sopenharmony_ci} 1151cb0ef41Sopenharmony_ci 1161cb0ef41Sopenharmony_ciclass SlowStream extends stream.Stream { 1171cb0ef41Sopenharmony_ci constructor(trickle) { 1181cb0ef41Sopenharmony_ci super(); 1191cb0ef41Sopenharmony_ci this.trickle = trickle; 1201cb0ef41Sopenharmony_ci this.offset = 0; 1211cb0ef41Sopenharmony_ci this.readable = this.writable = true; 1221cb0ef41Sopenharmony_ci } 1231cb0ef41Sopenharmony_ci 1241cb0ef41Sopenharmony_ci write() { 1251cb0ef41Sopenharmony_ci throw new Error('not implemented, just call ss.end(chunk)'); 1261cb0ef41Sopenharmony_ci } 1271cb0ef41Sopenharmony_ci 1281cb0ef41Sopenharmony_ci pause() { 1291cb0ef41Sopenharmony_ci this.paused = true; 1301cb0ef41Sopenharmony_ci this.emit('pause'); 1311cb0ef41Sopenharmony_ci } 1321cb0ef41Sopenharmony_ci 1331cb0ef41Sopenharmony_ci resume() { 1341cb0ef41Sopenharmony_ci const emit = () => { 1351cb0ef41Sopenharmony_ci if (this.paused) return; 1361cb0ef41Sopenharmony_ci if (this.offset >= this.length) { 1371cb0ef41Sopenharmony_ci this.ended = true; 1381cb0ef41Sopenharmony_ci return this.emit('end'); 1391cb0ef41Sopenharmony_ci } 1401cb0ef41Sopenharmony_ci const end = Math.min(this.offset + this.trickle, this.length); 1411cb0ef41Sopenharmony_ci const c = this.chunk.slice(this.offset, end); 1421cb0ef41Sopenharmony_ci this.offset += c.length; 1431cb0ef41Sopenharmony_ci this.emit('data', c); 1441cb0ef41Sopenharmony_ci process.nextTick(emit); 1451cb0ef41Sopenharmony_ci }; 1461cb0ef41Sopenharmony_ci 1471cb0ef41Sopenharmony_ci if (this.ended) return; 1481cb0ef41Sopenharmony_ci this.emit('resume'); 1491cb0ef41Sopenharmony_ci if (!this.chunk) return; 1501cb0ef41Sopenharmony_ci this.paused = false; 1511cb0ef41Sopenharmony_ci emit(); 1521cb0ef41Sopenharmony_ci } 1531cb0ef41Sopenharmony_ci 1541cb0ef41Sopenharmony_ci end(chunk) { 1551cb0ef41Sopenharmony_ci // Walk over the chunk in blocks. 1561cb0ef41Sopenharmony_ci this.chunk = chunk; 1571cb0ef41Sopenharmony_ci this.length = chunk.length; 1581cb0ef41Sopenharmony_ci this.resume(); 1591cb0ef41Sopenharmony_ci return this.ended; 1601cb0ef41Sopenharmony_ci } 1611cb0ef41Sopenharmony_ci} 1621cb0ef41Sopenharmony_ci 1631cb0ef41Sopenharmony_ci// windowBits: 8 shouldn't throw 1641cb0ef41Sopenharmony_cizlib.createDeflateRaw({ windowBits: 8 }); 1651cb0ef41Sopenharmony_ci 1661cb0ef41Sopenharmony_ci{ 1671cb0ef41Sopenharmony_ci const node = fs.createReadStream(fixtures.path('person.jpg')); 1681cb0ef41Sopenharmony_ci const raw = []; 1691cb0ef41Sopenharmony_ci const reinflated = []; 1701cb0ef41Sopenharmony_ci node.on('data', (chunk) => raw.push(chunk)); 1711cb0ef41Sopenharmony_ci 1721cb0ef41Sopenharmony_ci // Usually, the inflate windowBits parameter needs to be at least the 1731cb0ef41Sopenharmony_ci // value of the matching deflate’s windowBits. However, inflate raw with 1741cb0ef41Sopenharmony_ci // windowBits = 8 should be able to handle compressed data from a source 1751cb0ef41Sopenharmony_ci // that does not know about the silent 8-to-9 upgrade of windowBits 1761cb0ef41Sopenharmony_ci // that most versions of zlib/Node perform, and which *still* results in 1771cb0ef41Sopenharmony_ci // a valid 8-bit-window zlib stream. 1781cb0ef41Sopenharmony_ci node.pipe(zlib.createDeflateRaw({ windowBits: 9 })) 1791cb0ef41Sopenharmony_ci .pipe(zlib.createInflateRaw({ windowBits: 8 })) 1801cb0ef41Sopenharmony_ci .on('data', (chunk) => reinflated.push(chunk)) 1811cb0ef41Sopenharmony_ci .on('end', common.mustCall( 1821cb0ef41Sopenharmony_ci () => assert(Buffer.concat(raw).equals(Buffer.concat(reinflated))))) 1831cb0ef41Sopenharmony_ci .on('close', common.mustCall(1)); 1841cb0ef41Sopenharmony_ci} 1851cb0ef41Sopenharmony_ci 1861cb0ef41Sopenharmony_ci// For each of the files, make sure that compressing and 1871cb0ef41Sopenharmony_ci// decompressing results in the same data, for every combination 1881cb0ef41Sopenharmony_ci// of the options set above. 1891cb0ef41Sopenharmony_ci 1901cb0ef41Sopenharmony_ciconst testKeys = Object.keys(tests); 1911cb0ef41Sopenharmony_citestKeys.forEach(common.mustCall((file) => { 1921cb0ef41Sopenharmony_ci const test = tests[file]; 1931cb0ef41Sopenharmony_ci chunkSize.forEach(common.mustCall((chunkSize) => { 1941cb0ef41Sopenharmony_ci trickle.forEach(common.mustCall((trickle) => { 1951cb0ef41Sopenharmony_ci windowBits.forEach(common.mustCall((windowBits) => { 1961cb0ef41Sopenharmony_ci level.forEach(common.mustCall((level) => { 1971cb0ef41Sopenharmony_ci memLevel.forEach(common.mustCall((memLevel) => { 1981cb0ef41Sopenharmony_ci strategy.forEach(common.mustCall((strategy) => { 1991cb0ef41Sopenharmony_ci zlibPairs.forEach(common.mustCall((pair) => { 2001cb0ef41Sopenharmony_ci const Def = pair[0]; 2011cb0ef41Sopenharmony_ci const Inf = pair[1]; 2021cb0ef41Sopenharmony_ci const opts = { level, windowBits, memLevel, strategy }; 2031cb0ef41Sopenharmony_ci 2041cb0ef41Sopenharmony_ci const def = new Def(opts); 2051cb0ef41Sopenharmony_ci const inf = new Inf(opts); 2061cb0ef41Sopenharmony_ci const ss = new SlowStream(trickle); 2071cb0ef41Sopenharmony_ci const buf = new BufferStream(); 2081cb0ef41Sopenharmony_ci 2091cb0ef41Sopenharmony_ci // Verify that the same exact buffer comes out the other end. 2101cb0ef41Sopenharmony_ci buf.on('data', common.mustCall((c) => { 2111cb0ef41Sopenharmony_ci const msg = `${file} ${chunkSize} ${ 2121cb0ef41Sopenharmony_ci JSON.stringify(opts)} ${Def.name} -> ${Inf.name}`; 2131cb0ef41Sopenharmony_ci let i; 2141cb0ef41Sopenharmony_ci for (i = 0; i < Math.max(c.length, test.length); i++) { 2151cb0ef41Sopenharmony_ci if (c[i] !== test[i]) { 2161cb0ef41Sopenharmony_ci assert.fail(msg); 2171cb0ef41Sopenharmony_ci break; 2181cb0ef41Sopenharmony_ci } 2191cb0ef41Sopenharmony_ci } 2201cb0ef41Sopenharmony_ci })); 2211cb0ef41Sopenharmony_ci 2221cb0ef41Sopenharmony_ci // The magic happens here. 2231cb0ef41Sopenharmony_ci ss.pipe(def).pipe(inf).pipe(buf); 2241cb0ef41Sopenharmony_ci ss.end(test); 2251cb0ef41Sopenharmony_ci }, zlibPairs.length)); 2261cb0ef41Sopenharmony_ci }, strategy.length)); 2271cb0ef41Sopenharmony_ci }, memLevel.length)); 2281cb0ef41Sopenharmony_ci }, level.length)); 2291cb0ef41Sopenharmony_ci }, windowBits.length)); 2301cb0ef41Sopenharmony_ci }, trickle.length)); 2311cb0ef41Sopenharmony_ci }, chunkSize.length)); 2321cb0ef41Sopenharmony_ci}, testKeys.length)); 233