From 6c1a321500e08ec2917a2541b80fcc16ec4faa3f Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 27 Apr 2021 12:55:23 +0200 Subject: [PATCH 01/30] Move the `LZWStream` from `src/core/stream.js` and into its own file --- src/core/lzw_stream.js | 156 +++++++++++++++++++++++++++++++++++++++++ src/core/parser.js | 2 +- src/core/stream.js | 138 ------------------------------------ 3 files changed, 157 insertions(+), 139 deletions(-) create mode 100644 src/core/lzw_stream.js diff --git a/src/core/lzw_stream.js b/src/core/lzw_stream.js new file mode 100644 index 0000000000000..4d3a8cdce3660 --- /dev/null +++ b/src/core/lzw_stream.js @@ -0,0 +1,156 @@ +/* Copyright 2012 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* eslint-disable no-var */ + +import { DecodeStream } from "./stream.js"; + +var LZWStream = (function LZWStreamClosure() { + // eslint-disable-next-line no-shadow + function LZWStream(str, maybeLength, earlyChange) { + this.str = str; + this.dict = str.dict; + this.cachedData = 0; + this.bitsCached = 0; + + var maxLzwDictionarySize = 4096; + var lzwState = { + earlyChange, + codeLength: 9, + nextCode: 258, + dictionaryValues: new Uint8Array(maxLzwDictionarySize), + dictionaryLengths: new Uint16Array(maxLzwDictionarySize), + dictionaryPrevCodes: new Uint16Array(maxLzwDictionarySize), + currentSequence: new Uint8Array(maxLzwDictionarySize), + currentSequenceLength: 0, + }; + for (var i = 0; i < 256; ++i) { + lzwState.dictionaryValues[i] = i; + lzwState.dictionaryLengths[i] = 1; + } + this.lzwState = lzwState; + + DecodeStream.call(this, maybeLength); + } + + LZWStream.prototype = Object.create(DecodeStream.prototype); + + LZWStream.prototype.readBits = function LZWStream_readBits(n) { + var bitsCached = this.bitsCached; + var cachedData = this.cachedData; + while (bitsCached < n) { + var c = this.str.getByte(); + if (c === -1) { + this.eof = true; + return null; + } + cachedData = (cachedData << 8) | c; + bitsCached += 8; + } + this.bitsCached = bitsCached -= n; + this.cachedData = cachedData; + this.lastCode = null; + return (cachedData >>> bitsCached) & ((1 << n) - 1); + }; + + LZWStream.prototype.readBlock = function LZWStream_readBlock() { + var blockSize = 512; + var estimatedDecodedSize = blockSize * 2, + decodedSizeDelta = blockSize; + var i, j, q; + + var lzwState = this.lzwState; + if (!lzwState) { + return; // eof was found + } + + var earlyChange = lzwState.earlyChange; + var nextCode = lzwState.nextCode; + var dictionaryValues = lzwState.dictionaryValues; + var dictionaryLengths = lzwState.dictionaryLengths; + var dictionaryPrevCodes = lzwState.dictionaryPrevCodes; + var codeLength = lzwState.codeLength; + var prevCode = lzwState.prevCode; + var currentSequence = lzwState.currentSequence; + var currentSequenceLength = lzwState.currentSequenceLength; + + var decodedLength = 0; + var currentBufferLength = this.bufferLength; + var buffer = this.ensureBuffer(this.bufferLength + estimatedDecodedSize); + + for (i = 0; i < blockSize; i++) { + var code = this.readBits(codeLength); + var hasPrev = currentSequenceLength > 0; + if (code < 256) { + currentSequence[0] = code; + currentSequenceLength = 1; + } else if (code >= 258) { + if (code < nextCode) { + currentSequenceLength = dictionaryLengths[code]; + for (j = currentSequenceLength - 1, q = code; j >= 0; j--) { + currentSequence[j] = dictionaryValues[q]; + q = dictionaryPrevCodes[q]; + } + } else { + currentSequence[currentSequenceLength++] = currentSequence[0]; + } + } else if (code === 256) { + codeLength = 9; + nextCode = 258; + currentSequenceLength = 0; + continue; + } else { + this.eof = true; + delete this.lzwState; + break; + } + + if (hasPrev) { + dictionaryPrevCodes[nextCode] = prevCode; + dictionaryLengths[nextCode] = dictionaryLengths[prevCode] + 1; + dictionaryValues[nextCode] = currentSequence[0]; + nextCode++; + codeLength = + (nextCode + earlyChange) & (nextCode + earlyChange - 1) + ? codeLength + : Math.min( + Math.log(nextCode + earlyChange) / 0.6931471805599453 + 1, + 12 + ) | 0; + } + prevCode = code; + + decodedLength += currentSequenceLength; + if (estimatedDecodedSize < decodedLength) { + do { + estimatedDecodedSize += decodedSizeDelta; + } while (estimatedDecodedSize < decodedLength); + buffer = this.ensureBuffer(this.bufferLength + estimatedDecodedSize); + } + for (j = 0; j < currentSequenceLength; j++) { + buffer[currentBufferLength++] = currentSequence[j]; + } + } + lzwState.nextCode = nextCode; + lzwState.codeLength = codeLength; + lzwState.prevCode = prevCode; + lzwState.currentSequenceLength = currentSequenceLength; + + this.bufferLength = currentBufferLength; + }; + + return LZWStream; +})(); + +export { LZWStream }; diff --git a/src/core/parser.js b/src/core/parser.js index 6692adbdaf9af..5c79654b0dbcb 100644 --- a/src/core/parser.js +++ b/src/core/parser.js @@ -17,7 +17,6 @@ import { Ascii85Stream, AsciiHexStream, FlateStream, - LZWStream, NullStream, PredictorStream, RunLengthStream, @@ -47,6 +46,7 @@ import { CCITTFaxStream } from "./ccitt_stream.js"; import { Jbig2Stream } from "./jbig2_stream.js"; import { JpegStream } from "./jpeg_stream.js"; import { JpxStream } from "./jpx_stream.js"; +import { LZWStream } from "./lzw_stream.js"; const MAX_LENGTH_TO_CACHE = 1000; const MAX_ADLER32_LENGTH = 5552; diff --git a/src/core/stream.js b/src/core/stream.js index 20717d3dc41fa..258f0205e7642 100644 --- a/src/core/stream.js +++ b/src/core/stream.js @@ -1196,143 +1196,6 @@ var RunLengthStream = (function RunLengthStreamClosure() { return RunLengthStream; })(); -var LZWStream = (function LZWStreamClosure() { - // eslint-disable-next-line no-shadow - function LZWStream(str, maybeLength, earlyChange) { - this.str = str; - this.dict = str.dict; - this.cachedData = 0; - this.bitsCached = 0; - - var maxLzwDictionarySize = 4096; - var lzwState = { - earlyChange, - codeLength: 9, - nextCode: 258, - dictionaryValues: new Uint8Array(maxLzwDictionarySize), - dictionaryLengths: new Uint16Array(maxLzwDictionarySize), - dictionaryPrevCodes: new Uint16Array(maxLzwDictionarySize), - currentSequence: new Uint8Array(maxLzwDictionarySize), - currentSequenceLength: 0, - }; - for (var i = 0; i < 256; ++i) { - lzwState.dictionaryValues[i] = i; - lzwState.dictionaryLengths[i] = 1; - } - this.lzwState = lzwState; - - DecodeStream.call(this, maybeLength); - } - - LZWStream.prototype = Object.create(DecodeStream.prototype); - - LZWStream.prototype.readBits = function LZWStream_readBits(n) { - var bitsCached = this.bitsCached; - var cachedData = this.cachedData; - while (bitsCached < n) { - var c = this.str.getByte(); - if (c === -1) { - this.eof = true; - return null; - } - cachedData = (cachedData << 8) | c; - bitsCached += 8; - } - this.bitsCached = bitsCached -= n; - this.cachedData = cachedData; - this.lastCode = null; - return (cachedData >>> bitsCached) & ((1 << n) - 1); - }; - - LZWStream.prototype.readBlock = function LZWStream_readBlock() { - var blockSize = 512; - var estimatedDecodedSize = blockSize * 2, - decodedSizeDelta = blockSize; - var i, j, q; - - var lzwState = this.lzwState; - if (!lzwState) { - return; // eof was found - } - - var earlyChange = lzwState.earlyChange; - var nextCode = lzwState.nextCode; - var dictionaryValues = lzwState.dictionaryValues; - var dictionaryLengths = lzwState.dictionaryLengths; - var dictionaryPrevCodes = lzwState.dictionaryPrevCodes; - var codeLength = lzwState.codeLength; - var prevCode = lzwState.prevCode; - var currentSequence = lzwState.currentSequence; - var currentSequenceLength = lzwState.currentSequenceLength; - - var decodedLength = 0; - var currentBufferLength = this.bufferLength; - var buffer = this.ensureBuffer(this.bufferLength + estimatedDecodedSize); - - for (i = 0; i < blockSize; i++) { - var code = this.readBits(codeLength); - var hasPrev = currentSequenceLength > 0; - if (code < 256) { - currentSequence[0] = code; - currentSequenceLength = 1; - } else if (code >= 258) { - if (code < nextCode) { - currentSequenceLength = dictionaryLengths[code]; - for (j = currentSequenceLength - 1, q = code; j >= 0; j--) { - currentSequence[j] = dictionaryValues[q]; - q = dictionaryPrevCodes[q]; - } - } else { - currentSequence[currentSequenceLength++] = currentSequence[0]; - } - } else if (code === 256) { - codeLength = 9; - nextCode = 258; - currentSequenceLength = 0; - continue; - } else { - this.eof = true; - delete this.lzwState; - break; - } - - if (hasPrev) { - dictionaryPrevCodes[nextCode] = prevCode; - dictionaryLengths[nextCode] = dictionaryLengths[prevCode] + 1; - dictionaryValues[nextCode] = currentSequence[0]; - nextCode++; - codeLength = - (nextCode + earlyChange) & (nextCode + earlyChange - 1) - ? codeLength - : Math.min( - Math.log(nextCode + earlyChange) / 0.6931471805599453 + 1, - 12 - ) | 0; - } - prevCode = code; - - decodedLength += currentSequenceLength; - if (estimatedDecodedSize < decodedLength) { - do { - estimatedDecodedSize += decodedSizeDelta; - } while (estimatedDecodedSize < decodedLength); - buffer = this.ensureBuffer(this.bufferLength + estimatedDecodedSize); - } - for (j = 0; j < currentSequenceLength; j++) { - buffer[currentBufferLength++] = currentSequence[j]; - } - } - lzwState.nextCode = nextCode; - lzwState.codeLength = codeLength; - lzwState.prevCode = prevCode; - lzwState.currentSequenceLength = currentSequenceLength; - - this.bufferLength = currentBufferLength; - }; - - return LZWStream; -})(); - var NullStream = (function NullStreamClosure() { // eslint-disable-next-line no-shadow function NullStream() { @@ -1350,7 +1213,6 @@ export { DecodeStream, DecryptStream, FlateStream, - LZWStream, NullStream, PredictorStream, RunLengthStream, From 1f9b134c6a628197fec3a0d738ac5c288db35f63 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 27 Apr 2021 12:58:48 +0200 Subject: [PATCH 02/30] Enable the `no-var` rule in the `src/core/src/core/lzw_stream.js` file --- src/core/lzw_stream.js | 51 +++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/src/core/lzw_stream.js b/src/core/lzw_stream.js index 4d3a8cdce3660..22ac196a052b1 100644 --- a/src/core/lzw_stream.js +++ b/src/core/lzw_stream.js @@ -12,11 +12,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* eslint-disable no-var */ import { DecodeStream } from "./stream.js"; -var LZWStream = (function LZWStreamClosure() { +const LZWStream = (function LZWStreamClosure() { // eslint-disable-next-line no-shadow function LZWStream(str, maybeLength, earlyChange) { this.str = str; @@ -24,8 +23,8 @@ var LZWStream = (function LZWStreamClosure() { this.cachedData = 0; this.bitsCached = 0; - var maxLzwDictionarySize = 4096; - var lzwState = { + const maxLzwDictionarySize = 4096; + const lzwState = { earlyChange, codeLength: 9, nextCode: 258, @@ -35,7 +34,7 @@ var LZWStream = (function LZWStreamClosure() { currentSequence: new Uint8Array(maxLzwDictionarySize), currentSequenceLength: 0, }; - for (var i = 0; i < 256; ++i) { + for (let i = 0; i < 256; ++i) { lzwState.dictionaryValues[i] = i; lzwState.dictionaryLengths[i] = 1; } @@ -47,10 +46,10 @@ var LZWStream = (function LZWStreamClosure() { LZWStream.prototype = Object.create(DecodeStream.prototype); LZWStream.prototype.readBits = function LZWStream_readBits(n) { - var bitsCached = this.bitsCached; - var cachedData = this.cachedData; + let bitsCached = this.bitsCached; + let cachedData = this.cachedData; while (bitsCached < n) { - var c = this.str.getByte(); + const c = this.str.getByte(); if (c === -1) { this.eof = true; return null; @@ -65,33 +64,33 @@ var LZWStream = (function LZWStreamClosure() { }; LZWStream.prototype.readBlock = function LZWStream_readBlock() { - var blockSize = 512; - var estimatedDecodedSize = blockSize * 2, + const blockSize = 512, decodedSizeDelta = blockSize; - var i, j, q; + let estimatedDecodedSize = blockSize * 2; + let i, j, q; - var lzwState = this.lzwState; + const lzwState = this.lzwState; if (!lzwState) { return; // eof was found } - var earlyChange = lzwState.earlyChange; - var nextCode = lzwState.nextCode; - var dictionaryValues = lzwState.dictionaryValues; - var dictionaryLengths = lzwState.dictionaryLengths; - var dictionaryPrevCodes = lzwState.dictionaryPrevCodes; - var codeLength = lzwState.codeLength; - var prevCode = lzwState.prevCode; - var currentSequence = lzwState.currentSequence; - var currentSequenceLength = lzwState.currentSequenceLength; + const earlyChange = lzwState.earlyChange; + let nextCode = lzwState.nextCode; + const dictionaryValues = lzwState.dictionaryValues; + const dictionaryLengths = lzwState.dictionaryLengths; + const dictionaryPrevCodes = lzwState.dictionaryPrevCodes; + let codeLength = lzwState.codeLength; + let prevCode = lzwState.prevCode; + const currentSequence = lzwState.currentSequence; + let currentSequenceLength = lzwState.currentSequenceLength; - var decodedLength = 0; - var currentBufferLength = this.bufferLength; - var buffer = this.ensureBuffer(this.bufferLength + estimatedDecodedSize); + let decodedLength = 0; + let currentBufferLength = this.bufferLength; + let buffer = this.ensureBuffer(this.bufferLength + estimatedDecodedSize); for (i = 0; i < blockSize; i++) { - var code = this.readBits(codeLength); - var hasPrev = currentSequenceLength > 0; + const code = this.readBits(codeLength); + const hasPrev = currentSequenceLength > 0; if (code < 256) { currentSequence[0] = code; currentSequenceLength = 1; From 1f0685cee6450f2b5c7a438e6d7c87f07655fbb5 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 27 Apr 2021 13:00:05 +0200 Subject: [PATCH 03/30] Convert `src/core/lzw_stream.js` to use standard classes --- src/core/lzw_stream.js | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/core/lzw_stream.js b/src/core/lzw_stream.js index 22ac196a052b1..3ea98adeac814 100644 --- a/src/core/lzw_stream.js +++ b/src/core/lzw_stream.js @@ -15,9 +15,10 @@ import { DecodeStream } from "./stream.js"; -const LZWStream = (function LZWStreamClosure() { - // eslint-disable-next-line no-shadow - function LZWStream(str, maybeLength, earlyChange) { +class LZWStream extends DecodeStream { + constructor(str, maybeLength, earlyChange) { + super(maybeLength); + this.str = str; this.dict = str.dict; this.cachedData = 0; @@ -39,13 +40,9 @@ const LZWStream = (function LZWStreamClosure() { lzwState.dictionaryLengths[i] = 1; } this.lzwState = lzwState; - - DecodeStream.call(this, maybeLength); } - LZWStream.prototype = Object.create(DecodeStream.prototype); - - LZWStream.prototype.readBits = function LZWStream_readBits(n) { + readBits(n) { let bitsCached = this.bitsCached; let cachedData = this.cachedData; while (bitsCached < n) { @@ -61,9 +58,9 @@ const LZWStream = (function LZWStreamClosure() { this.cachedData = cachedData; this.lastCode = null; return (cachedData >>> bitsCached) & ((1 << n) - 1); - }; + } - LZWStream.prototype.readBlock = function LZWStream_readBlock() { + readBlock() { const blockSize = 512, decodedSizeDelta = blockSize; let estimatedDecodedSize = blockSize * 2; @@ -147,9 +144,7 @@ const LZWStream = (function LZWStreamClosure() { lzwState.currentSequenceLength = currentSequenceLength; this.bufferLength = currentBufferLength; - }; - - return LZWStream; -})(); + } +} export { LZWStream }; From 342b0c1bbcfdcda300c66d9a9987b950594d45f9 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 27 Apr 2021 13:04:07 +0200 Subject: [PATCH 04/30] Move the `RunLengthStream` from `src/core/stream.js` and into its own file --- src/core/parser.js | 2 +- src/core/run_length_stream.js | 67 +++++++++++++++++++++++++++++++++++ src/core/stream.js | 49 ------------------------- 3 files changed, 68 insertions(+), 50 deletions(-) create mode 100644 src/core/run_length_stream.js diff --git a/src/core/parser.js b/src/core/parser.js index 5c79654b0dbcb..a925aa9471ef4 100644 --- a/src/core/parser.js +++ b/src/core/parser.js @@ -19,7 +19,6 @@ import { FlateStream, NullStream, PredictorStream, - RunLengthStream, } from "./stream.js"; import { assert, @@ -47,6 +46,7 @@ import { Jbig2Stream } from "./jbig2_stream.js"; import { JpegStream } from "./jpeg_stream.js"; import { JpxStream } from "./jpx_stream.js"; import { LZWStream } from "./lzw_stream.js"; +import { RunLengthStream } from "./run_length_stream.js"; const MAX_LENGTH_TO_CACHE = 1000; const MAX_ADLER32_LENGTH = 5552; diff --git a/src/core/run_length_stream.js b/src/core/run_length_stream.js new file mode 100644 index 0000000000000..22eb8d769b330 --- /dev/null +++ b/src/core/run_length_stream.js @@ -0,0 +1,67 @@ +/* Copyright 2012 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* eslint-disable no-var */ + +import { DecodeStream } from "./stream.js"; + +var RunLengthStream = (function RunLengthStreamClosure() { + // eslint-disable-next-line no-shadow + function RunLengthStream(str, maybeLength) { + this.str = str; + this.dict = str.dict; + + DecodeStream.call(this, maybeLength); + } + + RunLengthStream.prototype = Object.create(DecodeStream.prototype); + + RunLengthStream.prototype.readBlock = function RunLengthStream_readBlock() { + // The repeatHeader has following format. The first byte defines type of run + // and amount of bytes to repeat/copy: n = 0 through 127 - copy next n bytes + // (in addition to the second byte from the header), n = 129 through 255 - + // duplicate the second byte from the header (257 - n) times, n = 128 - end. + var repeatHeader = this.str.getBytes(2); + if (!repeatHeader || repeatHeader.length < 2 || repeatHeader[0] === 128) { + this.eof = true; + return; + } + + var buffer; + var bufferLength = this.bufferLength; + var n = repeatHeader[0]; + if (n < 128) { + // copy n bytes + buffer = this.ensureBuffer(bufferLength + n + 1); + buffer[bufferLength++] = repeatHeader[1]; + if (n > 0) { + var source = this.str.getBytes(n); + buffer.set(source, bufferLength); + bufferLength += n; + } + } else { + n = 257 - n; + var b = repeatHeader[1]; + buffer = this.ensureBuffer(bufferLength + n + 1); + for (var i = 0; i < n; i++) { + buffer[bufferLength++] = b; + } + } + this.bufferLength = bufferLength; + }; + + return RunLengthStream; +})(); + +export { RunLengthStream }; diff --git a/src/core/stream.js b/src/core/stream.js index 258f0205e7642..54321d23a590f 100644 --- a/src/core/stream.js +++ b/src/core/stream.js @@ -1148,54 +1148,6 @@ var AsciiHexStream = (function AsciiHexStreamClosure() { return AsciiHexStream; })(); -var RunLengthStream = (function RunLengthStreamClosure() { - // eslint-disable-next-line no-shadow - function RunLengthStream(str, maybeLength) { - this.str = str; - this.dict = str.dict; - - DecodeStream.call(this, maybeLength); - } - - RunLengthStream.prototype = Object.create(DecodeStream.prototype); - - RunLengthStream.prototype.readBlock = function RunLengthStream_readBlock() { - // The repeatHeader has following format. The first byte defines type of run - // and amount of bytes to repeat/copy: n = 0 through 127 - copy next n bytes - // (in addition to the second byte from the header), n = 129 through 255 - - // duplicate the second byte from the header (257 - n) times, n = 128 - end. - var repeatHeader = this.str.getBytes(2); - if (!repeatHeader || repeatHeader.length < 2 || repeatHeader[0] === 128) { - this.eof = true; - return; - } - - var buffer; - var bufferLength = this.bufferLength; - var n = repeatHeader[0]; - if (n < 128) { - // copy n bytes - buffer = this.ensureBuffer(bufferLength + n + 1); - buffer[bufferLength++] = repeatHeader[1]; - if (n > 0) { - var source = this.str.getBytes(n); - buffer.set(source, bufferLength); - bufferLength += n; - } - } else { - n = 257 - n; - var b = repeatHeader[1]; - buffer = this.ensureBuffer(bufferLength + n + 1); - for (var i = 0; i < n; i++) { - buffer[bufferLength++] = b; - } - } - this.bufferLength = bufferLength; - }; - - return RunLengthStream; -})(); - var NullStream = (function NullStreamClosure() { // eslint-disable-next-line no-shadow function NullStream() { @@ -1215,7 +1167,6 @@ export { FlateStream, NullStream, PredictorStream, - RunLengthStream, Stream, StreamsSequenceStream, StringStream, From 66b898eb58d5c0f7b1e3747de0a6b39de079254e Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 27 Apr 2021 13:05:46 +0200 Subject: [PATCH 05/30] Enable the `no-var` rule in the ` src/core/run_length_stream.js` file --- src/core/run_length_stream.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/core/run_length_stream.js b/src/core/run_length_stream.js index 22eb8d769b330..8378f31798a05 100644 --- a/src/core/run_length_stream.js +++ b/src/core/run_length_stream.js @@ -12,11 +12,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* eslint-disable no-var */ import { DecodeStream } from "./stream.js"; -var RunLengthStream = (function RunLengthStreamClosure() { +const RunLengthStream = (function RunLengthStreamClosure() { // eslint-disable-next-line no-shadow function RunLengthStream(str, maybeLength) { this.str = str; @@ -32,29 +31,29 @@ var RunLengthStream = (function RunLengthStreamClosure() { // and amount of bytes to repeat/copy: n = 0 through 127 - copy next n bytes // (in addition to the second byte from the header), n = 129 through 255 - // duplicate the second byte from the header (257 - n) times, n = 128 - end. - var repeatHeader = this.str.getBytes(2); + const repeatHeader = this.str.getBytes(2); if (!repeatHeader || repeatHeader.length < 2 || repeatHeader[0] === 128) { this.eof = true; return; } - var buffer; - var bufferLength = this.bufferLength; - var n = repeatHeader[0]; + let buffer; + let bufferLength = this.bufferLength; + let n = repeatHeader[0]; if (n < 128) { // copy n bytes buffer = this.ensureBuffer(bufferLength + n + 1); buffer[bufferLength++] = repeatHeader[1]; if (n > 0) { - var source = this.str.getBytes(n); + const source = this.str.getBytes(n); buffer.set(source, bufferLength); bufferLength += n; } } else { n = 257 - n; - var b = repeatHeader[1]; + const b = repeatHeader[1]; buffer = this.ensureBuffer(bufferLength + n + 1); - for (var i = 0; i < n; i++) { + for (let i = 0; i < n; i++) { buffer[bufferLength++] = b; } } From 704514c7cd3a216f02ee8708c63a470d60e1002a Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 27 Apr 2021 13:07:39 +0200 Subject: [PATCH 06/30] Convert `src/core/run_length_stream.js` to use standard classes --- src/core/run_length_stream.js | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/core/run_length_stream.js b/src/core/run_length_stream.js index 8378f31798a05..c32d3fcf5550c 100644 --- a/src/core/run_length_stream.js +++ b/src/core/run_length_stream.js @@ -15,18 +15,15 @@ import { DecodeStream } from "./stream.js"; -const RunLengthStream = (function RunLengthStreamClosure() { - // eslint-disable-next-line no-shadow - function RunLengthStream(str, maybeLength) { +class RunLengthStream extends DecodeStream { + constructor(str, maybeLength) { + super(maybeLength); + this.str = str; this.dict = str.dict; - - DecodeStream.call(this, maybeLength); } - RunLengthStream.prototype = Object.create(DecodeStream.prototype); - - RunLengthStream.prototype.readBlock = function RunLengthStream_readBlock() { + readBlock() { // The repeatHeader has following format. The first byte defines type of run // and amount of bytes to repeat/copy: n = 0 through 127 - copy next n bytes // (in addition to the second byte from the header), n = 129 through 255 - @@ -58,9 +55,7 @@ const RunLengthStream = (function RunLengthStreamClosure() { } } this.bufferLength = bufferLength; - }; - - return RunLengthStream; -})(); + } +} export { RunLengthStream }; From d63df04854045c2b53ee903c57452398f92a6b15 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 27 Apr 2021 13:12:55 +0200 Subject: [PATCH 07/30] Move the `AsciiHexStream` from `src/core/stream.js` and into its own file --- src/core/ascii_hex_stream.js | 86 ++++++++++++++++++++++++++++++++++++ src/core/parser.js | 2 +- src/core/stream.js | 68 ---------------------------- 3 files changed, 87 insertions(+), 69 deletions(-) create mode 100644 src/core/ascii_hex_stream.js diff --git a/src/core/ascii_hex_stream.js b/src/core/ascii_hex_stream.js new file mode 100644 index 0000000000000..7446672f3c0ec --- /dev/null +++ b/src/core/ascii_hex_stream.js @@ -0,0 +1,86 @@ +/* Copyright 2012 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* eslint-disable no-var */ + +import { DecodeStream } from "./stream.js"; + +var AsciiHexStream = (function AsciiHexStreamClosure() { + // eslint-disable-next-line no-shadow + function AsciiHexStream(str, maybeLength) { + this.str = str; + this.dict = str.dict; + + this.firstDigit = -1; + + // Most streams increase in size when decoded, but AsciiHex streams shrink + // by 50%. + if (maybeLength) { + maybeLength = 0.5 * maybeLength; + } + DecodeStream.call(this, maybeLength); + } + + AsciiHexStream.prototype = Object.create(DecodeStream.prototype); + + AsciiHexStream.prototype.readBlock = function AsciiHexStream_readBlock() { + var UPSTREAM_BLOCK_SIZE = 8000; + var bytes = this.str.getBytes(UPSTREAM_BLOCK_SIZE); + if (!bytes.length) { + this.eof = true; + return; + } + + var maxDecodeLength = (bytes.length + 1) >> 1; + var buffer = this.ensureBuffer(this.bufferLength + maxDecodeLength); + var bufferLength = this.bufferLength; + + var firstDigit = this.firstDigit; + for (var i = 0, ii = bytes.length; i < ii; i++) { + var ch = bytes[i], + digit; + if (ch >= /* '0' = */ 0x30 && ch <= /* '9' = */ 0x39) { + digit = ch & 0x0f; + } else if ( + (ch >= /* 'A' = */ 0x41 && ch <= /* 'Z' = */ 0x46) || + (ch >= /* 'a' = */ 0x61 && ch <= /* 'z' = */ 0x66) + ) { + digit = (ch & 0x0f) + 9; + } else if (ch === /* '>' = */ 0x3e) { + this.eof = true; + break; + } else { + // Probably whitespace, ignoring. + continue; + } + if (firstDigit < 0) { + firstDigit = digit; + } else { + buffer[bufferLength++] = (firstDigit << 4) | digit; + firstDigit = -1; + } + } + if (firstDigit >= 0 && this.eof) { + // incomplete byte + buffer[bufferLength++] = firstDigit << 4; + firstDigit = -1; + } + this.firstDigit = firstDigit; + this.bufferLength = bufferLength; + }; + + return AsciiHexStream; +})(); + +export { AsciiHexStream }; diff --git a/src/core/parser.js b/src/core/parser.js index a925aa9471ef4..048deae7fd3ff 100644 --- a/src/core/parser.js +++ b/src/core/parser.js @@ -15,7 +15,6 @@ import { Ascii85Stream, - AsciiHexStream, FlateStream, NullStream, PredictorStream, @@ -41,6 +40,7 @@ import { Ref, } from "./primitives.js"; import { isWhiteSpace, MissingDataException } from "./core_utils.js"; +import { AsciiHexStream } from "./ascii_hex_stream.js"; import { CCITTFaxStream } from "./ccitt_stream.js"; import { Jbig2Stream } from "./jbig2_stream.js"; import { JpegStream } from "./jpeg_stream.js"; diff --git a/src/core/stream.js b/src/core/stream.js index 54321d23a590f..1c09cb8aaba9b 100644 --- a/src/core/stream.js +++ b/src/core/stream.js @@ -1081,73 +1081,6 @@ var Ascii85Stream = (function Ascii85StreamClosure() { return Ascii85Stream; })(); -var AsciiHexStream = (function AsciiHexStreamClosure() { - // eslint-disable-next-line no-shadow - function AsciiHexStream(str, maybeLength) { - this.str = str; - this.dict = str.dict; - - this.firstDigit = -1; - - // Most streams increase in size when decoded, but AsciiHex streams shrink - // by 50%. - if (maybeLength) { - maybeLength = 0.5 * maybeLength; - } - DecodeStream.call(this, maybeLength); - } - - AsciiHexStream.prototype = Object.create(DecodeStream.prototype); - - AsciiHexStream.prototype.readBlock = function AsciiHexStream_readBlock() { - var UPSTREAM_BLOCK_SIZE = 8000; - var bytes = this.str.getBytes(UPSTREAM_BLOCK_SIZE); - if (!bytes.length) { - this.eof = true; - return; - } - - var maxDecodeLength = (bytes.length + 1) >> 1; - var buffer = this.ensureBuffer(this.bufferLength + maxDecodeLength); - var bufferLength = this.bufferLength; - - var firstDigit = this.firstDigit; - for (var i = 0, ii = bytes.length; i < ii; i++) { - var ch = bytes[i], - digit; - if (ch >= /* '0' = */ 0x30 && ch <= /* '9' = */ 0x39) { - digit = ch & 0x0f; - } else if ( - (ch >= /* 'A' = */ 0x41 && ch <= /* 'Z' = */ 0x46) || - (ch >= /* 'a' = */ 0x61 && ch <= /* 'z' = */ 0x66) - ) { - digit = (ch & 0x0f) + 9; - } else if (ch === /* '>' = */ 0x3e) { - this.eof = true; - break; - } else { - // Probably whitespace, ignoring. - continue; - } - if (firstDigit < 0) { - firstDigit = digit; - } else { - buffer[bufferLength++] = (firstDigit << 4) | digit; - firstDigit = -1; - } - } - if (firstDigit >= 0 && this.eof) { - // incomplete byte - buffer[bufferLength++] = firstDigit << 4; - firstDigit = -1; - } - this.firstDigit = firstDigit; - this.bufferLength = bufferLength; - }; - - return AsciiHexStream; -})(); - var NullStream = (function NullStreamClosure() { // eslint-disable-next-line no-shadow function NullStream() { @@ -1161,7 +1094,6 @@ var NullStream = (function NullStreamClosure() { export { Ascii85Stream, - AsciiHexStream, DecodeStream, DecryptStream, FlateStream, From 59591f8788dac221d0d59baf8709a4ee96ce8525 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 27 Apr 2021 13:15:00 +0200 Subject: [PATCH 08/30] Enable the `no-var` rule in the ` src/core/ascii_hex_stream.js` file --- src/core/ascii_hex_stream.js | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/core/ascii_hex_stream.js b/src/core/ascii_hex_stream.js index 7446672f3c0ec..07d1ee6f0a930 100644 --- a/src/core/ascii_hex_stream.js +++ b/src/core/ascii_hex_stream.js @@ -12,11 +12,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* eslint-disable no-var */ import { DecodeStream } from "./stream.js"; -var AsciiHexStream = (function AsciiHexStreamClosure() { +const AsciiHexStream = (function AsciiHexStreamClosure() { // eslint-disable-next-line no-shadow function AsciiHexStream(str, maybeLength) { this.str = str; @@ -35,21 +34,21 @@ var AsciiHexStream = (function AsciiHexStreamClosure() { AsciiHexStream.prototype = Object.create(DecodeStream.prototype); AsciiHexStream.prototype.readBlock = function AsciiHexStream_readBlock() { - var UPSTREAM_BLOCK_SIZE = 8000; - var bytes = this.str.getBytes(UPSTREAM_BLOCK_SIZE); + const UPSTREAM_BLOCK_SIZE = 8000; + const bytes = this.str.getBytes(UPSTREAM_BLOCK_SIZE); if (!bytes.length) { this.eof = true; return; } - var maxDecodeLength = (bytes.length + 1) >> 1; - var buffer = this.ensureBuffer(this.bufferLength + maxDecodeLength); - var bufferLength = this.bufferLength; + const maxDecodeLength = (bytes.length + 1) >> 1; + const buffer = this.ensureBuffer(this.bufferLength + maxDecodeLength); + let bufferLength = this.bufferLength; - var firstDigit = this.firstDigit; - for (var i = 0, ii = bytes.length; i < ii; i++) { - var ch = bytes[i], - digit; + let firstDigit = this.firstDigit; + for (let i = 0, ii = bytes.length; i < ii; i++) { + const ch = bytes[i]; + let digit; if (ch >= /* '0' = */ 0x30 && ch <= /* '9' = */ 0x39) { digit = ch & 0x0f; } else if ( From d2227a7d105a7830fa8a5561b83f5093f3ecdd02 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 27 Apr 2021 13:17:24 +0200 Subject: [PATCH 09/30] Convert `src/core/ascii_hex_stream.js` to use standard classes --- src/core/ascii_hex_stream.js | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/src/core/ascii_hex_stream.js b/src/core/ascii_hex_stream.js index 07d1ee6f0a930..69e9021715110 100644 --- a/src/core/ascii_hex_stream.js +++ b/src/core/ascii_hex_stream.js @@ -15,25 +15,22 @@ import { DecodeStream } from "./stream.js"; -const AsciiHexStream = (function AsciiHexStreamClosure() { - // eslint-disable-next-line no-shadow - function AsciiHexStream(str, maybeLength) { - this.str = str; - this.dict = str.dict; - - this.firstDigit = -1; - +class AsciiHexStream extends DecodeStream { + constructor(str, maybeLength) { // Most streams increase in size when decoded, but AsciiHex streams shrink // by 50%. if (maybeLength) { maybeLength = 0.5 * maybeLength; } - DecodeStream.call(this, maybeLength); - } + super(maybeLength); - AsciiHexStream.prototype = Object.create(DecodeStream.prototype); + this.str = str; + this.dict = str.dict; + + this.firstDigit = -1; + } - AsciiHexStream.prototype.readBlock = function AsciiHexStream_readBlock() { + readBlock() { const UPSTREAM_BLOCK_SIZE = 8000; const bytes = this.str.getBytes(UPSTREAM_BLOCK_SIZE); if (!bytes.length) { @@ -46,8 +43,7 @@ const AsciiHexStream = (function AsciiHexStreamClosure() { let bufferLength = this.bufferLength; let firstDigit = this.firstDigit; - for (let i = 0, ii = bytes.length; i < ii; i++) { - const ch = bytes[i]; + for (const ch of bytes) { let digit; if (ch >= /* '0' = */ 0x30 && ch <= /* '9' = */ 0x39) { digit = ch & 0x0f; @@ -77,9 +73,7 @@ const AsciiHexStream = (function AsciiHexStreamClosure() { } this.firstDigit = firstDigit; this.bufferLength = bufferLength; - }; - - return AsciiHexStream; -})(); + } +} export { AsciiHexStream }; From 3294d4d5a33c9e1bcccf6743ccc87f146c85a1d3 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 27 Apr 2021 13:20:25 +0200 Subject: [PATCH 10/30] Move the `Ascii85Stream` from `src/core/stream.js` and into its own file --- src/core/ascii_85_stream.js | 105 ++++++++++++++++++++++++++++++++++++ src/core/parser.js | 8 +-- src/core/stream.js | 87 ------------------------------ 3 files changed, 107 insertions(+), 93 deletions(-) create mode 100644 src/core/ascii_85_stream.js diff --git a/src/core/ascii_85_stream.js b/src/core/ascii_85_stream.js new file mode 100644 index 0000000000000..78f13afd9ecd0 --- /dev/null +++ b/src/core/ascii_85_stream.js @@ -0,0 +1,105 @@ +/* Copyright 2012 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* eslint-disable no-var */ + +import { DecodeStream } from "./stream.js"; +import { isWhiteSpace } from "./core_utils.js"; + +var Ascii85Stream = (function Ascii85StreamClosure() { + // eslint-disable-next-line no-shadow + function Ascii85Stream(str, maybeLength) { + this.str = str; + this.dict = str.dict; + this.input = new Uint8Array(5); + + // Most streams increase in size when decoded, but Ascii85 streams + // typically shrink by ~20%. + if (maybeLength) { + maybeLength = 0.8 * maybeLength; + } + DecodeStream.call(this, maybeLength); + } + + Ascii85Stream.prototype = Object.create(DecodeStream.prototype); + + Ascii85Stream.prototype.readBlock = function Ascii85Stream_readBlock() { + var TILDA_CHAR = 0x7e; // '~' + var Z_LOWER_CHAR = 0x7a; // 'z' + var EOF = -1; + + var str = this.str; + + var c = str.getByte(); + while (isWhiteSpace(c)) { + c = str.getByte(); + } + + if (c === EOF || c === TILDA_CHAR) { + this.eof = true; + return; + } + + var bufferLength = this.bufferLength, + buffer; + var i; + + // special code for z + if (c === Z_LOWER_CHAR) { + buffer = this.ensureBuffer(bufferLength + 4); + for (i = 0; i < 4; ++i) { + buffer[bufferLength + i] = 0; + } + this.bufferLength += 4; + } else { + var input = this.input; + input[0] = c; + for (i = 1; i < 5; ++i) { + c = str.getByte(); + while (isWhiteSpace(c)) { + c = str.getByte(); + } + + input[i] = c; + + if (c === EOF || c === TILDA_CHAR) { + break; + } + } + buffer = this.ensureBuffer(bufferLength + i - 1); + this.bufferLength += i - 1; + + // partial ending; + if (i < 5) { + for (; i < 5; ++i) { + input[i] = 0x21 + 84; + } + this.eof = true; + } + var t = 0; + for (i = 0; i < 5; ++i) { + t = t * 85 + (input[i] - 0x21); + } + + for (i = 3; i >= 0; --i) { + buffer[bufferLength + i] = t & 0xff; + t >>= 8; + } + } + }; + + return Ascii85Stream; +})(); + +export { Ascii85Stream }; diff --git a/src/core/parser.js b/src/core/parser.js index 048deae7fd3ff..90796ad2206be 100644 --- a/src/core/parser.js +++ b/src/core/parser.js @@ -13,12 +13,6 @@ * limitations under the License. */ -import { - Ascii85Stream, - FlateStream, - NullStream, - PredictorStream, -} from "./stream.js"; import { assert, bytesToString, @@ -39,7 +33,9 @@ import { Name, Ref, } from "./primitives.js"; +import { FlateStream, NullStream, PredictorStream } from "./stream.js"; import { isWhiteSpace, MissingDataException } from "./core_utils.js"; +import { Ascii85Stream } from "./ascii_85_stream.js"; import { AsciiHexStream } from "./ascii_hex_stream.js"; import { CCITTFaxStream } from "./ccitt_stream.js"; import { Jbig2Stream } from "./jbig2_stream.js"; diff --git a/src/core/stream.js b/src/core/stream.js index 1c09cb8aaba9b..9005d02bfc247 100644 --- a/src/core/stream.js +++ b/src/core/stream.js @@ -22,7 +22,6 @@ import { FormatError, stringToBytes, unreachable } from "../shared/util.js"; import { isDict } from "./primitives.js"; -import { isWhiteSpace } from "./core_utils.js"; var Stream = (function StreamClosure() { // eslint-disable-next-line no-shadow @@ -996,91 +995,6 @@ var DecryptStream = (function DecryptStreamClosure() { return DecryptStream; })(); -var Ascii85Stream = (function Ascii85StreamClosure() { - // eslint-disable-next-line no-shadow - function Ascii85Stream(str, maybeLength) { - this.str = str; - this.dict = str.dict; - this.input = new Uint8Array(5); - - // Most streams increase in size when decoded, but Ascii85 streams - // typically shrink by ~20%. - if (maybeLength) { - maybeLength = 0.8 * maybeLength; - } - DecodeStream.call(this, maybeLength); - } - - Ascii85Stream.prototype = Object.create(DecodeStream.prototype); - - Ascii85Stream.prototype.readBlock = function Ascii85Stream_readBlock() { - var TILDA_CHAR = 0x7e; // '~' - var Z_LOWER_CHAR = 0x7a; // 'z' - var EOF = -1; - - var str = this.str; - - var c = str.getByte(); - while (isWhiteSpace(c)) { - c = str.getByte(); - } - - if (c === EOF || c === TILDA_CHAR) { - this.eof = true; - return; - } - - var bufferLength = this.bufferLength, - buffer; - var i; - - // special code for z - if (c === Z_LOWER_CHAR) { - buffer = this.ensureBuffer(bufferLength + 4); - for (i = 0; i < 4; ++i) { - buffer[bufferLength + i] = 0; - } - this.bufferLength += 4; - } else { - var input = this.input; - input[0] = c; - for (i = 1; i < 5; ++i) { - c = str.getByte(); - while (isWhiteSpace(c)) { - c = str.getByte(); - } - - input[i] = c; - - if (c === EOF || c === TILDA_CHAR) { - break; - } - } - buffer = this.ensureBuffer(bufferLength + i - 1); - this.bufferLength += i - 1; - - // partial ending; - if (i < 5) { - for (; i < 5; ++i) { - input[i] = 0x21 + 84; - } - this.eof = true; - } - var t = 0; - for (i = 0; i < 5; ++i) { - t = t * 85 + (input[i] - 0x21); - } - - for (i = 3; i >= 0; --i) { - buffer[bufferLength + i] = t & 0xff; - t >>= 8; - } - } - }; - - return Ascii85Stream; -})(); - var NullStream = (function NullStreamClosure() { // eslint-disable-next-line no-shadow function NullStream() { @@ -1093,7 +1007,6 @@ var NullStream = (function NullStreamClosure() { })(); export { - Ascii85Stream, DecodeStream, DecryptStream, FlateStream, From f6c7a6520283dd7d74f85ada2a2afe001d8d864b Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 27 Apr 2021 13:22:34 +0200 Subject: [PATCH 11/30] Enable the `no-var` rule in the `src/core/ascii_85_stream.js` file --- src/core/ascii_85_stream.js | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/core/ascii_85_stream.js b/src/core/ascii_85_stream.js index 78f13afd9ecd0..9b27cfd57f697 100644 --- a/src/core/ascii_85_stream.js +++ b/src/core/ascii_85_stream.js @@ -12,12 +12,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* eslint-disable no-var */ import { DecodeStream } from "./stream.js"; import { isWhiteSpace } from "./core_utils.js"; -var Ascii85Stream = (function Ascii85StreamClosure() { +const Ascii85Stream = (function Ascii85StreamClosure() { // eslint-disable-next-line no-shadow function Ascii85Stream(str, maybeLength) { this.str = str; @@ -35,13 +34,13 @@ var Ascii85Stream = (function Ascii85StreamClosure() { Ascii85Stream.prototype = Object.create(DecodeStream.prototype); Ascii85Stream.prototype.readBlock = function Ascii85Stream_readBlock() { - var TILDA_CHAR = 0x7e; // '~' - var Z_LOWER_CHAR = 0x7a; // 'z' - var EOF = -1; + const TILDA_CHAR = 0x7e; // '~' + const Z_LOWER_CHAR = 0x7a; // 'z' + const EOF = -1; - var str = this.str; + const str = this.str; - var c = str.getByte(); + let c = str.getByte(); while (isWhiteSpace(c)) { c = str.getByte(); } @@ -51,9 +50,8 @@ var Ascii85Stream = (function Ascii85StreamClosure() { return; } - var bufferLength = this.bufferLength, - buffer; - var i; + const bufferLength = this.bufferLength; + let buffer, i; // special code for z if (c === Z_LOWER_CHAR) { @@ -63,7 +61,7 @@ var Ascii85Stream = (function Ascii85StreamClosure() { } this.bufferLength += 4; } else { - var input = this.input; + const input = this.input; input[0] = c; for (i = 1; i < 5; ++i) { c = str.getByte(); @@ -87,7 +85,7 @@ var Ascii85Stream = (function Ascii85StreamClosure() { } this.eof = true; } - var t = 0; + let t = 0; for (i = 0; i < 5; ++i) { t = t * 85 + (input[i] - 0x21); } From cdb583b7644d8fec9c0b12afb37a7de4f52faed8 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 27 Apr 2021 13:26:42 +0200 Subject: [PATCH 12/30] Convert `src/core/ascii_85_stream.js` to use standard classes --- src/core/ascii_85_stream.js | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/core/ascii_85_stream.js b/src/core/ascii_85_stream.js index 9b27cfd57f697..159eae66ec858 100644 --- a/src/core/ascii_85_stream.js +++ b/src/core/ascii_85_stream.js @@ -16,24 +16,21 @@ import { DecodeStream } from "./stream.js"; import { isWhiteSpace } from "./core_utils.js"; -const Ascii85Stream = (function Ascii85StreamClosure() { - // eslint-disable-next-line no-shadow - function Ascii85Stream(str, maybeLength) { - this.str = str; - this.dict = str.dict; - this.input = new Uint8Array(5); - +class Ascii85Stream extends DecodeStream { + constructor(str, maybeLength) { // Most streams increase in size when decoded, but Ascii85 streams // typically shrink by ~20%. if (maybeLength) { maybeLength = 0.8 * maybeLength; } - DecodeStream.call(this, maybeLength); - } + super(maybeLength); - Ascii85Stream.prototype = Object.create(DecodeStream.prototype); + this.str = str; + this.dict = str.dict; + this.input = new Uint8Array(5); + } - Ascii85Stream.prototype.readBlock = function Ascii85Stream_readBlock() { + readBlock() { const TILDA_CHAR = 0x7e; // '~' const Z_LOWER_CHAR = 0x7a; // 'z' const EOF = -1; @@ -95,9 +92,7 @@ const Ascii85Stream = (function Ascii85StreamClosure() { t >>= 8; } } - }; - - return Ascii85Stream; -})(); + } +} export { Ascii85Stream }; From 28b0809e609b45cba1f954f5be43c5a30fb1d057 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 27 Apr 2021 13:31:13 +0200 Subject: [PATCH 13/30] Move the `DecryptStream` from `src/core/stream.js` and into its own file --- src/core/crypto.js | 2 +- src/core/decrypt_stream.js | 66 ++++++++++++++++++++++++++++++++++++++ src/core/stream.js | 48 --------------------------- 3 files changed, 67 insertions(+), 49 deletions(-) create mode 100644 src/core/decrypt_stream.js diff --git a/src/core/crypto.js b/src/core/crypto.js index 752e5e79d0075..dab3a1e5272ba 100644 --- a/src/core/crypto.js +++ b/src/core/crypto.js @@ -26,7 +26,7 @@ import { warn, } from "../shared/util.js"; import { isDict, isName, Name } from "./primitives.js"; -import { DecryptStream } from "./stream.js"; +import { DecryptStream } from "./decrypt_stream.js"; class ARCFourCipher { constructor(key) { diff --git a/src/core/decrypt_stream.js b/src/core/decrypt_stream.js new file mode 100644 index 0000000000000..68be79d2b435e --- /dev/null +++ b/src/core/decrypt_stream.js @@ -0,0 +1,66 @@ +/* Copyright 2012 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* eslint-disable no-var */ + +import { DecodeStream } from "./stream.js"; + +var DecryptStream = (function DecryptStreamClosure() { + // eslint-disable-next-line no-shadow + function DecryptStream(str, maybeLength, decrypt) { + this.str = str; + this.dict = str.dict; + this.decrypt = decrypt; + this.nextChunk = null; + this.initialized = false; + + DecodeStream.call(this, maybeLength); + } + + var chunkSize = 512; + + DecryptStream.prototype = Object.create(DecodeStream.prototype); + + DecryptStream.prototype.readBlock = function DecryptStream_readBlock() { + var chunk; + if (this.initialized) { + chunk = this.nextChunk; + } else { + chunk = this.str.getBytes(chunkSize); + this.initialized = true; + } + if (!chunk || chunk.length === 0) { + this.eof = true; + return; + } + this.nextChunk = this.str.getBytes(chunkSize); + var hasMoreData = this.nextChunk && this.nextChunk.length > 0; + + var decrypt = this.decrypt; + chunk = decrypt(chunk, !hasMoreData); + + var bufferLength = this.bufferLength; + var i, + n = chunk.length; + var buffer = this.ensureBuffer(bufferLength + n); + for (i = 0; i < n; i++) { + buffer[bufferLength++] = chunk[i]; + } + this.bufferLength = bufferLength; + }; + + return DecryptStream; +})(); + +export { DecryptStream }; diff --git a/src/core/stream.js b/src/core/stream.js index 9005d02bfc247..425da861e1634 100644 --- a/src/core/stream.js +++ b/src/core/stream.js @@ -948,53 +948,6 @@ var PredictorStream = (function PredictorStreamClosure() { return PredictorStream; })(); -var DecryptStream = (function DecryptStreamClosure() { - // eslint-disable-next-line no-shadow - function DecryptStream(str, maybeLength, decrypt) { - this.str = str; - this.dict = str.dict; - this.decrypt = decrypt; - this.nextChunk = null; - this.initialized = false; - - DecodeStream.call(this, maybeLength); - } - - var chunkSize = 512; - - DecryptStream.prototype = Object.create(DecodeStream.prototype); - - DecryptStream.prototype.readBlock = function DecryptStream_readBlock() { - var chunk; - if (this.initialized) { - chunk = this.nextChunk; - } else { - chunk = this.str.getBytes(chunkSize); - this.initialized = true; - } - if (!chunk || chunk.length === 0) { - this.eof = true; - return; - } - this.nextChunk = this.str.getBytes(chunkSize); - var hasMoreData = this.nextChunk && this.nextChunk.length > 0; - - var decrypt = this.decrypt; - chunk = decrypt(chunk, !hasMoreData); - - var bufferLength = this.bufferLength; - var i, - n = chunk.length; - var buffer = this.ensureBuffer(bufferLength + n); - for (i = 0; i < n; i++) { - buffer[bufferLength++] = chunk[i]; - } - this.bufferLength = bufferLength; - }; - - return DecryptStream; -})(); - var NullStream = (function NullStreamClosure() { // eslint-disable-next-line no-shadow function NullStream() { @@ -1008,7 +961,6 @@ var NullStream = (function NullStreamClosure() { export { DecodeStream, - DecryptStream, FlateStream, NullStream, PredictorStream, From a9476e7dd0a4308d338fd959aac74b0c5d9b4996 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 27 Apr 2021 13:34:42 +0200 Subject: [PATCH 14/30] Enable the `no-var` rule in the `src/core/decrypt_stream.js` file --- src/core/decrypt_stream.js | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/core/decrypt_stream.js b/src/core/decrypt_stream.js index 68be79d2b435e..c4daede47cf72 100644 --- a/src/core/decrypt_stream.js +++ b/src/core/decrypt_stream.js @@ -12,11 +12,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* eslint-disable no-var */ import { DecodeStream } from "./stream.js"; -var DecryptStream = (function DecryptStreamClosure() { +const DecryptStream = (function DecryptStreamClosure() { // eslint-disable-next-line no-shadow function DecryptStream(str, maybeLength, decrypt) { this.str = str; @@ -28,12 +27,12 @@ var DecryptStream = (function DecryptStreamClosure() { DecodeStream.call(this, maybeLength); } - var chunkSize = 512; + const chunkSize = 512; DecryptStream.prototype = Object.create(DecodeStream.prototype); DecryptStream.prototype.readBlock = function DecryptStream_readBlock() { - var chunk; + let chunk; if (this.initialized) { chunk = this.nextChunk; } else { @@ -45,16 +44,15 @@ var DecryptStream = (function DecryptStreamClosure() { return; } this.nextChunk = this.str.getBytes(chunkSize); - var hasMoreData = this.nextChunk && this.nextChunk.length > 0; + const hasMoreData = this.nextChunk && this.nextChunk.length > 0; - var decrypt = this.decrypt; + const decrypt = this.decrypt; chunk = decrypt(chunk, !hasMoreData); - var bufferLength = this.bufferLength; - var i, - n = chunk.length; - var buffer = this.ensureBuffer(bufferLength + n); - for (i = 0; i < n; i++) { + let bufferLength = this.bufferLength; + const n = chunk.length, + buffer = this.ensureBuffer(bufferLength + n); + for (let i = 0; i < n; i++) { buffer[bufferLength++] = chunk[i]; } this.bufferLength = bufferLength; From e938c05edb45335c03f2516ecf48dc12aab8675c Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 27 Apr 2021 13:35:59 +0200 Subject: [PATCH 15/30] Convert `src/core/decrypt_stream.js` to use standard classes --- src/core/decrypt_stream.js | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/core/decrypt_stream.js b/src/core/decrypt_stream.js index c4daede47cf72..cc5df1b66ac95 100644 --- a/src/core/decrypt_stream.js +++ b/src/core/decrypt_stream.js @@ -15,23 +15,20 @@ import { DecodeStream } from "./stream.js"; -const DecryptStream = (function DecryptStreamClosure() { - // eslint-disable-next-line no-shadow - function DecryptStream(str, maybeLength, decrypt) { +const chunkSize = 512; + +class DecryptStream extends DecodeStream { + constructor(str, maybeLength, decrypt) { + super(maybeLength); + this.str = str; this.dict = str.dict; this.decrypt = decrypt; this.nextChunk = null; this.initialized = false; - - DecodeStream.call(this, maybeLength); } - const chunkSize = 512; - - DecryptStream.prototype = Object.create(DecodeStream.prototype); - - DecryptStream.prototype.readBlock = function DecryptStream_readBlock() { + readBlock() { let chunk; if (this.initialized) { chunk = this.nextChunk; @@ -56,9 +53,7 @@ const DecryptStream = (function DecryptStreamClosure() { buffer[bufferLength++] = chunk[i]; } this.bufferLength = bufferLength; - }; - - return DecryptStream; -})(); + } +} export { DecryptStream }; From 66d9d83dcb00a6297401b05319f7f01b39a4606f Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 27 Apr 2021 13:41:45 +0200 Subject: [PATCH 16/30] Move the `PredictorStream` from `src/core/stream.js` and into its own file --- src/core/parser.js | 3 +- src/core/predictor_stream.js | 243 +++++++++++++++++++++++++++++++++++ src/core/stream.js | 224 -------------------------------- test/unit/stream_spec.js | 3 +- 4 files changed, 247 insertions(+), 226 deletions(-) create mode 100644 src/core/predictor_stream.js diff --git a/src/core/parser.js b/src/core/parser.js index 90796ad2206be..bae33d1788391 100644 --- a/src/core/parser.js +++ b/src/core/parser.js @@ -33,7 +33,7 @@ import { Name, Ref, } from "./primitives.js"; -import { FlateStream, NullStream, PredictorStream } from "./stream.js"; +import { FlateStream, NullStream } from "./stream.js"; import { isWhiteSpace, MissingDataException } from "./core_utils.js"; import { Ascii85Stream } from "./ascii_85_stream.js"; import { AsciiHexStream } from "./ascii_hex_stream.js"; @@ -42,6 +42,7 @@ import { Jbig2Stream } from "./jbig2_stream.js"; import { JpegStream } from "./jpeg_stream.js"; import { JpxStream } from "./jpx_stream.js"; import { LZWStream } from "./lzw_stream.js"; +import { PredictorStream } from "./predictor_stream.js"; import { RunLengthStream } from "./run_length_stream.js"; const MAX_LENGTH_TO_CACHE = 1000; diff --git a/src/core/predictor_stream.js b/src/core/predictor_stream.js new file mode 100644 index 0000000000000..e9683e7476e8d --- /dev/null +++ b/src/core/predictor_stream.js @@ -0,0 +1,243 @@ +/* Copyright 2012 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* eslint-disable no-var */ + +import { DecodeStream } from "./stream.js"; +import { FormatError } from "../shared/util.js"; +import { isDict } from "./primitives.js"; + +var PredictorStream = (function PredictorStreamClosure() { + // eslint-disable-next-line no-shadow + function PredictorStream(str, maybeLength, params) { + if (!isDict(params)) { + return str; // no prediction + } + var predictor = (this.predictor = params.get("Predictor") || 1); + + if (predictor <= 1) { + return str; // no prediction + } + if (predictor !== 2 && (predictor < 10 || predictor > 15)) { + throw new FormatError(`Unsupported predictor: ${predictor}`); + } + + if (predictor === 2) { + this.readBlock = this.readBlockTiff; + } else { + this.readBlock = this.readBlockPng; + } + + this.str = str; + this.dict = str.dict; + + var colors = (this.colors = params.get("Colors") || 1); + var bits = (this.bits = params.get("BitsPerComponent") || 8); + var columns = (this.columns = params.get("Columns") || 1); + + this.pixBytes = (colors * bits + 7) >> 3; + this.rowBytes = (columns * colors * bits + 7) >> 3; + + DecodeStream.call(this, maybeLength); + return this; + } + + PredictorStream.prototype = Object.create(DecodeStream.prototype); + + PredictorStream.prototype.readBlockTiff = function predictorStreamReadBlockTiff() { + var rowBytes = this.rowBytes; + + var bufferLength = this.bufferLength; + var buffer = this.ensureBuffer(bufferLength + rowBytes); + + var bits = this.bits; + var colors = this.colors; + + var rawBytes = this.str.getBytes(rowBytes); + this.eof = !rawBytes.length; + if (this.eof) { + return; + } + + var inbuf = 0, + outbuf = 0; + var inbits = 0, + outbits = 0; + var pos = bufferLength; + var i; + + if (bits === 1 && colors === 1) { + // Optimized version of the loop in the "else"-branch + // for 1 bit-per-component and 1 color TIFF images. + for (i = 0; i < rowBytes; ++i) { + var c = rawBytes[i] ^ inbuf; + c ^= c >> 1; + c ^= c >> 2; + c ^= c >> 4; + inbuf = (c & 1) << 7; + buffer[pos++] = c; + } + } else if (bits === 8) { + for (i = 0; i < colors; ++i) { + buffer[pos++] = rawBytes[i]; + } + for (; i < rowBytes; ++i) { + buffer[pos] = buffer[pos - colors] + rawBytes[i]; + pos++; + } + } else if (bits === 16) { + var bytesPerPixel = colors * 2; + for (i = 0; i < bytesPerPixel; ++i) { + buffer[pos++] = rawBytes[i]; + } + for (; i < rowBytes; i += 2) { + var sum = + ((rawBytes[i] & 0xff) << 8) + + (rawBytes[i + 1] & 0xff) + + ((buffer[pos - bytesPerPixel] & 0xff) << 8) + + (buffer[pos - bytesPerPixel + 1] & 0xff); + buffer[pos++] = (sum >> 8) & 0xff; + buffer[pos++] = sum & 0xff; + } + } else { + var compArray = new Uint8Array(colors + 1); + var bitMask = (1 << bits) - 1; + var j = 0, + k = bufferLength; + var columns = this.columns; + for (i = 0; i < columns; ++i) { + for (var kk = 0; kk < colors; ++kk) { + if (inbits < bits) { + inbuf = (inbuf << 8) | (rawBytes[j++] & 0xff); + inbits += 8; + } + compArray[kk] = + (compArray[kk] + (inbuf >> (inbits - bits))) & bitMask; + inbits -= bits; + outbuf = (outbuf << bits) | compArray[kk]; + outbits += bits; + if (outbits >= 8) { + buffer[k++] = (outbuf >> (outbits - 8)) & 0xff; + outbits -= 8; + } + } + } + if (outbits > 0) { + buffer[k++] = + (outbuf << (8 - outbits)) + (inbuf & ((1 << (8 - outbits)) - 1)); + } + } + this.bufferLength += rowBytes; + }; + + PredictorStream.prototype.readBlockPng = function predictorStreamReadBlockPng() { + var rowBytes = this.rowBytes; + var pixBytes = this.pixBytes; + + var predictor = this.str.getByte(); + var rawBytes = this.str.getBytes(rowBytes); + this.eof = !rawBytes.length; + if (this.eof) { + return; + } + + var bufferLength = this.bufferLength; + var buffer = this.ensureBuffer(bufferLength + rowBytes); + + var prevRow = buffer.subarray(bufferLength - rowBytes, bufferLength); + if (prevRow.length === 0) { + prevRow = new Uint8Array(rowBytes); + } + + var i, + j = bufferLength, + up, + c; + switch (predictor) { + case 0: + for (i = 0; i < rowBytes; ++i) { + buffer[j++] = rawBytes[i]; + } + break; + case 1: + for (i = 0; i < pixBytes; ++i) { + buffer[j++] = rawBytes[i]; + } + for (; i < rowBytes; ++i) { + buffer[j] = (buffer[j - pixBytes] + rawBytes[i]) & 0xff; + j++; + } + break; + case 2: + for (i = 0; i < rowBytes; ++i) { + buffer[j++] = (prevRow[i] + rawBytes[i]) & 0xff; + } + break; + case 3: + for (i = 0; i < pixBytes; ++i) { + buffer[j++] = (prevRow[i] >> 1) + rawBytes[i]; + } + for (; i < rowBytes; ++i) { + buffer[j] = + (((prevRow[i] + buffer[j - pixBytes]) >> 1) + rawBytes[i]) & 0xff; + j++; + } + break; + case 4: + // we need to save the up left pixels values. the simplest way + // is to create a new buffer + for (i = 0; i < pixBytes; ++i) { + up = prevRow[i]; + c = rawBytes[i]; + buffer[j++] = up + c; + } + for (; i < rowBytes; ++i) { + up = prevRow[i]; + var upLeft = prevRow[i - pixBytes]; + var left = buffer[j - pixBytes]; + var p = left + up - upLeft; + + var pa = p - left; + if (pa < 0) { + pa = -pa; + } + var pb = p - up; + if (pb < 0) { + pb = -pb; + } + var pc = p - upLeft; + if (pc < 0) { + pc = -pc; + } + + c = rawBytes[i]; + if (pa <= pb && pa <= pc) { + buffer[j++] = left + c; + } else if (pb <= pc) { + buffer[j++] = up + c; + } else { + buffer[j++] = upLeft + c; + } + } + break; + default: + throw new FormatError(`Unsupported predictor: ${predictor}`); + } + this.bufferLength += rowBytes; + }; + + return PredictorStream; +})(); + +export { PredictorStream }; diff --git a/src/core/stream.js b/src/core/stream.js index 425da861e1634..7f1195ad01265 100644 --- a/src/core/stream.js +++ b/src/core/stream.js @@ -21,7 +21,6 @@ /* eslint-disable no-var */ import { FormatError, stringToBytes, unreachable } from "../shared/util.js"; -import { isDict } from "./primitives.js"; var Stream = (function StreamClosure() { // eslint-disable-next-line no-shadow @@ -726,228 +725,6 @@ var FlateStream = (function FlateStreamClosure() { return FlateStream; })(); -var PredictorStream = (function PredictorStreamClosure() { - // eslint-disable-next-line no-shadow - function PredictorStream(str, maybeLength, params) { - if (!isDict(params)) { - return str; // no prediction - } - var predictor = (this.predictor = params.get("Predictor") || 1); - - if (predictor <= 1) { - return str; // no prediction - } - if (predictor !== 2 && (predictor < 10 || predictor > 15)) { - throw new FormatError(`Unsupported predictor: ${predictor}`); - } - - if (predictor === 2) { - this.readBlock = this.readBlockTiff; - } else { - this.readBlock = this.readBlockPng; - } - - this.str = str; - this.dict = str.dict; - - var colors = (this.colors = params.get("Colors") || 1); - var bits = (this.bits = params.get("BitsPerComponent") || 8); - var columns = (this.columns = params.get("Columns") || 1); - - this.pixBytes = (colors * bits + 7) >> 3; - this.rowBytes = (columns * colors * bits + 7) >> 3; - - DecodeStream.call(this, maybeLength); - return this; - } - - PredictorStream.prototype = Object.create(DecodeStream.prototype); - - PredictorStream.prototype.readBlockTiff = function predictorStreamReadBlockTiff() { - var rowBytes = this.rowBytes; - - var bufferLength = this.bufferLength; - var buffer = this.ensureBuffer(bufferLength + rowBytes); - - var bits = this.bits; - var colors = this.colors; - - var rawBytes = this.str.getBytes(rowBytes); - this.eof = !rawBytes.length; - if (this.eof) { - return; - } - - var inbuf = 0, - outbuf = 0; - var inbits = 0, - outbits = 0; - var pos = bufferLength; - var i; - - if (bits === 1 && colors === 1) { - // Optimized version of the loop in the "else"-branch - // for 1 bit-per-component and 1 color TIFF images. - for (i = 0; i < rowBytes; ++i) { - var c = rawBytes[i] ^ inbuf; - c ^= c >> 1; - c ^= c >> 2; - c ^= c >> 4; - inbuf = (c & 1) << 7; - buffer[pos++] = c; - } - } else if (bits === 8) { - for (i = 0; i < colors; ++i) { - buffer[pos++] = rawBytes[i]; - } - for (; i < rowBytes; ++i) { - buffer[pos] = buffer[pos - colors] + rawBytes[i]; - pos++; - } - } else if (bits === 16) { - var bytesPerPixel = colors * 2; - for (i = 0; i < bytesPerPixel; ++i) { - buffer[pos++] = rawBytes[i]; - } - for (; i < rowBytes; i += 2) { - var sum = - ((rawBytes[i] & 0xff) << 8) + - (rawBytes[i + 1] & 0xff) + - ((buffer[pos - bytesPerPixel] & 0xff) << 8) + - (buffer[pos - bytesPerPixel + 1] & 0xff); - buffer[pos++] = (sum >> 8) & 0xff; - buffer[pos++] = sum & 0xff; - } - } else { - var compArray = new Uint8Array(colors + 1); - var bitMask = (1 << bits) - 1; - var j = 0, - k = bufferLength; - var columns = this.columns; - for (i = 0; i < columns; ++i) { - for (var kk = 0; kk < colors; ++kk) { - if (inbits < bits) { - inbuf = (inbuf << 8) | (rawBytes[j++] & 0xff); - inbits += 8; - } - compArray[kk] = - (compArray[kk] + (inbuf >> (inbits - bits))) & bitMask; - inbits -= bits; - outbuf = (outbuf << bits) | compArray[kk]; - outbits += bits; - if (outbits >= 8) { - buffer[k++] = (outbuf >> (outbits - 8)) & 0xff; - outbits -= 8; - } - } - } - if (outbits > 0) { - buffer[k++] = - (outbuf << (8 - outbits)) + (inbuf & ((1 << (8 - outbits)) - 1)); - } - } - this.bufferLength += rowBytes; - }; - - PredictorStream.prototype.readBlockPng = function predictorStreamReadBlockPng() { - var rowBytes = this.rowBytes; - var pixBytes = this.pixBytes; - - var predictor = this.str.getByte(); - var rawBytes = this.str.getBytes(rowBytes); - this.eof = !rawBytes.length; - if (this.eof) { - return; - } - - var bufferLength = this.bufferLength; - var buffer = this.ensureBuffer(bufferLength + rowBytes); - - var prevRow = buffer.subarray(bufferLength - rowBytes, bufferLength); - if (prevRow.length === 0) { - prevRow = new Uint8Array(rowBytes); - } - - var i, - j = bufferLength, - up, - c; - switch (predictor) { - case 0: - for (i = 0; i < rowBytes; ++i) { - buffer[j++] = rawBytes[i]; - } - break; - case 1: - for (i = 0; i < pixBytes; ++i) { - buffer[j++] = rawBytes[i]; - } - for (; i < rowBytes; ++i) { - buffer[j] = (buffer[j - pixBytes] + rawBytes[i]) & 0xff; - j++; - } - break; - case 2: - for (i = 0; i < rowBytes; ++i) { - buffer[j++] = (prevRow[i] + rawBytes[i]) & 0xff; - } - break; - case 3: - for (i = 0; i < pixBytes; ++i) { - buffer[j++] = (prevRow[i] >> 1) + rawBytes[i]; - } - for (; i < rowBytes; ++i) { - buffer[j] = - (((prevRow[i] + buffer[j - pixBytes]) >> 1) + rawBytes[i]) & 0xff; - j++; - } - break; - case 4: - // we need to save the up left pixels values. the simplest way - // is to create a new buffer - for (i = 0; i < pixBytes; ++i) { - up = prevRow[i]; - c = rawBytes[i]; - buffer[j++] = up + c; - } - for (; i < rowBytes; ++i) { - up = prevRow[i]; - var upLeft = prevRow[i - pixBytes]; - var left = buffer[j - pixBytes]; - var p = left + up - upLeft; - - var pa = p - left; - if (pa < 0) { - pa = -pa; - } - var pb = p - up; - if (pb < 0) { - pb = -pb; - } - var pc = p - upLeft; - if (pc < 0) { - pc = -pc; - } - - c = rawBytes[i]; - if (pa <= pb && pa <= pc) { - buffer[j++] = left + c; - } else if (pb <= pc) { - buffer[j++] = up + c; - } else { - buffer[j++] = upLeft + c; - } - } - break; - default: - throw new FormatError(`Unsupported predictor: ${predictor}`); - } - this.bufferLength += rowBytes; - }; - - return PredictorStream; -})(); - var NullStream = (function NullStreamClosure() { // eslint-disable-next-line no-shadow function NullStream() { @@ -963,7 +740,6 @@ export { DecodeStream, FlateStream, NullStream, - PredictorStream, Stream, StreamsSequenceStream, StringStream, diff --git a/test/unit/stream_spec.js b/test/unit/stream_spec.js index 0fcd6d492dbe9..6ed5666546b5e 100644 --- a/test/unit/stream_spec.js +++ b/test/unit/stream_spec.js @@ -13,8 +13,9 @@ * limitations under the License. */ -import { PredictorStream, Stream } from "../../src/core/stream.js"; import { Dict } from "../../src/core/primitives.js"; +import { PredictorStream } from "../../src/core/predictor_stream.js"; +import { Stream } from "../../src/core/stream.js"; describe("stream", function () { beforeEach(function () { From b08f9a818281a03d635b594ca9432a35821c2c5c Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 27 Apr 2021 13:43:18 +0200 Subject: [PATCH 17/30] Enable the `no-var` rule in the `src/core/predictor_stream.js` file --- src/core/predictor_stream.js | 75 ++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 38 deletions(-) diff --git a/src/core/predictor_stream.js b/src/core/predictor_stream.js index e9683e7476e8d..ca3cabcd8a7c4 100644 --- a/src/core/predictor_stream.js +++ b/src/core/predictor_stream.js @@ -12,19 +12,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* eslint-disable no-var */ import { DecodeStream } from "./stream.js"; import { FormatError } from "../shared/util.js"; import { isDict } from "./primitives.js"; -var PredictorStream = (function PredictorStreamClosure() { +const PredictorStream = (function PredictorStreamClosure() { // eslint-disable-next-line no-shadow function PredictorStream(str, maybeLength, params) { if (!isDict(params)) { return str; // no prediction } - var predictor = (this.predictor = params.get("Predictor") || 1); + const predictor = (this.predictor = params.get("Predictor") || 1); if (predictor <= 1) { return str; // no prediction @@ -42,9 +41,9 @@ var PredictorStream = (function PredictorStreamClosure() { this.str = str; this.dict = str.dict; - var colors = (this.colors = params.get("Colors") || 1); - var bits = (this.bits = params.get("BitsPerComponent") || 8); - var columns = (this.columns = params.get("Columns") || 1); + const colors = (this.colors = params.get("Colors") || 1); + const bits = (this.bits = params.get("BitsPerComponent") || 8); + const columns = (this.columns = params.get("Columns") || 1); this.pixBytes = (colors * bits + 7) >> 3; this.rowBytes = (columns * colors * bits + 7) >> 3; @@ -56,32 +55,32 @@ var PredictorStream = (function PredictorStreamClosure() { PredictorStream.prototype = Object.create(DecodeStream.prototype); PredictorStream.prototype.readBlockTiff = function predictorStreamReadBlockTiff() { - var rowBytes = this.rowBytes; + const rowBytes = this.rowBytes; - var bufferLength = this.bufferLength; - var buffer = this.ensureBuffer(bufferLength + rowBytes); + const bufferLength = this.bufferLength; + const buffer = this.ensureBuffer(bufferLength + rowBytes); - var bits = this.bits; - var colors = this.colors; + const bits = this.bits; + const colors = this.colors; - var rawBytes = this.str.getBytes(rowBytes); + const rawBytes = this.str.getBytes(rowBytes); this.eof = !rawBytes.length; if (this.eof) { return; } - var inbuf = 0, + let inbuf = 0, outbuf = 0; - var inbits = 0, + let inbits = 0, outbits = 0; - var pos = bufferLength; - var i; + let pos = bufferLength; + let i; if (bits === 1 && colors === 1) { // Optimized version of the loop in the "else"-branch // for 1 bit-per-component and 1 color TIFF images. for (i = 0; i < rowBytes; ++i) { - var c = rawBytes[i] ^ inbuf; + let c = rawBytes[i] ^ inbuf; c ^= c >> 1; c ^= c >> 2; c ^= c >> 4; @@ -97,12 +96,12 @@ var PredictorStream = (function PredictorStreamClosure() { pos++; } } else if (bits === 16) { - var bytesPerPixel = colors * 2; + const bytesPerPixel = colors * 2; for (i = 0; i < bytesPerPixel; ++i) { buffer[pos++] = rawBytes[i]; } for (; i < rowBytes; i += 2) { - var sum = + const sum = ((rawBytes[i] & 0xff) << 8) + (rawBytes[i + 1] & 0xff) + ((buffer[pos - bytesPerPixel] & 0xff) << 8) + @@ -111,13 +110,13 @@ var PredictorStream = (function PredictorStreamClosure() { buffer[pos++] = sum & 0xff; } } else { - var compArray = new Uint8Array(colors + 1); - var bitMask = (1 << bits) - 1; - var j = 0, + const compArray = new Uint8Array(colors + 1); + const bitMask = (1 << bits) - 1; + let j = 0, k = bufferLength; - var columns = this.columns; + const columns = this.columns; for (i = 0; i < columns; ++i) { - for (var kk = 0; kk < colors; ++kk) { + for (let kk = 0; kk < colors; ++kk) { if (inbits < bits) { inbuf = (inbuf << 8) | (rawBytes[j++] & 0xff); inbits += 8; @@ -142,25 +141,25 @@ var PredictorStream = (function PredictorStreamClosure() { }; PredictorStream.prototype.readBlockPng = function predictorStreamReadBlockPng() { - var rowBytes = this.rowBytes; - var pixBytes = this.pixBytes; + const rowBytes = this.rowBytes; + const pixBytes = this.pixBytes; - var predictor = this.str.getByte(); - var rawBytes = this.str.getBytes(rowBytes); + const predictor = this.str.getByte(); + const rawBytes = this.str.getBytes(rowBytes); this.eof = !rawBytes.length; if (this.eof) { return; } - var bufferLength = this.bufferLength; - var buffer = this.ensureBuffer(bufferLength + rowBytes); + const bufferLength = this.bufferLength; + const buffer = this.ensureBuffer(bufferLength + rowBytes); - var prevRow = buffer.subarray(bufferLength - rowBytes, bufferLength); + let prevRow = buffer.subarray(bufferLength - rowBytes, bufferLength); if (prevRow.length === 0) { prevRow = new Uint8Array(rowBytes); } - var i, + let i, j = bufferLength, up, c; @@ -204,19 +203,19 @@ var PredictorStream = (function PredictorStreamClosure() { } for (; i < rowBytes; ++i) { up = prevRow[i]; - var upLeft = prevRow[i - pixBytes]; - var left = buffer[j - pixBytes]; - var p = left + up - upLeft; + const upLeft = prevRow[i - pixBytes]; + const left = buffer[j - pixBytes]; + const p = left + up - upLeft; - var pa = p - left; + let pa = p - left; if (pa < 0) { pa = -pa; } - var pb = p - up; + let pb = p - up; if (pb < 0) { pb = -pb; } - var pc = p - upLeft; + let pc = p - upLeft; if (pc < 0) { pc = -pc; } From 40c342ec6cf28c4e544cc4d4b3452a2354cdf38b Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 27 Apr 2021 13:46:11 +0200 Subject: [PATCH 18/30] Convert `src/core/predictor_stream.js` to use standard classes --- src/core/predictor_stream.js | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/core/predictor_stream.js b/src/core/predictor_stream.js index ca3cabcd8a7c4..1653833f88ab9 100644 --- a/src/core/predictor_stream.js +++ b/src/core/predictor_stream.js @@ -17,13 +17,12 @@ import { DecodeStream } from "./stream.js"; import { FormatError } from "../shared/util.js"; import { isDict } from "./primitives.js"; -const PredictorStream = (function PredictorStreamClosure() { - // eslint-disable-next-line no-shadow - function PredictorStream(str, maybeLength, params) { +class PredictorStream extends DecodeStream { + constructor(str, maybeLength, params) { if (!isDict(params)) { return str; // no prediction } - const predictor = (this.predictor = params.get("Predictor") || 1); + const predictor = params.get("Predictor") || 1; if (predictor <= 1) { return str; // no prediction @@ -31,6 +30,8 @@ const PredictorStream = (function PredictorStreamClosure() { if (predictor !== 2 && (predictor < 10 || predictor > 15)) { throw new FormatError(`Unsupported predictor: ${predictor}`); } + super(maybeLength); + this.predictor = predictor; if (predictor === 2) { this.readBlock = this.readBlockTiff; @@ -48,13 +49,10 @@ const PredictorStream = (function PredictorStreamClosure() { this.pixBytes = (colors * bits + 7) >> 3; this.rowBytes = (columns * colors * bits + 7) >> 3; - DecodeStream.call(this, maybeLength); return this; } - PredictorStream.prototype = Object.create(DecodeStream.prototype); - - PredictorStream.prototype.readBlockTiff = function predictorStreamReadBlockTiff() { + readBlockTiff() { const rowBytes = this.rowBytes; const bufferLength = this.bufferLength; @@ -138,9 +136,9 @@ const PredictorStream = (function PredictorStreamClosure() { } } this.bufferLength += rowBytes; - }; + } - PredictorStream.prototype.readBlockPng = function predictorStreamReadBlockPng() { + readBlockPng() { const rowBytes = this.rowBytes; const pixBytes = this.pixBytes; @@ -234,9 +232,7 @@ const PredictorStream = (function PredictorStreamClosure() { throw new FormatError(`Unsupported predictor: ${predictor}`); } this.bufferLength += rowBytes; - }; - - return PredictorStream; -})(); + } +} export { PredictorStream }; From 1e5bf352a5be1d2ba0c689643ca8f397b07611ff Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 27 Apr 2021 13:49:35 +0200 Subject: [PATCH 19/30] Move the `FlateStream` from `src/core/stream.js` and into its own file --- src/core/flate_stream.js | 409 +++++++++++++++++++++++++++++++++++++++ src/core/parser.js | 3 +- src/core/stream.js | 392 +------------------------------------ 3 files changed, 412 insertions(+), 392 deletions(-) create mode 100644 src/core/flate_stream.js diff --git a/src/core/flate_stream.js b/src/core/flate_stream.js new file mode 100644 index 0000000000000..566aadb92b8e3 --- /dev/null +++ b/src/core/flate_stream.js @@ -0,0 +1,409 @@ +/* Copyright 2012 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Copyright 1996-2003 Glyph & Cog, LLC + * + * The flate stream implementation contained in this file is a JavaScript port + * of XPDF's implementation, made available under the Apache 2.0 open source + * license. + */ +/* eslint-disable no-var */ + +import { DecodeStream } from "./stream.js"; +import { FormatError } from "../shared/util.js"; + +var FlateStream = (function FlateStreamClosure() { + // prettier-ignore + var codeLenCodeMap = new Int32Array([ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 + ]); + + // prettier-ignore + var lengthDecode = new Int32Array([ + 0x00003, 0x00004, 0x00005, 0x00006, 0x00007, 0x00008, 0x00009, 0x0000a, + 0x1000b, 0x1000d, 0x1000f, 0x10011, 0x20013, 0x20017, 0x2001b, 0x2001f, + 0x30023, 0x3002b, 0x30033, 0x3003b, 0x40043, 0x40053, 0x40063, 0x40073, + 0x50083, 0x500a3, 0x500c3, 0x500e3, 0x00102, 0x00102, 0x00102 + ]); + + // prettier-ignore + var distDecode = new Int32Array([ + 0x00001, 0x00002, 0x00003, 0x00004, 0x10005, 0x10007, 0x20009, 0x2000d, + 0x30011, 0x30019, 0x40021, 0x40031, 0x50041, 0x50061, 0x60081, 0x600c1, + 0x70101, 0x70181, 0x80201, 0x80301, 0x90401, 0x90601, 0xa0801, 0xa0c01, + 0xb1001, 0xb1801, 0xc2001, 0xc3001, 0xd4001, 0xd6001 + ]); + + // prettier-ignore + var fixedLitCodeTab = [new Int32Array([ + 0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c0, + 0x70108, 0x80060, 0x80020, 0x900a0, 0x80000, 0x80080, 0x80040, 0x900e0, + 0x70104, 0x80058, 0x80018, 0x90090, 0x70114, 0x80078, 0x80038, 0x900d0, + 0x7010c, 0x80068, 0x80028, 0x900b0, 0x80008, 0x80088, 0x80048, 0x900f0, + 0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c8, + 0x7010a, 0x80064, 0x80024, 0x900a8, 0x80004, 0x80084, 0x80044, 0x900e8, + 0x70106, 0x8005c, 0x8001c, 0x90098, 0x70116, 0x8007c, 0x8003c, 0x900d8, + 0x7010e, 0x8006c, 0x8002c, 0x900b8, 0x8000c, 0x8008c, 0x8004c, 0x900f8, + 0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c4, + 0x70109, 0x80062, 0x80022, 0x900a4, 0x80002, 0x80082, 0x80042, 0x900e4, + 0x70105, 0x8005a, 0x8001a, 0x90094, 0x70115, 0x8007a, 0x8003a, 0x900d4, + 0x7010d, 0x8006a, 0x8002a, 0x900b4, 0x8000a, 0x8008a, 0x8004a, 0x900f4, + 0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cc, + 0x7010b, 0x80066, 0x80026, 0x900ac, 0x80006, 0x80086, 0x80046, 0x900ec, + 0x70107, 0x8005e, 0x8001e, 0x9009c, 0x70117, 0x8007e, 0x8003e, 0x900dc, + 0x7010f, 0x8006e, 0x8002e, 0x900bc, 0x8000e, 0x8008e, 0x8004e, 0x900fc, + 0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c2, + 0x70108, 0x80061, 0x80021, 0x900a2, 0x80001, 0x80081, 0x80041, 0x900e2, + 0x70104, 0x80059, 0x80019, 0x90092, 0x70114, 0x80079, 0x80039, 0x900d2, + 0x7010c, 0x80069, 0x80029, 0x900b2, 0x80009, 0x80089, 0x80049, 0x900f2, + 0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900ca, + 0x7010a, 0x80065, 0x80025, 0x900aa, 0x80005, 0x80085, 0x80045, 0x900ea, + 0x70106, 0x8005d, 0x8001d, 0x9009a, 0x70116, 0x8007d, 0x8003d, 0x900da, + 0x7010e, 0x8006d, 0x8002d, 0x900ba, 0x8000d, 0x8008d, 0x8004d, 0x900fa, + 0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c6, + 0x70109, 0x80063, 0x80023, 0x900a6, 0x80003, 0x80083, 0x80043, 0x900e6, + 0x70105, 0x8005b, 0x8001b, 0x90096, 0x70115, 0x8007b, 0x8003b, 0x900d6, + 0x7010d, 0x8006b, 0x8002b, 0x900b6, 0x8000b, 0x8008b, 0x8004b, 0x900f6, + 0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900ce, + 0x7010b, 0x80067, 0x80027, 0x900ae, 0x80007, 0x80087, 0x80047, 0x900ee, + 0x70107, 0x8005f, 0x8001f, 0x9009e, 0x70117, 0x8007f, 0x8003f, 0x900de, + 0x7010f, 0x8006f, 0x8002f, 0x900be, 0x8000f, 0x8008f, 0x8004f, 0x900fe, + 0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c1, + 0x70108, 0x80060, 0x80020, 0x900a1, 0x80000, 0x80080, 0x80040, 0x900e1, + 0x70104, 0x80058, 0x80018, 0x90091, 0x70114, 0x80078, 0x80038, 0x900d1, + 0x7010c, 0x80068, 0x80028, 0x900b1, 0x80008, 0x80088, 0x80048, 0x900f1, + 0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c9, + 0x7010a, 0x80064, 0x80024, 0x900a9, 0x80004, 0x80084, 0x80044, 0x900e9, + 0x70106, 0x8005c, 0x8001c, 0x90099, 0x70116, 0x8007c, 0x8003c, 0x900d9, + 0x7010e, 0x8006c, 0x8002c, 0x900b9, 0x8000c, 0x8008c, 0x8004c, 0x900f9, + 0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c5, + 0x70109, 0x80062, 0x80022, 0x900a5, 0x80002, 0x80082, 0x80042, 0x900e5, + 0x70105, 0x8005a, 0x8001a, 0x90095, 0x70115, 0x8007a, 0x8003a, 0x900d5, + 0x7010d, 0x8006a, 0x8002a, 0x900b5, 0x8000a, 0x8008a, 0x8004a, 0x900f5, + 0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cd, + 0x7010b, 0x80066, 0x80026, 0x900ad, 0x80006, 0x80086, 0x80046, 0x900ed, + 0x70107, 0x8005e, 0x8001e, 0x9009d, 0x70117, 0x8007e, 0x8003e, 0x900dd, + 0x7010f, 0x8006e, 0x8002e, 0x900bd, 0x8000e, 0x8008e, 0x8004e, 0x900fd, + 0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c3, + 0x70108, 0x80061, 0x80021, 0x900a3, 0x80001, 0x80081, 0x80041, 0x900e3, + 0x70104, 0x80059, 0x80019, 0x90093, 0x70114, 0x80079, 0x80039, 0x900d3, + 0x7010c, 0x80069, 0x80029, 0x900b3, 0x80009, 0x80089, 0x80049, 0x900f3, + 0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900cb, + 0x7010a, 0x80065, 0x80025, 0x900ab, 0x80005, 0x80085, 0x80045, 0x900eb, + 0x70106, 0x8005d, 0x8001d, 0x9009b, 0x70116, 0x8007d, 0x8003d, 0x900db, + 0x7010e, 0x8006d, 0x8002d, 0x900bb, 0x8000d, 0x8008d, 0x8004d, 0x900fb, + 0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c7, + 0x70109, 0x80063, 0x80023, 0x900a7, 0x80003, 0x80083, 0x80043, 0x900e7, + 0x70105, 0x8005b, 0x8001b, 0x90097, 0x70115, 0x8007b, 0x8003b, 0x900d7, + 0x7010d, 0x8006b, 0x8002b, 0x900b7, 0x8000b, 0x8008b, 0x8004b, 0x900f7, + 0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900cf, + 0x7010b, 0x80067, 0x80027, 0x900af, 0x80007, 0x80087, 0x80047, 0x900ef, + 0x70107, 0x8005f, 0x8001f, 0x9009f, 0x70117, 0x8007f, 0x8003f, 0x900df, + 0x7010f, 0x8006f, 0x8002f, 0x900bf, 0x8000f, 0x8008f, 0x8004f, 0x900ff + ]), 9]; + + // prettier-ignore + var fixedDistCodeTab = [new Int32Array([ + 0x50000, 0x50010, 0x50008, 0x50018, 0x50004, 0x50014, 0x5000c, 0x5001c, + 0x50002, 0x50012, 0x5000a, 0x5001a, 0x50006, 0x50016, 0x5000e, 0x00000, + 0x50001, 0x50011, 0x50009, 0x50019, 0x50005, 0x50015, 0x5000d, 0x5001d, + 0x50003, 0x50013, 0x5000b, 0x5001b, 0x50007, 0x50017, 0x5000f, 0x00000 + ]), 5]; + + // eslint-disable-next-line no-shadow + function FlateStream(str, maybeLength) { + this.str = str; + this.dict = str.dict; + + var cmf = str.getByte(); + var flg = str.getByte(); + if (cmf === -1 || flg === -1) { + throw new FormatError(`Invalid header in flate stream: ${cmf}, ${flg}`); + } + if ((cmf & 0x0f) !== 0x08) { + throw new FormatError( + `Unknown compression method in flate stream: ${cmf}, ${flg}` + ); + } + if (((cmf << 8) + flg) % 31 !== 0) { + throw new FormatError(`Bad FCHECK in flate stream: ${cmf}, ${flg}`); + } + if (flg & 0x20) { + throw new FormatError(`FDICT bit set in flate stream: ${cmf}, ${flg}`); + } + + this.codeSize = 0; + this.codeBuf = 0; + + DecodeStream.call(this, maybeLength); + } + + FlateStream.prototype = Object.create(DecodeStream.prototype); + + FlateStream.prototype.getBits = function FlateStream_getBits(bits) { + var str = this.str; + var codeSize = this.codeSize; + var codeBuf = this.codeBuf; + + var b; + while (codeSize < bits) { + if ((b = str.getByte()) === -1) { + throw new FormatError("Bad encoding in flate stream"); + } + codeBuf |= b << codeSize; + codeSize += 8; + } + b = codeBuf & ((1 << bits) - 1); + this.codeBuf = codeBuf >> bits; + this.codeSize = codeSize -= bits; + + return b; + }; + + FlateStream.prototype.getCode = function FlateStream_getCode(table) { + var str = this.str; + var codes = table[0]; + var maxLen = table[1]; + var codeSize = this.codeSize; + var codeBuf = this.codeBuf; + + var b; + while (codeSize < maxLen) { + if ((b = str.getByte()) === -1) { + // premature end of stream. code might however still be valid. + // codeSize < codeLen check below guards against incomplete codeVal. + break; + } + codeBuf |= b << codeSize; + codeSize += 8; + } + var code = codes[codeBuf & ((1 << maxLen) - 1)]; + var codeLen = code >> 16; + var codeVal = code & 0xffff; + if (codeLen < 1 || codeSize < codeLen) { + throw new FormatError("Bad encoding in flate stream"); + } + this.codeBuf = codeBuf >> codeLen; + this.codeSize = codeSize - codeLen; + return codeVal; + }; + + FlateStream.prototype.generateHuffmanTable = function flateStreamGenerateHuffmanTable( + lengths + ) { + var n = lengths.length; + + // find max code length + var maxLen = 0; + var i; + for (i = 0; i < n; ++i) { + if (lengths[i] > maxLen) { + maxLen = lengths[i]; + } + } + + // build the table + var size = 1 << maxLen; + var codes = new Int32Array(size); + for ( + var len = 1, code = 0, skip = 2; + len <= maxLen; + ++len, code <<= 1, skip <<= 1 + ) { + for (var val = 0; val < n; ++val) { + if (lengths[val] === len) { + // bit-reverse the code + var code2 = 0; + var t = code; + for (i = 0; i < len; ++i) { + code2 = (code2 << 1) | (t & 1); + t >>= 1; + } + + // fill the table entries + for (i = code2; i < size; i += skip) { + codes[i] = (len << 16) | val; + } + ++code; + } + } + } + + return [codes, maxLen]; + }; + + FlateStream.prototype.readBlock = function FlateStream_readBlock() { + var buffer, len; + var str = this.str; + // read block header + var hdr = this.getBits(3); + if (hdr & 1) { + this.eof = true; + } + hdr >>= 1; + + if (hdr === 0) { + // uncompressed block + var b; + + if ((b = str.getByte()) === -1) { + throw new FormatError("Bad block header in flate stream"); + } + var blockLen = b; + if ((b = str.getByte()) === -1) { + throw new FormatError("Bad block header in flate stream"); + } + blockLen |= b << 8; + if ((b = str.getByte()) === -1) { + throw new FormatError("Bad block header in flate stream"); + } + var check = b; + if ((b = str.getByte()) === -1) { + throw new FormatError("Bad block header in flate stream"); + } + check |= b << 8; + if (check !== (~blockLen & 0xffff) && (blockLen !== 0 || check !== 0)) { + // Ignoring error for bad "empty" block (see issue 1277) + throw new FormatError("Bad uncompressed block length in flate stream"); + } + + this.codeBuf = 0; + this.codeSize = 0; + + const bufferLength = this.bufferLength, + end = bufferLength + blockLen; + buffer = this.ensureBuffer(end); + this.bufferLength = end; + + if (blockLen === 0) { + if (str.peekByte() === -1) { + this.eof = true; + } + } else { + const block = str.getBytes(blockLen); + buffer.set(block, bufferLength); + if (block.length < blockLen) { + this.eof = true; + } + } + return; + } + + var litCodeTable; + var distCodeTable; + if (hdr === 1) { + // compressed block, fixed codes + litCodeTable = fixedLitCodeTab; + distCodeTable = fixedDistCodeTab; + } else if (hdr === 2) { + // compressed block, dynamic codes + var numLitCodes = this.getBits(5) + 257; + var numDistCodes = this.getBits(5) + 1; + var numCodeLenCodes = this.getBits(4) + 4; + + // build the code lengths code table + var codeLenCodeLengths = new Uint8Array(codeLenCodeMap.length); + + var i; + for (i = 0; i < numCodeLenCodes; ++i) { + codeLenCodeLengths[codeLenCodeMap[i]] = this.getBits(3); + } + var codeLenCodeTab = this.generateHuffmanTable(codeLenCodeLengths); + + // build the literal and distance code tables + len = 0; + i = 0; + var codes = numLitCodes + numDistCodes; + var codeLengths = new Uint8Array(codes); + var bitsLength, bitsOffset, what; + while (i < codes) { + var code = this.getCode(codeLenCodeTab); + if (code === 16) { + bitsLength = 2; + bitsOffset = 3; + what = len; + } else if (code === 17) { + bitsLength = 3; + bitsOffset = 3; + what = len = 0; + } else if (code === 18) { + bitsLength = 7; + bitsOffset = 11; + what = len = 0; + } else { + codeLengths[i++] = len = code; + continue; + } + + var repeatLength = this.getBits(bitsLength) + bitsOffset; + while (repeatLength-- > 0) { + codeLengths[i++] = what; + } + } + + litCodeTable = this.generateHuffmanTable( + codeLengths.subarray(0, numLitCodes) + ); + distCodeTable = this.generateHuffmanTable( + codeLengths.subarray(numLitCodes, codes) + ); + } else { + throw new FormatError("Unknown block type in flate stream"); + } + + buffer = this.buffer; + var limit = buffer ? buffer.length : 0; + var pos = this.bufferLength; + while (true) { + var code1 = this.getCode(litCodeTable); + if (code1 < 256) { + if (pos + 1 >= limit) { + buffer = this.ensureBuffer(pos + 1); + limit = buffer.length; + } + buffer[pos++] = code1; + continue; + } + if (code1 === 256) { + this.bufferLength = pos; + return; + } + code1 -= 257; + code1 = lengthDecode[code1]; + var code2 = code1 >> 16; + if (code2 > 0) { + code2 = this.getBits(code2); + } + len = (code1 & 0xffff) + code2; + code1 = this.getCode(distCodeTable); + code1 = distDecode[code1]; + code2 = code1 >> 16; + if (code2 > 0) { + code2 = this.getBits(code2); + } + var dist = (code1 & 0xffff) + code2; + if (pos + len >= limit) { + buffer = this.ensureBuffer(pos + len); + limit = buffer.length; + } + for (var k = 0; k < len; ++k, ++pos) { + buffer[pos] = buffer[pos - dist]; + } + } + }; + + return FlateStream; +})(); + +export { FlateStream }; diff --git a/src/core/parser.js b/src/core/parser.js index bae33d1788391..24b5cabf5fc21 100644 --- a/src/core/parser.js +++ b/src/core/parser.js @@ -33,15 +33,16 @@ import { Name, Ref, } from "./primitives.js"; -import { FlateStream, NullStream } from "./stream.js"; import { isWhiteSpace, MissingDataException } from "./core_utils.js"; import { Ascii85Stream } from "./ascii_85_stream.js"; import { AsciiHexStream } from "./ascii_hex_stream.js"; import { CCITTFaxStream } from "./ccitt_stream.js"; +import { FlateStream } from "./flate_stream.js"; import { Jbig2Stream } from "./jbig2_stream.js"; import { JpegStream } from "./jpeg_stream.js"; import { JpxStream } from "./jpx_stream.js"; import { LZWStream } from "./lzw_stream.js"; +import { NullStream } from "./stream.js"; import { PredictorStream } from "./predictor_stream.js"; import { RunLengthStream } from "./run_length_stream.js"; diff --git a/src/core/stream.js b/src/core/stream.js index 7f1195ad01265..64e71d5a56a49 100644 --- a/src/core/stream.js +++ b/src/core/stream.js @@ -12,15 +12,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* Copyright 1996-2003 Glyph & Cog, LLC - * - * The flate stream implementation contained in this file is a JavaScript port - * of XPDF's implementation, made available under the Apache 2.0 open source - * license. - */ /* eslint-disable no-var */ -import { FormatError, stringToBytes, unreachable } from "../shared/util.js"; +import { stringToBytes, unreachable } from "../shared/util.js"; var Stream = (function StreamClosure() { // eslint-disable-next-line no-shadow @@ -342,389 +336,6 @@ var StreamsSequenceStream = (function StreamsSequenceStreamClosure() { return StreamsSequenceStream; })(); -var FlateStream = (function FlateStreamClosure() { - // prettier-ignore - var codeLenCodeMap = new Int32Array([ - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 - ]); - - // prettier-ignore - var lengthDecode = new Int32Array([ - 0x00003, 0x00004, 0x00005, 0x00006, 0x00007, 0x00008, 0x00009, 0x0000a, - 0x1000b, 0x1000d, 0x1000f, 0x10011, 0x20013, 0x20017, 0x2001b, 0x2001f, - 0x30023, 0x3002b, 0x30033, 0x3003b, 0x40043, 0x40053, 0x40063, 0x40073, - 0x50083, 0x500a3, 0x500c3, 0x500e3, 0x00102, 0x00102, 0x00102 - ]); - - // prettier-ignore - var distDecode = new Int32Array([ - 0x00001, 0x00002, 0x00003, 0x00004, 0x10005, 0x10007, 0x20009, 0x2000d, - 0x30011, 0x30019, 0x40021, 0x40031, 0x50041, 0x50061, 0x60081, 0x600c1, - 0x70101, 0x70181, 0x80201, 0x80301, 0x90401, 0x90601, 0xa0801, 0xa0c01, - 0xb1001, 0xb1801, 0xc2001, 0xc3001, 0xd4001, 0xd6001 - ]); - - // prettier-ignore - var fixedLitCodeTab = [new Int32Array([ - 0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c0, - 0x70108, 0x80060, 0x80020, 0x900a0, 0x80000, 0x80080, 0x80040, 0x900e0, - 0x70104, 0x80058, 0x80018, 0x90090, 0x70114, 0x80078, 0x80038, 0x900d0, - 0x7010c, 0x80068, 0x80028, 0x900b0, 0x80008, 0x80088, 0x80048, 0x900f0, - 0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c8, - 0x7010a, 0x80064, 0x80024, 0x900a8, 0x80004, 0x80084, 0x80044, 0x900e8, - 0x70106, 0x8005c, 0x8001c, 0x90098, 0x70116, 0x8007c, 0x8003c, 0x900d8, - 0x7010e, 0x8006c, 0x8002c, 0x900b8, 0x8000c, 0x8008c, 0x8004c, 0x900f8, - 0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c4, - 0x70109, 0x80062, 0x80022, 0x900a4, 0x80002, 0x80082, 0x80042, 0x900e4, - 0x70105, 0x8005a, 0x8001a, 0x90094, 0x70115, 0x8007a, 0x8003a, 0x900d4, - 0x7010d, 0x8006a, 0x8002a, 0x900b4, 0x8000a, 0x8008a, 0x8004a, 0x900f4, - 0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cc, - 0x7010b, 0x80066, 0x80026, 0x900ac, 0x80006, 0x80086, 0x80046, 0x900ec, - 0x70107, 0x8005e, 0x8001e, 0x9009c, 0x70117, 0x8007e, 0x8003e, 0x900dc, - 0x7010f, 0x8006e, 0x8002e, 0x900bc, 0x8000e, 0x8008e, 0x8004e, 0x900fc, - 0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c2, - 0x70108, 0x80061, 0x80021, 0x900a2, 0x80001, 0x80081, 0x80041, 0x900e2, - 0x70104, 0x80059, 0x80019, 0x90092, 0x70114, 0x80079, 0x80039, 0x900d2, - 0x7010c, 0x80069, 0x80029, 0x900b2, 0x80009, 0x80089, 0x80049, 0x900f2, - 0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900ca, - 0x7010a, 0x80065, 0x80025, 0x900aa, 0x80005, 0x80085, 0x80045, 0x900ea, - 0x70106, 0x8005d, 0x8001d, 0x9009a, 0x70116, 0x8007d, 0x8003d, 0x900da, - 0x7010e, 0x8006d, 0x8002d, 0x900ba, 0x8000d, 0x8008d, 0x8004d, 0x900fa, - 0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c6, - 0x70109, 0x80063, 0x80023, 0x900a6, 0x80003, 0x80083, 0x80043, 0x900e6, - 0x70105, 0x8005b, 0x8001b, 0x90096, 0x70115, 0x8007b, 0x8003b, 0x900d6, - 0x7010d, 0x8006b, 0x8002b, 0x900b6, 0x8000b, 0x8008b, 0x8004b, 0x900f6, - 0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900ce, - 0x7010b, 0x80067, 0x80027, 0x900ae, 0x80007, 0x80087, 0x80047, 0x900ee, - 0x70107, 0x8005f, 0x8001f, 0x9009e, 0x70117, 0x8007f, 0x8003f, 0x900de, - 0x7010f, 0x8006f, 0x8002f, 0x900be, 0x8000f, 0x8008f, 0x8004f, 0x900fe, - 0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c1, - 0x70108, 0x80060, 0x80020, 0x900a1, 0x80000, 0x80080, 0x80040, 0x900e1, - 0x70104, 0x80058, 0x80018, 0x90091, 0x70114, 0x80078, 0x80038, 0x900d1, - 0x7010c, 0x80068, 0x80028, 0x900b1, 0x80008, 0x80088, 0x80048, 0x900f1, - 0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c9, - 0x7010a, 0x80064, 0x80024, 0x900a9, 0x80004, 0x80084, 0x80044, 0x900e9, - 0x70106, 0x8005c, 0x8001c, 0x90099, 0x70116, 0x8007c, 0x8003c, 0x900d9, - 0x7010e, 0x8006c, 0x8002c, 0x900b9, 0x8000c, 0x8008c, 0x8004c, 0x900f9, - 0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c5, - 0x70109, 0x80062, 0x80022, 0x900a5, 0x80002, 0x80082, 0x80042, 0x900e5, - 0x70105, 0x8005a, 0x8001a, 0x90095, 0x70115, 0x8007a, 0x8003a, 0x900d5, - 0x7010d, 0x8006a, 0x8002a, 0x900b5, 0x8000a, 0x8008a, 0x8004a, 0x900f5, - 0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cd, - 0x7010b, 0x80066, 0x80026, 0x900ad, 0x80006, 0x80086, 0x80046, 0x900ed, - 0x70107, 0x8005e, 0x8001e, 0x9009d, 0x70117, 0x8007e, 0x8003e, 0x900dd, - 0x7010f, 0x8006e, 0x8002e, 0x900bd, 0x8000e, 0x8008e, 0x8004e, 0x900fd, - 0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c3, - 0x70108, 0x80061, 0x80021, 0x900a3, 0x80001, 0x80081, 0x80041, 0x900e3, - 0x70104, 0x80059, 0x80019, 0x90093, 0x70114, 0x80079, 0x80039, 0x900d3, - 0x7010c, 0x80069, 0x80029, 0x900b3, 0x80009, 0x80089, 0x80049, 0x900f3, - 0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900cb, - 0x7010a, 0x80065, 0x80025, 0x900ab, 0x80005, 0x80085, 0x80045, 0x900eb, - 0x70106, 0x8005d, 0x8001d, 0x9009b, 0x70116, 0x8007d, 0x8003d, 0x900db, - 0x7010e, 0x8006d, 0x8002d, 0x900bb, 0x8000d, 0x8008d, 0x8004d, 0x900fb, - 0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c7, - 0x70109, 0x80063, 0x80023, 0x900a7, 0x80003, 0x80083, 0x80043, 0x900e7, - 0x70105, 0x8005b, 0x8001b, 0x90097, 0x70115, 0x8007b, 0x8003b, 0x900d7, - 0x7010d, 0x8006b, 0x8002b, 0x900b7, 0x8000b, 0x8008b, 0x8004b, 0x900f7, - 0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900cf, - 0x7010b, 0x80067, 0x80027, 0x900af, 0x80007, 0x80087, 0x80047, 0x900ef, - 0x70107, 0x8005f, 0x8001f, 0x9009f, 0x70117, 0x8007f, 0x8003f, 0x900df, - 0x7010f, 0x8006f, 0x8002f, 0x900bf, 0x8000f, 0x8008f, 0x8004f, 0x900ff - ]), 9]; - - // prettier-ignore - var fixedDistCodeTab = [new Int32Array([ - 0x50000, 0x50010, 0x50008, 0x50018, 0x50004, 0x50014, 0x5000c, 0x5001c, - 0x50002, 0x50012, 0x5000a, 0x5001a, 0x50006, 0x50016, 0x5000e, 0x00000, - 0x50001, 0x50011, 0x50009, 0x50019, 0x50005, 0x50015, 0x5000d, 0x5001d, - 0x50003, 0x50013, 0x5000b, 0x5001b, 0x50007, 0x50017, 0x5000f, 0x00000 - ]), 5]; - - // eslint-disable-next-line no-shadow - function FlateStream(str, maybeLength) { - this.str = str; - this.dict = str.dict; - - var cmf = str.getByte(); - var flg = str.getByte(); - if (cmf === -1 || flg === -1) { - throw new FormatError(`Invalid header in flate stream: ${cmf}, ${flg}`); - } - if ((cmf & 0x0f) !== 0x08) { - throw new FormatError( - `Unknown compression method in flate stream: ${cmf}, ${flg}` - ); - } - if (((cmf << 8) + flg) % 31 !== 0) { - throw new FormatError(`Bad FCHECK in flate stream: ${cmf}, ${flg}`); - } - if (flg & 0x20) { - throw new FormatError(`FDICT bit set in flate stream: ${cmf}, ${flg}`); - } - - this.codeSize = 0; - this.codeBuf = 0; - - DecodeStream.call(this, maybeLength); - } - - FlateStream.prototype = Object.create(DecodeStream.prototype); - - FlateStream.prototype.getBits = function FlateStream_getBits(bits) { - var str = this.str; - var codeSize = this.codeSize; - var codeBuf = this.codeBuf; - - var b; - while (codeSize < bits) { - if ((b = str.getByte()) === -1) { - throw new FormatError("Bad encoding in flate stream"); - } - codeBuf |= b << codeSize; - codeSize += 8; - } - b = codeBuf & ((1 << bits) - 1); - this.codeBuf = codeBuf >> bits; - this.codeSize = codeSize -= bits; - - return b; - }; - - FlateStream.prototype.getCode = function FlateStream_getCode(table) { - var str = this.str; - var codes = table[0]; - var maxLen = table[1]; - var codeSize = this.codeSize; - var codeBuf = this.codeBuf; - - var b; - while (codeSize < maxLen) { - if ((b = str.getByte()) === -1) { - // premature end of stream. code might however still be valid. - // codeSize < codeLen check below guards against incomplete codeVal. - break; - } - codeBuf |= b << codeSize; - codeSize += 8; - } - var code = codes[codeBuf & ((1 << maxLen) - 1)]; - var codeLen = code >> 16; - var codeVal = code & 0xffff; - if (codeLen < 1 || codeSize < codeLen) { - throw new FormatError("Bad encoding in flate stream"); - } - this.codeBuf = codeBuf >> codeLen; - this.codeSize = codeSize - codeLen; - return codeVal; - }; - - FlateStream.prototype.generateHuffmanTable = function flateStreamGenerateHuffmanTable( - lengths - ) { - var n = lengths.length; - - // find max code length - var maxLen = 0; - var i; - for (i = 0; i < n; ++i) { - if (lengths[i] > maxLen) { - maxLen = lengths[i]; - } - } - - // build the table - var size = 1 << maxLen; - var codes = new Int32Array(size); - for ( - var len = 1, code = 0, skip = 2; - len <= maxLen; - ++len, code <<= 1, skip <<= 1 - ) { - for (var val = 0; val < n; ++val) { - if (lengths[val] === len) { - // bit-reverse the code - var code2 = 0; - var t = code; - for (i = 0; i < len; ++i) { - code2 = (code2 << 1) | (t & 1); - t >>= 1; - } - - // fill the table entries - for (i = code2; i < size; i += skip) { - codes[i] = (len << 16) | val; - } - ++code; - } - } - } - - return [codes, maxLen]; - }; - - FlateStream.prototype.readBlock = function FlateStream_readBlock() { - var buffer, len; - var str = this.str; - // read block header - var hdr = this.getBits(3); - if (hdr & 1) { - this.eof = true; - } - hdr >>= 1; - - if (hdr === 0) { - // uncompressed block - var b; - - if ((b = str.getByte()) === -1) { - throw new FormatError("Bad block header in flate stream"); - } - var blockLen = b; - if ((b = str.getByte()) === -1) { - throw new FormatError("Bad block header in flate stream"); - } - blockLen |= b << 8; - if ((b = str.getByte()) === -1) { - throw new FormatError("Bad block header in flate stream"); - } - var check = b; - if ((b = str.getByte()) === -1) { - throw new FormatError("Bad block header in flate stream"); - } - check |= b << 8; - if (check !== (~blockLen & 0xffff) && (blockLen !== 0 || check !== 0)) { - // Ignoring error for bad "empty" block (see issue 1277) - throw new FormatError("Bad uncompressed block length in flate stream"); - } - - this.codeBuf = 0; - this.codeSize = 0; - - const bufferLength = this.bufferLength, - end = bufferLength + blockLen; - buffer = this.ensureBuffer(end); - this.bufferLength = end; - - if (blockLen === 0) { - if (str.peekByte() === -1) { - this.eof = true; - } - } else { - const block = str.getBytes(blockLen); - buffer.set(block, bufferLength); - if (block.length < blockLen) { - this.eof = true; - } - } - return; - } - - var litCodeTable; - var distCodeTable; - if (hdr === 1) { - // compressed block, fixed codes - litCodeTable = fixedLitCodeTab; - distCodeTable = fixedDistCodeTab; - } else if (hdr === 2) { - // compressed block, dynamic codes - var numLitCodes = this.getBits(5) + 257; - var numDistCodes = this.getBits(5) + 1; - var numCodeLenCodes = this.getBits(4) + 4; - - // build the code lengths code table - var codeLenCodeLengths = new Uint8Array(codeLenCodeMap.length); - - var i; - for (i = 0; i < numCodeLenCodes; ++i) { - codeLenCodeLengths[codeLenCodeMap[i]] = this.getBits(3); - } - var codeLenCodeTab = this.generateHuffmanTable(codeLenCodeLengths); - - // build the literal and distance code tables - len = 0; - i = 0; - var codes = numLitCodes + numDistCodes; - var codeLengths = new Uint8Array(codes); - var bitsLength, bitsOffset, what; - while (i < codes) { - var code = this.getCode(codeLenCodeTab); - if (code === 16) { - bitsLength = 2; - bitsOffset = 3; - what = len; - } else if (code === 17) { - bitsLength = 3; - bitsOffset = 3; - what = len = 0; - } else if (code === 18) { - bitsLength = 7; - bitsOffset = 11; - what = len = 0; - } else { - codeLengths[i++] = len = code; - continue; - } - - var repeatLength = this.getBits(bitsLength) + bitsOffset; - while (repeatLength-- > 0) { - codeLengths[i++] = what; - } - } - - litCodeTable = this.generateHuffmanTable( - codeLengths.subarray(0, numLitCodes) - ); - distCodeTable = this.generateHuffmanTable( - codeLengths.subarray(numLitCodes, codes) - ); - } else { - throw new FormatError("Unknown block type in flate stream"); - } - - buffer = this.buffer; - var limit = buffer ? buffer.length : 0; - var pos = this.bufferLength; - while (true) { - var code1 = this.getCode(litCodeTable); - if (code1 < 256) { - if (pos + 1 >= limit) { - buffer = this.ensureBuffer(pos + 1); - limit = buffer.length; - } - buffer[pos++] = code1; - continue; - } - if (code1 === 256) { - this.bufferLength = pos; - return; - } - code1 -= 257; - code1 = lengthDecode[code1]; - var code2 = code1 >> 16; - if (code2 > 0) { - code2 = this.getBits(code2); - } - len = (code1 & 0xffff) + code2; - code1 = this.getCode(distCodeTable); - code1 = distDecode[code1]; - code2 = code1 >> 16; - if (code2 > 0) { - code2 = this.getBits(code2); - } - var dist = (code1 & 0xffff) + code2; - if (pos + len >= limit) { - buffer = this.ensureBuffer(pos + len); - limit = buffer.length; - } - for (var k = 0; k < len; ++k, ++pos) { - buffer[pos] = buffer[pos - dist]; - } - } - }; - - return FlateStream; -})(); - var NullStream = (function NullStreamClosure() { // eslint-disable-next-line no-shadow function NullStream() { @@ -738,7 +349,6 @@ var NullStream = (function NullStreamClosure() { export { DecodeStream, - FlateStream, NullStream, Stream, StreamsSequenceStream, From aa1deaf93c6073dfabcdf19241844377406e8d97 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 27 Apr 2021 13:51:30 +0200 Subject: [PATCH 20/30] Enable the `no-var` rule in the `src/core/flate_stream.js` file --- src/core/flate_stream.js | 111 +++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 56 deletions(-) diff --git a/src/core/flate_stream.js b/src/core/flate_stream.js index 566aadb92b8e3..da4a1ebd1dc58 100644 --- a/src/core/flate_stream.js +++ b/src/core/flate_stream.js @@ -18,19 +18,18 @@ * of XPDF's implementation, made available under the Apache 2.0 open source * license. */ -/* eslint-disable no-var */ import { DecodeStream } from "./stream.js"; import { FormatError } from "../shared/util.js"; -var FlateStream = (function FlateStreamClosure() { +const FlateStream = (function FlateStreamClosure() { // prettier-ignore - var codeLenCodeMap = new Int32Array([ + const codeLenCodeMap = new Int32Array([ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ]); // prettier-ignore - var lengthDecode = new Int32Array([ + const lengthDecode = new Int32Array([ 0x00003, 0x00004, 0x00005, 0x00006, 0x00007, 0x00008, 0x00009, 0x0000a, 0x1000b, 0x1000d, 0x1000f, 0x10011, 0x20013, 0x20017, 0x2001b, 0x2001f, 0x30023, 0x3002b, 0x30033, 0x3003b, 0x40043, 0x40053, 0x40063, 0x40073, @@ -38,7 +37,7 @@ var FlateStream = (function FlateStreamClosure() { ]); // prettier-ignore - var distDecode = new Int32Array([ + const distDecode = new Int32Array([ 0x00001, 0x00002, 0x00003, 0x00004, 0x10005, 0x10007, 0x20009, 0x2000d, 0x30011, 0x30019, 0x40021, 0x40031, 0x50041, 0x50061, 0x60081, 0x600c1, 0x70101, 0x70181, 0x80201, 0x80301, 0x90401, 0x90601, 0xa0801, 0xa0c01, @@ -46,7 +45,7 @@ var FlateStream = (function FlateStreamClosure() { ]); // prettier-ignore - var fixedLitCodeTab = [new Int32Array([ + const fixedLitCodeTab = [new Int32Array([ 0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c0, 0x70108, 0x80060, 0x80020, 0x900a0, 0x80000, 0x80080, 0x80040, 0x900e0, 0x70104, 0x80058, 0x80018, 0x90090, 0x70114, 0x80078, 0x80038, 0x900d0, @@ -114,7 +113,7 @@ var FlateStream = (function FlateStreamClosure() { ]), 9]; // prettier-ignore - var fixedDistCodeTab = [new Int32Array([ + const fixedDistCodeTab = [new Int32Array([ 0x50000, 0x50010, 0x50008, 0x50018, 0x50004, 0x50014, 0x5000c, 0x5001c, 0x50002, 0x50012, 0x5000a, 0x5001a, 0x50006, 0x50016, 0x5000e, 0x00000, 0x50001, 0x50011, 0x50009, 0x50019, 0x50005, 0x50015, 0x5000d, 0x5001d, @@ -126,8 +125,8 @@ var FlateStream = (function FlateStreamClosure() { this.str = str; this.dict = str.dict; - var cmf = str.getByte(); - var flg = str.getByte(); + const cmf = str.getByte(); + const flg = str.getByte(); if (cmf === -1 || flg === -1) { throw new FormatError(`Invalid header in flate stream: ${cmf}, ${flg}`); } @@ -152,11 +151,11 @@ var FlateStream = (function FlateStreamClosure() { FlateStream.prototype = Object.create(DecodeStream.prototype); FlateStream.prototype.getBits = function FlateStream_getBits(bits) { - var str = this.str; - var codeSize = this.codeSize; - var codeBuf = this.codeBuf; + const str = this.str; + let codeSize = this.codeSize; + let codeBuf = this.codeBuf; - var b; + let b; while (codeSize < bits) { if ((b = str.getByte()) === -1) { throw new FormatError("Bad encoding in flate stream"); @@ -172,13 +171,13 @@ var FlateStream = (function FlateStreamClosure() { }; FlateStream.prototype.getCode = function FlateStream_getCode(table) { - var str = this.str; - var codes = table[0]; - var maxLen = table[1]; - var codeSize = this.codeSize; - var codeBuf = this.codeBuf; + const str = this.str; + const codes = table[0]; + const maxLen = table[1]; + let codeSize = this.codeSize; + let codeBuf = this.codeBuf; - var b; + let b; while (codeSize < maxLen) { if ((b = str.getByte()) === -1) { // premature end of stream. code might however still be valid. @@ -188,9 +187,9 @@ var FlateStream = (function FlateStreamClosure() { codeBuf |= b << codeSize; codeSize += 8; } - var code = codes[codeBuf & ((1 << maxLen) - 1)]; - var codeLen = code >> 16; - var codeVal = code & 0xffff; + const code = codes[codeBuf & ((1 << maxLen) - 1)]; + const codeLen = code >> 16; + const codeVal = code & 0xffff; if (codeLen < 1 || codeSize < codeLen) { throw new FormatError("Bad encoding in flate stream"); } @@ -202,11 +201,11 @@ var FlateStream = (function FlateStreamClosure() { FlateStream.prototype.generateHuffmanTable = function flateStreamGenerateHuffmanTable( lengths ) { - var n = lengths.length; + const n = lengths.length; // find max code length - var maxLen = 0; - var i; + let maxLen = 0; + let i; for (i = 0; i < n; ++i) { if (lengths[i] > maxLen) { maxLen = lengths[i]; @@ -214,18 +213,18 @@ var FlateStream = (function FlateStreamClosure() { } // build the table - var size = 1 << maxLen; - var codes = new Int32Array(size); + const size = 1 << maxLen; + const codes = new Int32Array(size); for ( - var len = 1, code = 0, skip = 2; + let len = 1, code = 0, skip = 2; len <= maxLen; ++len, code <<= 1, skip <<= 1 ) { - for (var val = 0; val < n; ++val) { + for (let val = 0; val < n; ++val) { if (lengths[val] === len) { // bit-reverse the code - var code2 = 0; - var t = code; + let code2 = 0; + let t = code; for (i = 0; i < len; ++i) { code2 = (code2 << 1) | (t & 1); t >>= 1; @@ -244,10 +243,10 @@ var FlateStream = (function FlateStreamClosure() { }; FlateStream.prototype.readBlock = function FlateStream_readBlock() { - var buffer, len; - var str = this.str; + let buffer, len; + const str = this.str; // read block header - var hdr = this.getBits(3); + let hdr = this.getBits(3); if (hdr & 1) { this.eof = true; } @@ -255,12 +254,12 @@ var FlateStream = (function FlateStreamClosure() { if (hdr === 0) { // uncompressed block - var b; + let b; if ((b = str.getByte()) === -1) { throw new FormatError("Bad block header in flate stream"); } - var blockLen = b; + let blockLen = b; if ((b = str.getByte()) === -1) { throw new FormatError("Bad block header in flate stream"); } @@ -268,7 +267,7 @@ var FlateStream = (function FlateStreamClosure() { if ((b = str.getByte()) === -1) { throw new FormatError("Bad block header in flate stream"); } - var check = b; + let check = b; if ((b = str.getByte()) === -1) { throw new FormatError("Bad block header in flate stream"); } @@ -300,35 +299,35 @@ var FlateStream = (function FlateStreamClosure() { return; } - var litCodeTable; - var distCodeTable; + let litCodeTable; + let distCodeTable; if (hdr === 1) { // compressed block, fixed codes litCodeTable = fixedLitCodeTab; distCodeTable = fixedDistCodeTab; } else if (hdr === 2) { // compressed block, dynamic codes - var numLitCodes = this.getBits(5) + 257; - var numDistCodes = this.getBits(5) + 1; - var numCodeLenCodes = this.getBits(4) + 4; + const numLitCodes = this.getBits(5) + 257; + const numDistCodes = this.getBits(5) + 1; + const numCodeLenCodes = this.getBits(4) + 4; // build the code lengths code table - var codeLenCodeLengths = new Uint8Array(codeLenCodeMap.length); + const codeLenCodeLengths = new Uint8Array(codeLenCodeMap.length); - var i; + let i; for (i = 0; i < numCodeLenCodes; ++i) { codeLenCodeLengths[codeLenCodeMap[i]] = this.getBits(3); } - var codeLenCodeTab = this.generateHuffmanTable(codeLenCodeLengths); + const codeLenCodeTab = this.generateHuffmanTable(codeLenCodeLengths); // build the literal and distance code tables len = 0; i = 0; - var codes = numLitCodes + numDistCodes; - var codeLengths = new Uint8Array(codes); - var bitsLength, bitsOffset, what; + const codes = numLitCodes + numDistCodes; + const codeLengths = new Uint8Array(codes); + let bitsLength, bitsOffset, what; while (i < codes) { - var code = this.getCode(codeLenCodeTab); + const code = this.getCode(codeLenCodeTab); if (code === 16) { bitsLength = 2; bitsOffset = 3; @@ -346,7 +345,7 @@ var FlateStream = (function FlateStreamClosure() { continue; } - var repeatLength = this.getBits(bitsLength) + bitsOffset; + let repeatLength = this.getBits(bitsLength) + bitsOffset; while (repeatLength-- > 0) { codeLengths[i++] = what; } @@ -363,10 +362,10 @@ var FlateStream = (function FlateStreamClosure() { } buffer = this.buffer; - var limit = buffer ? buffer.length : 0; - var pos = this.bufferLength; + let limit = buffer ? buffer.length : 0; + let pos = this.bufferLength; while (true) { - var code1 = this.getCode(litCodeTable); + let code1 = this.getCode(litCodeTable); if (code1 < 256) { if (pos + 1 >= limit) { buffer = this.ensureBuffer(pos + 1); @@ -381,7 +380,7 @@ var FlateStream = (function FlateStreamClosure() { } code1 -= 257; code1 = lengthDecode[code1]; - var code2 = code1 >> 16; + let code2 = code1 >> 16; if (code2 > 0) { code2 = this.getBits(code2); } @@ -392,12 +391,12 @@ var FlateStream = (function FlateStreamClosure() { if (code2 > 0) { code2 = this.getBits(code2); } - var dist = (code1 & 0xffff) + code2; + const dist = (code1 & 0xffff) + code2; if (pos + len >= limit) { buffer = this.ensureBuffer(pos + len); limit = buffer.length; } - for (var k = 0; k < len; ++k, ++pos) { + for (let k = 0; k < len; ++k, ++pos) { buffer[pos] = buffer[pos - dist]; } } From 213e1c389c72fda3b56f80b0f4643341087c8d03 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 27 Apr 2021 13:53:36 +0200 Subject: [PATCH 21/30] Convert `src/core/flate_stream.js` to use standard classes --- src/core/flate_stream.js | 227 +++++++++++++++++++-------------------- 1 file changed, 110 insertions(+), 117 deletions(-) diff --git a/src/core/flate_stream.js b/src/core/flate_stream.js index da4a1ebd1dc58..b8dfb4cfff0ed 100644 --- a/src/core/flate_stream.js +++ b/src/core/flate_stream.js @@ -22,106 +22,107 @@ import { DecodeStream } from "./stream.js"; import { FormatError } from "../shared/util.js"; -const FlateStream = (function FlateStreamClosure() { - // prettier-ignore - const codeLenCodeMap = new Int32Array([ - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 - ]); - - // prettier-ignore - const lengthDecode = new Int32Array([ - 0x00003, 0x00004, 0x00005, 0x00006, 0x00007, 0x00008, 0x00009, 0x0000a, - 0x1000b, 0x1000d, 0x1000f, 0x10011, 0x20013, 0x20017, 0x2001b, 0x2001f, - 0x30023, 0x3002b, 0x30033, 0x3003b, 0x40043, 0x40053, 0x40063, 0x40073, - 0x50083, 0x500a3, 0x500c3, 0x500e3, 0x00102, 0x00102, 0x00102 - ]); - - // prettier-ignore - const distDecode = new Int32Array([ - 0x00001, 0x00002, 0x00003, 0x00004, 0x10005, 0x10007, 0x20009, 0x2000d, - 0x30011, 0x30019, 0x40021, 0x40031, 0x50041, 0x50061, 0x60081, 0x600c1, - 0x70101, 0x70181, 0x80201, 0x80301, 0x90401, 0x90601, 0xa0801, 0xa0c01, - 0xb1001, 0xb1801, 0xc2001, 0xc3001, 0xd4001, 0xd6001 - ]); - - // prettier-ignore - const fixedLitCodeTab = [new Int32Array([ - 0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c0, - 0x70108, 0x80060, 0x80020, 0x900a0, 0x80000, 0x80080, 0x80040, 0x900e0, - 0x70104, 0x80058, 0x80018, 0x90090, 0x70114, 0x80078, 0x80038, 0x900d0, - 0x7010c, 0x80068, 0x80028, 0x900b0, 0x80008, 0x80088, 0x80048, 0x900f0, - 0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c8, - 0x7010a, 0x80064, 0x80024, 0x900a8, 0x80004, 0x80084, 0x80044, 0x900e8, - 0x70106, 0x8005c, 0x8001c, 0x90098, 0x70116, 0x8007c, 0x8003c, 0x900d8, - 0x7010e, 0x8006c, 0x8002c, 0x900b8, 0x8000c, 0x8008c, 0x8004c, 0x900f8, - 0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c4, - 0x70109, 0x80062, 0x80022, 0x900a4, 0x80002, 0x80082, 0x80042, 0x900e4, - 0x70105, 0x8005a, 0x8001a, 0x90094, 0x70115, 0x8007a, 0x8003a, 0x900d4, - 0x7010d, 0x8006a, 0x8002a, 0x900b4, 0x8000a, 0x8008a, 0x8004a, 0x900f4, - 0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cc, - 0x7010b, 0x80066, 0x80026, 0x900ac, 0x80006, 0x80086, 0x80046, 0x900ec, - 0x70107, 0x8005e, 0x8001e, 0x9009c, 0x70117, 0x8007e, 0x8003e, 0x900dc, - 0x7010f, 0x8006e, 0x8002e, 0x900bc, 0x8000e, 0x8008e, 0x8004e, 0x900fc, - 0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c2, - 0x70108, 0x80061, 0x80021, 0x900a2, 0x80001, 0x80081, 0x80041, 0x900e2, - 0x70104, 0x80059, 0x80019, 0x90092, 0x70114, 0x80079, 0x80039, 0x900d2, - 0x7010c, 0x80069, 0x80029, 0x900b2, 0x80009, 0x80089, 0x80049, 0x900f2, - 0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900ca, - 0x7010a, 0x80065, 0x80025, 0x900aa, 0x80005, 0x80085, 0x80045, 0x900ea, - 0x70106, 0x8005d, 0x8001d, 0x9009a, 0x70116, 0x8007d, 0x8003d, 0x900da, - 0x7010e, 0x8006d, 0x8002d, 0x900ba, 0x8000d, 0x8008d, 0x8004d, 0x900fa, - 0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c6, - 0x70109, 0x80063, 0x80023, 0x900a6, 0x80003, 0x80083, 0x80043, 0x900e6, - 0x70105, 0x8005b, 0x8001b, 0x90096, 0x70115, 0x8007b, 0x8003b, 0x900d6, - 0x7010d, 0x8006b, 0x8002b, 0x900b6, 0x8000b, 0x8008b, 0x8004b, 0x900f6, - 0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900ce, - 0x7010b, 0x80067, 0x80027, 0x900ae, 0x80007, 0x80087, 0x80047, 0x900ee, - 0x70107, 0x8005f, 0x8001f, 0x9009e, 0x70117, 0x8007f, 0x8003f, 0x900de, - 0x7010f, 0x8006f, 0x8002f, 0x900be, 0x8000f, 0x8008f, 0x8004f, 0x900fe, - 0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c1, - 0x70108, 0x80060, 0x80020, 0x900a1, 0x80000, 0x80080, 0x80040, 0x900e1, - 0x70104, 0x80058, 0x80018, 0x90091, 0x70114, 0x80078, 0x80038, 0x900d1, - 0x7010c, 0x80068, 0x80028, 0x900b1, 0x80008, 0x80088, 0x80048, 0x900f1, - 0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c9, - 0x7010a, 0x80064, 0x80024, 0x900a9, 0x80004, 0x80084, 0x80044, 0x900e9, - 0x70106, 0x8005c, 0x8001c, 0x90099, 0x70116, 0x8007c, 0x8003c, 0x900d9, - 0x7010e, 0x8006c, 0x8002c, 0x900b9, 0x8000c, 0x8008c, 0x8004c, 0x900f9, - 0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c5, - 0x70109, 0x80062, 0x80022, 0x900a5, 0x80002, 0x80082, 0x80042, 0x900e5, - 0x70105, 0x8005a, 0x8001a, 0x90095, 0x70115, 0x8007a, 0x8003a, 0x900d5, - 0x7010d, 0x8006a, 0x8002a, 0x900b5, 0x8000a, 0x8008a, 0x8004a, 0x900f5, - 0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cd, - 0x7010b, 0x80066, 0x80026, 0x900ad, 0x80006, 0x80086, 0x80046, 0x900ed, - 0x70107, 0x8005e, 0x8001e, 0x9009d, 0x70117, 0x8007e, 0x8003e, 0x900dd, - 0x7010f, 0x8006e, 0x8002e, 0x900bd, 0x8000e, 0x8008e, 0x8004e, 0x900fd, - 0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c3, - 0x70108, 0x80061, 0x80021, 0x900a3, 0x80001, 0x80081, 0x80041, 0x900e3, - 0x70104, 0x80059, 0x80019, 0x90093, 0x70114, 0x80079, 0x80039, 0x900d3, - 0x7010c, 0x80069, 0x80029, 0x900b3, 0x80009, 0x80089, 0x80049, 0x900f3, - 0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900cb, - 0x7010a, 0x80065, 0x80025, 0x900ab, 0x80005, 0x80085, 0x80045, 0x900eb, - 0x70106, 0x8005d, 0x8001d, 0x9009b, 0x70116, 0x8007d, 0x8003d, 0x900db, - 0x7010e, 0x8006d, 0x8002d, 0x900bb, 0x8000d, 0x8008d, 0x8004d, 0x900fb, - 0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c7, - 0x70109, 0x80063, 0x80023, 0x900a7, 0x80003, 0x80083, 0x80043, 0x900e7, - 0x70105, 0x8005b, 0x8001b, 0x90097, 0x70115, 0x8007b, 0x8003b, 0x900d7, - 0x7010d, 0x8006b, 0x8002b, 0x900b7, 0x8000b, 0x8008b, 0x8004b, 0x900f7, - 0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900cf, - 0x7010b, 0x80067, 0x80027, 0x900af, 0x80007, 0x80087, 0x80047, 0x900ef, - 0x70107, 0x8005f, 0x8001f, 0x9009f, 0x70117, 0x8007f, 0x8003f, 0x900df, - 0x7010f, 0x8006f, 0x8002f, 0x900bf, 0x8000f, 0x8008f, 0x8004f, 0x900ff - ]), 9]; - - // prettier-ignore - const fixedDistCodeTab = [new Int32Array([ - 0x50000, 0x50010, 0x50008, 0x50018, 0x50004, 0x50014, 0x5000c, 0x5001c, - 0x50002, 0x50012, 0x5000a, 0x5001a, 0x50006, 0x50016, 0x5000e, 0x00000, - 0x50001, 0x50011, 0x50009, 0x50019, 0x50005, 0x50015, 0x5000d, 0x5001d, - 0x50003, 0x50013, 0x5000b, 0x5001b, 0x50007, 0x50017, 0x5000f, 0x00000 - ]), 5]; - - // eslint-disable-next-line no-shadow - function FlateStream(str, maybeLength) { +// prettier-ignore +const codeLenCodeMap = new Int32Array([ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 +]); + +// prettier-ignore +const lengthDecode = new Int32Array([ + 0x00003, 0x00004, 0x00005, 0x00006, 0x00007, 0x00008, 0x00009, 0x0000a, + 0x1000b, 0x1000d, 0x1000f, 0x10011, 0x20013, 0x20017, 0x2001b, 0x2001f, + 0x30023, 0x3002b, 0x30033, 0x3003b, 0x40043, 0x40053, 0x40063, 0x40073, + 0x50083, 0x500a3, 0x500c3, 0x500e3, 0x00102, 0x00102, 0x00102 +]); + +// prettier-ignore +const distDecode = new Int32Array([ + 0x00001, 0x00002, 0x00003, 0x00004, 0x10005, 0x10007, 0x20009, 0x2000d, + 0x30011, 0x30019, 0x40021, 0x40031, 0x50041, 0x50061, 0x60081, 0x600c1, + 0x70101, 0x70181, 0x80201, 0x80301, 0x90401, 0x90601, 0xa0801, 0xa0c01, + 0xb1001, 0xb1801, 0xc2001, 0xc3001, 0xd4001, 0xd6001 +]); + +// prettier-ignore +const fixedLitCodeTab = [new Int32Array([ + 0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c0, + 0x70108, 0x80060, 0x80020, 0x900a0, 0x80000, 0x80080, 0x80040, 0x900e0, + 0x70104, 0x80058, 0x80018, 0x90090, 0x70114, 0x80078, 0x80038, 0x900d0, + 0x7010c, 0x80068, 0x80028, 0x900b0, 0x80008, 0x80088, 0x80048, 0x900f0, + 0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c8, + 0x7010a, 0x80064, 0x80024, 0x900a8, 0x80004, 0x80084, 0x80044, 0x900e8, + 0x70106, 0x8005c, 0x8001c, 0x90098, 0x70116, 0x8007c, 0x8003c, 0x900d8, + 0x7010e, 0x8006c, 0x8002c, 0x900b8, 0x8000c, 0x8008c, 0x8004c, 0x900f8, + 0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c4, + 0x70109, 0x80062, 0x80022, 0x900a4, 0x80002, 0x80082, 0x80042, 0x900e4, + 0x70105, 0x8005a, 0x8001a, 0x90094, 0x70115, 0x8007a, 0x8003a, 0x900d4, + 0x7010d, 0x8006a, 0x8002a, 0x900b4, 0x8000a, 0x8008a, 0x8004a, 0x900f4, + 0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cc, + 0x7010b, 0x80066, 0x80026, 0x900ac, 0x80006, 0x80086, 0x80046, 0x900ec, + 0x70107, 0x8005e, 0x8001e, 0x9009c, 0x70117, 0x8007e, 0x8003e, 0x900dc, + 0x7010f, 0x8006e, 0x8002e, 0x900bc, 0x8000e, 0x8008e, 0x8004e, 0x900fc, + 0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c2, + 0x70108, 0x80061, 0x80021, 0x900a2, 0x80001, 0x80081, 0x80041, 0x900e2, + 0x70104, 0x80059, 0x80019, 0x90092, 0x70114, 0x80079, 0x80039, 0x900d2, + 0x7010c, 0x80069, 0x80029, 0x900b2, 0x80009, 0x80089, 0x80049, 0x900f2, + 0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900ca, + 0x7010a, 0x80065, 0x80025, 0x900aa, 0x80005, 0x80085, 0x80045, 0x900ea, + 0x70106, 0x8005d, 0x8001d, 0x9009a, 0x70116, 0x8007d, 0x8003d, 0x900da, + 0x7010e, 0x8006d, 0x8002d, 0x900ba, 0x8000d, 0x8008d, 0x8004d, 0x900fa, + 0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c6, + 0x70109, 0x80063, 0x80023, 0x900a6, 0x80003, 0x80083, 0x80043, 0x900e6, + 0x70105, 0x8005b, 0x8001b, 0x90096, 0x70115, 0x8007b, 0x8003b, 0x900d6, + 0x7010d, 0x8006b, 0x8002b, 0x900b6, 0x8000b, 0x8008b, 0x8004b, 0x900f6, + 0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900ce, + 0x7010b, 0x80067, 0x80027, 0x900ae, 0x80007, 0x80087, 0x80047, 0x900ee, + 0x70107, 0x8005f, 0x8001f, 0x9009e, 0x70117, 0x8007f, 0x8003f, 0x900de, + 0x7010f, 0x8006f, 0x8002f, 0x900be, 0x8000f, 0x8008f, 0x8004f, 0x900fe, + 0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c1, + 0x70108, 0x80060, 0x80020, 0x900a1, 0x80000, 0x80080, 0x80040, 0x900e1, + 0x70104, 0x80058, 0x80018, 0x90091, 0x70114, 0x80078, 0x80038, 0x900d1, + 0x7010c, 0x80068, 0x80028, 0x900b1, 0x80008, 0x80088, 0x80048, 0x900f1, + 0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c9, + 0x7010a, 0x80064, 0x80024, 0x900a9, 0x80004, 0x80084, 0x80044, 0x900e9, + 0x70106, 0x8005c, 0x8001c, 0x90099, 0x70116, 0x8007c, 0x8003c, 0x900d9, + 0x7010e, 0x8006c, 0x8002c, 0x900b9, 0x8000c, 0x8008c, 0x8004c, 0x900f9, + 0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c5, + 0x70109, 0x80062, 0x80022, 0x900a5, 0x80002, 0x80082, 0x80042, 0x900e5, + 0x70105, 0x8005a, 0x8001a, 0x90095, 0x70115, 0x8007a, 0x8003a, 0x900d5, + 0x7010d, 0x8006a, 0x8002a, 0x900b5, 0x8000a, 0x8008a, 0x8004a, 0x900f5, + 0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cd, + 0x7010b, 0x80066, 0x80026, 0x900ad, 0x80006, 0x80086, 0x80046, 0x900ed, + 0x70107, 0x8005e, 0x8001e, 0x9009d, 0x70117, 0x8007e, 0x8003e, 0x900dd, + 0x7010f, 0x8006e, 0x8002e, 0x900bd, 0x8000e, 0x8008e, 0x8004e, 0x900fd, + 0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c3, + 0x70108, 0x80061, 0x80021, 0x900a3, 0x80001, 0x80081, 0x80041, 0x900e3, + 0x70104, 0x80059, 0x80019, 0x90093, 0x70114, 0x80079, 0x80039, 0x900d3, + 0x7010c, 0x80069, 0x80029, 0x900b3, 0x80009, 0x80089, 0x80049, 0x900f3, + 0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900cb, + 0x7010a, 0x80065, 0x80025, 0x900ab, 0x80005, 0x80085, 0x80045, 0x900eb, + 0x70106, 0x8005d, 0x8001d, 0x9009b, 0x70116, 0x8007d, 0x8003d, 0x900db, + 0x7010e, 0x8006d, 0x8002d, 0x900bb, 0x8000d, 0x8008d, 0x8004d, 0x900fb, + 0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c7, + 0x70109, 0x80063, 0x80023, 0x900a7, 0x80003, 0x80083, 0x80043, 0x900e7, + 0x70105, 0x8005b, 0x8001b, 0x90097, 0x70115, 0x8007b, 0x8003b, 0x900d7, + 0x7010d, 0x8006b, 0x8002b, 0x900b7, 0x8000b, 0x8008b, 0x8004b, 0x900f7, + 0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900cf, + 0x7010b, 0x80067, 0x80027, 0x900af, 0x80007, 0x80087, 0x80047, 0x900ef, + 0x70107, 0x8005f, 0x8001f, 0x9009f, 0x70117, 0x8007f, 0x8003f, 0x900df, + 0x7010f, 0x8006f, 0x8002f, 0x900bf, 0x8000f, 0x8008f, 0x8004f, 0x900ff +]), 9]; + +// prettier-ignore +const fixedDistCodeTab = [new Int32Array([ + 0x50000, 0x50010, 0x50008, 0x50018, 0x50004, 0x50014, 0x5000c, 0x5001c, + 0x50002, 0x50012, 0x5000a, 0x5001a, 0x50006, 0x50016, 0x5000e, 0x00000, + 0x50001, 0x50011, 0x50009, 0x50019, 0x50005, 0x50015, 0x5000d, 0x5001d, + 0x50003, 0x50013, 0x5000b, 0x5001b, 0x50007, 0x50017, 0x5000f, 0x00000 +]), 5]; + +class FlateStream extends DecodeStream { + constructor(str, maybeLength) { + super(maybeLength); + this.str = str; this.dict = str.dict; @@ -144,13 +145,9 @@ const FlateStream = (function FlateStreamClosure() { this.codeSize = 0; this.codeBuf = 0; - - DecodeStream.call(this, maybeLength); } - FlateStream.prototype = Object.create(DecodeStream.prototype); - - FlateStream.prototype.getBits = function FlateStream_getBits(bits) { + getBits(bits) { const str = this.str; let codeSize = this.codeSize; let codeBuf = this.codeBuf; @@ -168,9 +165,9 @@ const FlateStream = (function FlateStreamClosure() { this.codeSize = codeSize -= bits; return b; - }; + } - FlateStream.prototype.getCode = function FlateStream_getCode(table) { + getCode(table) { const str = this.str; const codes = table[0]; const maxLen = table[1]; @@ -196,11 +193,9 @@ const FlateStream = (function FlateStreamClosure() { this.codeBuf = codeBuf >> codeLen; this.codeSize = codeSize - codeLen; return codeVal; - }; + } - FlateStream.prototype.generateHuffmanTable = function flateStreamGenerateHuffmanTable( - lengths - ) { + generateHuffmanTable(lengths) { const n = lengths.length; // find max code length @@ -240,9 +235,9 @@ const FlateStream = (function FlateStreamClosure() { } return [codes, maxLen]; - }; + } - FlateStream.prototype.readBlock = function FlateStream_readBlock() { + readBlock() { let buffer, len; const str = this.str; // read block header @@ -400,9 +395,7 @@ const FlateStream = (function FlateStreamClosure() { buffer[pos] = buffer[pos - dist]; } } - }; - - return FlateStream; -})(); + } +} export { FlateStream }; From 30a22a168d8876d8653df878c435fbb189fd7c66 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 27 Apr 2021 16:18:52 +0200 Subject: [PATCH 22/30] Move the `DecodeStream` and `StreamsSequenceStream` from `src/core/stream.js` and into its own file --- src/core/ascii_85_stream.js | 2 +- src/core/ascii_hex_stream.js | 2 +- src/core/ccitt_stream.js | 2 +- src/core/decode_stream.js | 222 ++++++++++++++++++++++++++++++++++ src/core/decrypt_stream.js | 2 +- src/core/document.js | 3 +- src/core/evaluator.js | 3 +- src/core/flate_stream.js | 2 +- src/core/image.js | 2 +- src/core/jbig2_stream.js | 2 +- src/core/jpeg_stream.js | 2 +- src/core/jpx_stream.js | 2 +- src/core/lzw_stream.js | 2 +- src/core/predictor_stream.js | 2 +- src/core/run_length_stream.js | 2 +- src/core/stream.js | 212 +------------------------------- 16 files changed, 240 insertions(+), 224 deletions(-) create mode 100644 src/core/decode_stream.js diff --git a/src/core/ascii_85_stream.js b/src/core/ascii_85_stream.js index 159eae66ec858..a006d40e2043b 100644 --- a/src/core/ascii_85_stream.js +++ b/src/core/ascii_85_stream.js @@ -13,7 +13,7 @@ * limitations under the License. */ -import { DecodeStream } from "./stream.js"; +import { DecodeStream } from "./decode_stream.js"; import { isWhiteSpace } from "./core_utils.js"; class Ascii85Stream extends DecodeStream { diff --git a/src/core/ascii_hex_stream.js b/src/core/ascii_hex_stream.js index 69e9021715110..0bc1bd15a130b 100644 --- a/src/core/ascii_hex_stream.js +++ b/src/core/ascii_hex_stream.js @@ -13,7 +13,7 @@ * limitations under the License. */ -import { DecodeStream } from "./stream.js"; +import { DecodeStream } from "./decode_stream.js"; class AsciiHexStream extends DecodeStream { constructor(str, maybeLength) { diff --git a/src/core/ccitt_stream.js b/src/core/ccitt_stream.js index 6f597689aba32..d716b48419ab1 100644 --- a/src/core/ccitt_stream.js +++ b/src/core/ccitt_stream.js @@ -15,7 +15,7 @@ import { Dict, isDict } from "./primitives.js"; import { CCITTFaxDecoder } from "./ccitt.js"; -import { DecodeStream } from "./stream.js"; +import { DecodeStream } from "./decode_stream.js"; class CCITTFaxStream extends DecodeStream { constructor(str, maybeLength, params) { diff --git a/src/core/decode_stream.js b/src/core/decode_stream.js new file mode 100644 index 0000000000000..f4ff751c30868 --- /dev/null +++ b/src/core/decode_stream.js @@ -0,0 +1,222 @@ +/* Copyright 2012 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* eslint-disable no-var */ + +import { Stream } from "./stream.js"; +import { unreachable } from "../shared/util.js"; + +// super class for the decoding streams +var DecodeStream = (function DecodeStreamClosure() { + // Lots of DecodeStreams are created whose buffers are never used. For these + // we share a single empty buffer. This is (a) space-efficient and (b) avoids + // having special cases that would be required if we used |null| for an empty + // buffer. + var emptyBuffer = new Uint8Array(0); + + // eslint-disable-next-line no-shadow + function DecodeStream(maybeMinBufferLength) { + this._rawMinBufferLength = maybeMinBufferLength || 0; + + this.pos = 0; + this.bufferLength = 0; + this.eof = false; + this.buffer = emptyBuffer; + this.minBufferLength = 512; + if (maybeMinBufferLength) { + // Compute the first power of two that is as big as maybeMinBufferLength. + while (this.minBufferLength < maybeMinBufferLength) { + this.minBufferLength *= 2; + } + } + } + + DecodeStream.prototype = { + // eslint-disable-next-line getter-return + get length() { + unreachable("Should not access DecodeStream.length"); + }, + + get isEmpty() { + while (!this.eof && this.bufferLength === 0) { + this.readBlock(); + } + return this.bufferLength === 0; + }, + ensureBuffer: function DecodeStream_ensureBuffer(requested) { + var buffer = this.buffer; + if (requested <= buffer.byteLength) { + return buffer; + } + var size = this.minBufferLength; + while (size < requested) { + size *= 2; + } + var buffer2 = new Uint8Array(size); + buffer2.set(buffer); + return (this.buffer = buffer2); + }, + getByte: function DecodeStream_getByte() { + var pos = this.pos; + while (this.bufferLength <= pos) { + if (this.eof) { + return -1; + } + this.readBlock(); + } + return this.buffer[this.pos++]; + }, + getUint16: function DecodeStream_getUint16() { + var b0 = this.getByte(); + var b1 = this.getByte(); + if (b0 === -1 || b1 === -1) { + return -1; + } + return (b0 << 8) + b1; + }, + getInt32: function DecodeStream_getInt32() { + var b0 = this.getByte(); + var b1 = this.getByte(); + var b2 = this.getByte(); + var b3 = this.getByte(); + return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; + }, + getBytes(length, forceClamped = false) { + var end, + pos = this.pos; + + if (length) { + this.ensureBuffer(pos + length); + end = pos + length; + + while (!this.eof && this.bufferLength < end) { + this.readBlock(); + } + var bufEnd = this.bufferLength; + if (end > bufEnd) { + end = bufEnd; + } + } else { + while (!this.eof) { + this.readBlock(); + } + end = this.bufferLength; + } + + this.pos = end; + const subarray = this.buffer.subarray(pos, end); + // `this.buffer` is either a `Uint8Array` or `Uint8ClampedArray` here. + return forceClamped && !(subarray instanceof Uint8ClampedArray) + ? new Uint8ClampedArray(subarray) + : subarray; + }, + peekByte: function DecodeStream_peekByte() { + var peekedByte = this.getByte(); + if (peekedByte !== -1) { + this.pos--; + } + return peekedByte; + }, + peekBytes(length, forceClamped = false) { + var bytes = this.getBytes(length, forceClamped); + this.pos -= bytes.length; + return bytes; + }, + makeSubStream: function DecodeStream_makeSubStream(start, length, dict) { + if (length === undefined) { + while (!this.eof) { + this.readBlock(); + } + } else { + var end = start + length; + while (this.bufferLength <= end && !this.eof) { + this.readBlock(); + } + } + return new Stream(this.buffer, start, length, dict); + }, + + getByteRange(begin, end) { + unreachable("Should not call DecodeStream.getByteRange"); + }, + + skip: function DecodeStream_skip(n) { + if (!n) { + n = 1; + } + this.pos += n; + }, + reset: function DecodeStream_reset() { + this.pos = 0; + }, + getBaseStreams: function DecodeStream_getBaseStreams() { + if (this.str && this.str.getBaseStreams) { + return this.str.getBaseStreams(); + } + return []; + }, + }; + + return DecodeStream; +})(); + +var StreamsSequenceStream = (function StreamsSequenceStreamClosure() { + // eslint-disable-next-line no-shadow + function StreamsSequenceStream(streams) { + this.streams = streams; + + let maybeLength = 0; + for (let i = 0, ii = streams.length; i < ii; i++) { + const stream = streams[i]; + if (stream instanceof DecodeStream) { + maybeLength += stream._rawMinBufferLength; + } else { + maybeLength += stream.length; + } + } + DecodeStream.call(this, maybeLength); + } + + StreamsSequenceStream.prototype = Object.create(DecodeStream.prototype); + + StreamsSequenceStream.prototype.readBlock = function streamSequenceStreamReadBlock() { + var streams = this.streams; + if (streams.length === 0) { + this.eof = true; + return; + } + var stream = streams.shift(); + var chunk = stream.getBytes(); + var bufferLength = this.bufferLength; + var newLength = bufferLength + chunk.length; + var buffer = this.ensureBuffer(newLength); + buffer.set(chunk, bufferLength); + this.bufferLength = newLength; + }; + + StreamsSequenceStream.prototype.getBaseStreams = function StreamsSequenceStream_getBaseStreams() { + var baseStreams = []; + for (var i = 0, ii = this.streams.length; i < ii; i++) { + var stream = this.streams[i]; + if (stream.getBaseStreams) { + baseStreams.push(...stream.getBaseStreams()); + } + } + return baseStreams; + }; + + return StreamsSequenceStream; +})(); + +export { DecodeStream, StreamsSequenceStream }; diff --git a/src/core/decrypt_stream.js b/src/core/decrypt_stream.js index cc5df1b66ac95..6848ead7e1fc4 100644 --- a/src/core/decrypt_stream.js +++ b/src/core/decrypt_stream.js @@ -13,7 +13,7 @@ * limitations under the License. */ -import { DecodeStream } from "./stream.js"; +import { DecodeStream } from "./decode_stream.js"; const chunkSize = 512; diff --git a/src/core/document.js b/src/core/document.js index 0682d7813fd57..3e0883331f6d4 100644 --- a/src/core/document.js +++ b/src/core/document.js @@ -53,7 +53,7 @@ import { XRefEntryException, XRefParseException, } from "./core_utils.js"; -import { NullStream, Stream, StreamsSequenceStream } from "./stream.js"; +import { NullStream, Stream } from "./stream.js"; import { AnnotationFactory } from "./annotation.js"; import { calculateMD5 } from "./crypto.js"; import { Catalog } from "./catalog.js"; @@ -61,6 +61,7 @@ import { Linearization } from "./parser.js"; import { ObjectLoader } from "./object_loader.js"; import { OperatorList } from "./operator_list.js"; import { PartialEvaluator } from "./evaluator.js"; +import { StreamsSequenceStream } from "./decode_stream.js"; import { StructTreePage } from "./struct_tree.js"; import { XFAFactory } from "./xfa/factory.js"; import { XRef } from "./xref.js"; diff --git a/src/core/evaluator.js b/src/core/evaluator.js index 46c2cb3f13cc8..bd43c323db6f9 100644 --- a/src/core/evaluator.js +++ b/src/core/evaluator.js @@ -47,7 +47,6 @@ import { Ref, RefSet, } from "./primitives.js"; -import { DecodeStream, NullStream } from "./stream.js"; import { ErrorFont, Font, @@ -85,10 +84,12 @@ import { } from "./image_utils.js"; import { bidi } from "./bidi.js"; import { ColorSpace } from "./colorspace.js"; +import { DecodeStream } from "./decode_stream.js"; import { getGlyphsUnicode } from "./glyphlist.js"; import { getLookupTableFactory } from "./core_utils.js"; import { getMetrics } from "./metrics.js"; import { MurmurHash3_64 } from "./murmurhash3.js"; +import { NullStream } from "./stream.js"; import { OperatorList } from "./operator_list.js"; import { PDFImage } from "./image.js"; diff --git a/src/core/flate_stream.js b/src/core/flate_stream.js index b8dfb4cfff0ed..6533bbd6b8cfe 100644 --- a/src/core/flate_stream.js +++ b/src/core/flate_stream.js @@ -19,7 +19,7 @@ * license. */ -import { DecodeStream } from "./stream.js"; +import { DecodeStream } from "./decode_stream.js"; import { FormatError } from "../shared/util.js"; // prettier-ignore diff --git a/src/core/image.js b/src/core/image.js index e718b993734fc..9de3c32169fbe 100644 --- a/src/core/image.js +++ b/src/core/image.js @@ -16,7 +16,7 @@ import { assert, FormatError, ImageKind, info, warn } from "../shared/util.js"; import { isName, isStream, Name } from "./primitives.js"; import { ColorSpace } from "./colorspace.js"; -import { DecodeStream } from "./stream.js"; +import { DecodeStream } from "./decode_stream.js"; import { JpegStream } from "./jpeg_stream.js"; import { JpxImage } from "./jpx.js"; diff --git a/src/core/jbig2_stream.js b/src/core/jbig2_stream.js index c760e8d90db30..dda50f6d66ad4 100644 --- a/src/core/jbig2_stream.js +++ b/src/core/jbig2_stream.js @@ -14,7 +14,7 @@ */ import { isDict, isStream } from "./primitives.js"; -import { DecodeStream } from "./stream.js"; +import { DecodeStream } from "./decode_stream.js"; import { Jbig2Image } from "./jbig2.js"; import { shadow } from "../shared/util.js"; diff --git a/src/core/jpeg_stream.js b/src/core/jpeg_stream.js index 300f055a8c1cb..cd026f3dcc961 100644 --- a/src/core/jpeg_stream.js +++ b/src/core/jpeg_stream.js @@ -13,7 +13,7 @@ * limitations under the License. */ -import { DecodeStream } from "./stream.js"; +import { DecodeStream } from "./decode_stream.js"; import { isDict } from "./primitives.js"; import { JpegImage } from "./jpg.js"; import { shadow } from "../shared/util.js"; diff --git a/src/core/jpx_stream.js b/src/core/jpx_stream.js index 5808563b2437f..b9d904384cef6 100644 --- a/src/core/jpx_stream.js +++ b/src/core/jpx_stream.js @@ -13,7 +13,7 @@ * limitations under the License. */ -import { DecodeStream } from "./stream.js"; +import { DecodeStream } from "./decode_stream.js"; import { JpxImage } from "./jpx.js"; import { shadow } from "../shared/util.js"; diff --git a/src/core/lzw_stream.js b/src/core/lzw_stream.js index 3ea98adeac814..9a0ae744884a5 100644 --- a/src/core/lzw_stream.js +++ b/src/core/lzw_stream.js @@ -13,7 +13,7 @@ * limitations under the License. */ -import { DecodeStream } from "./stream.js"; +import { DecodeStream } from "./decode_stream.js"; class LZWStream extends DecodeStream { constructor(str, maybeLength, earlyChange) { diff --git a/src/core/predictor_stream.js b/src/core/predictor_stream.js index 1653833f88ab9..9a682f7e0b44f 100644 --- a/src/core/predictor_stream.js +++ b/src/core/predictor_stream.js @@ -13,7 +13,7 @@ * limitations under the License. */ -import { DecodeStream } from "./stream.js"; +import { DecodeStream } from "./decode_stream.js"; import { FormatError } from "../shared/util.js"; import { isDict } from "./primitives.js"; diff --git a/src/core/run_length_stream.js b/src/core/run_length_stream.js index c32d3fcf5550c..8df345fa7ea4b 100644 --- a/src/core/run_length_stream.js +++ b/src/core/run_length_stream.js @@ -13,7 +13,7 @@ * limitations under the License. */ -import { DecodeStream } from "./stream.js"; +import { DecodeStream } from "./decode_stream.js"; class RunLengthStream extends DecodeStream { constructor(str, maybeLength) { diff --git a/src/core/stream.js b/src/core/stream.js index 64e71d5a56a49..dbdc3e187fc1d 100644 --- a/src/core/stream.js +++ b/src/core/stream.js @@ -14,7 +14,7 @@ */ /* eslint-disable no-var */ -import { stringToBytes, unreachable } from "../shared/util.js"; +import { stringToBytes } from "../shared/util.js"; var Stream = (function StreamClosure() { // eslint-disable-next-line no-shadow @@ -134,208 +134,6 @@ var StringStream = (function StringStreamClosure() { return StringStream; })(); -// super class for the decoding streams -var DecodeStream = (function DecodeStreamClosure() { - // Lots of DecodeStreams are created whose buffers are never used. For these - // we share a single empty buffer. This is (a) space-efficient and (b) avoids - // having special cases that would be required if we used |null| for an empty - // buffer. - var emptyBuffer = new Uint8Array(0); - - // eslint-disable-next-line no-shadow - function DecodeStream(maybeMinBufferLength) { - this._rawMinBufferLength = maybeMinBufferLength || 0; - - this.pos = 0; - this.bufferLength = 0; - this.eof = false; - this.buffer = emptyBuffer; - this.minBufferLength = 512; - if (maybeMinBufferLength) { - // Compute the first power of two that is as big as maybeMinBufferLength. - while (this.minBufferLength < maybeMinBufferLength) { - this.minBufferLength *= 2; - } - } - } - - DecodeStream.prototype = { - // eslint-disable-next-line getter-return - get length() { - unreachable("Should not access DecodeStream.length"); - }, - - get isEmpty() { - while (!this.eof && this.bufferLength === 0) { - this.readBlock(); - } - return this.bufferLength === 0; - }, - ensureBuffer: function DecodeStream_ensureBuffer(requested) { - var buffer = this.buffer; - if (requested <= buffer.byteLength) { - return buffer; - } - var size = this.minBufferLength; - while (size < requested) { - size *= 2; - } - var buffer2 = new Uint8Array(size); - buffer2.set(buffer); - return (this.buffer = buffer2); - }, - getByte: function DecodeStream_getByte() { - var pos = this.pos; - while (this.bufferLength <= pos) { - if (this.eof) { - return -1; - } - this.readBlock(); - } - return this.buffer[this.pos++]; - }, - getUint16: function DecodeStream_getUint16() { - var b0 = this.getByte(); - var b1 = this.getByte(); - if (b0 === -1 || b1 === -1) { - return -1; - } - return (b0 << 8) + b1; - }, - getInt32: function DecodeStream_getInt32() { - var b0 = this.getByte(); - var b1 = this.getByte(); - var b2 = this.getByte(); - var b3 = this.getByte(); - return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; - }, - getBytes(length, forceClamped = false) { - var end, - pos = this.pos; - - if (length) { - this.ensureBuffer(pos + length); - end = pos + length; - - while (!this.eof && this.bufferLength < end) { - this.readBlock(); - } - var bufEnd = this.bufferLength; - if (end > bufEnd) { - end = bufEnd; - } - } else { - while (!this.eof) { - this.readBlock(); - } - end = this.bufferLength; - } - - this.pos = end; - const subarray = this.buffer.subarray(pos, end); - // `this.buffer` is either a `Uint8Array` or `Uint8ClampedArray` here. - return forceClamped && !(subarray instanceof Uint8ClampedArray) - ? new Uint8ClampedArray(subarray) - : subarray; - }, - peekByte: function DecodeStream_peekByte() { - var peekedByte = this.getByte(); - if (peekedByte !== -1) { - this.pos--; - } - return peekedByte; - }, - peekBytes(length, forceClamped = false) { - var bytes = this.getBytes(length, forceClamped); - this.pos -= bytes.length; - return bytes; - }, - makeSubStream: function DecodeStream_makeSubStream(start, length, dict) { - if (length === undefined) { - while (!this.eof) { - this.readBlock(); - } - } else { - var end = start + length; - while (this.bufferLength <= end && !this.eof) { - this.readBlock(); - } - } - return new Stream(this.buffer, start, length, dict); - }, - - getByteRange(begin, end) { - unreachable("Should not call DecodeStream.getByteRange"); - }, - - skip: function DecodeStream_skip(n) { - if (!n) { - n = 1; - } - this.pos += n; - }, - reset: function DecodeStream_reset() { - this.pos = 0; - }, - getBaseStreams: function DecodeStream_getBaseStreams() { - if (this.str && this.str.getBaseStreams) { - return this.str.getBaseStreams(); - } - return []; - }, - }; - - return DecodeStream; -})(); - -var StreamsSequenceStream = (function StreamsSequenceStreamClosure() { - // eslint-disable-next-line no-shadow - function StreamsSequenceStream(streams) { - this.streams = streams; - - let maybeLength = 0; - for (let i = 0, ii = streams.length; i < ii; i++) { - const stream = streams[i]; - if (stream instanceof DecodeStream) { - maybeLength += stream._rawMinBufferLength; - } else { - maybeLength += stream.length; - } - } - DecodeStream.call(this, maybeLength); - } - - StreamsSequenceStream.prototype = Object.create(DecodeStream.prototype); - - StreamsSequenceStream.prototype.readBlock = function streamSequenceStreamReadBlock() { - var streams = this.streams; - if (streams.length === 0) { - this.eof = true; - return; - } - var stream = streams.shift(); - var chunk = stream.getBytes(); - var bufferLength = this.bufferLength; - var newLength = bufferLength + chunk.length; - var buffer = this.ensureBuffer(newLength); - buffer.set(chunk, bufferLength); - this.bufferLength = newLength; - }; - - StreamsSequenceStream.prototype.getBaseStreams = function StreamsSequenceStream_getBaseStreams() { - var baseStreams = []; - for (var i = 0, ii = this.streams.length; i < ii; i++) { - var stream = this.streams[i]; - if (stream.getBaseStreams) { - baseStreams.push(...stream.getBaseStreams()); - } - } - return baseStreams; - }; - - return StreamsSequenceStream; -})(); - var NullStream = (function NullStreamClosure() { // eslint-disable-next-line no-shadow function NullStream() { @@ -347,10 +145,4 @@ var NullStream = (function NullStreamClosure() { return NullStream; })(); -export { - DecodeStream, - NullStream, - Stream, - StreamsSequenceStream, - StringStream, -}; +export { NullStream, Stream, StringStream }; From 8ce2cae4a7f0a85af93cc27a9d61928f1255a6fb Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 27 Apr 2021 16:24:33 +0200 Subject: [PATCH 23/30] Enable the `no-var` rule in the `src/core/decode_stream.js` file --- src/core/decode_stream.js | 57 +++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/src/core/decode_stream.js b/src/core/decode_stream.js index f4ff751c30868..01059c7588aa5 100644 --- a/src/core/decode_stream.js +++ b/src/core/decode_stream.js @@ -12,18 +12,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* eslint-disable no-var */ import { Stream } from "./stream.js"; import { unreachable } from "../shared/util.js"; // super class for the decoding streams -var DecodeStream = (function DecodeStreamClosure() { +const DecodeStream = (function DecodeStreamClosure() { // Lots of DecodeStreams are created whose buffers are never used. For these // we share a single empty buffer. This is (a) space-efficient and (b) avoids // having special cases that would be required if we used |null| for an empty // buffer. - var emptyBuffer = new Uint8Array(0); + const emptyBuffer = new Uint8Array(0); // eslint-disable-next-line no-shadow function DecodeStream(maybeMinBufferLength) { @@ -55,20 +54,20 @@ var DecodeStream = (function DecodeStreamClosure() { return this.bufferLength === 0; }, ensureBuffer: function DecodeStream_ensureBuffer(requested) { - var buffer = this.buffer; + const buffer = this.buffer; if (requested <= buffer.byteLength) { return buffer; } - var size = this.minBufferLength; + let size = this.minBufferLength; while (size < requested) { size *= 2; } - var buffer2 = new Uint8Array(size); + const buffer2 = new Uint8Array(size); buffer2.set(buffer); return (this.buffer = buffer2); }, getByte: function DecodeStream_getByte() { - var pos = this.pos; + const pos = this.pos; while (this.bufferLength <= pos) { if (this.eof) { return -1; @@ -78,23 +77,23 @@ var DecodeStream = (function DecodeStreamClosure() { return this.buffer[this.pos++]; }, getUint16: function DecodeStream_getUint16() { - var b0 = this.getByte(); - var b1 = this.getByte(); + const b0 = this.getByte(); + const b1 = this.getByte(); if (b0 === -1 || b1 === -1) { return -1; } return (b0 << 8) + b1; }, getInt32: function DecodeStream_getInt32() { - var b0 = this.getByte(); - var b1 = this.getByte(); - var b2 = this.getByte(); - var b3 = this.getByte(); + const b0 = this.getByte(); + const b1 = this.getByte(); + const b2 = this.getByte(); + const b3 = this.getByte(); return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; }, getBytes(length, forceClamped = false) { - var end, - pos = this.pos; + const pos = this.pos; + let end; if (length) { this.ensureBuffer(pos + length); @@ -103,7 +102,7 @@ var DecodeStream = (function DecodeStreamClosure() { while (!this.eof && this.bufferLength < end) { this.readBlock(); } - var bufEnd = this.bufferLength; + const bufEnd = this.bufferLength; if (end > bufEnd) { end = bufEnd; } @@ -122,14 +121,14 @@ var DecodeStream = (function DecodeStreamClosure() { : subarray; }, peekByte: function DecodeStream_peekByte() { - var peekedByte = this.getByte(); + const peekedByte = this.getByte(); if (peekedByte !== -1) { this.pos--; } return peekedByte; }, peekBytes(length, forceClamped = false) { - var bytes = this.getBytes(length, forceClamped); + const bytes = this.getBytes(length, forceClamped); this.pos -= bytes.length; return bytes; }, @@ -139,7 +138,7 @@ var DecodeStream = (function DecodeStreamClosure() { this.readBlock(); } } else { - var end = start + length; + const end = start + length; while (this.bufferLength <= end && !this.eof) { this.readBlock(); } @@ -171,7 +170,7 @@ var DecodeStream = (function DecodeStreamClosure() { return DecodeStream; })(); -var StreamsSequenceStream = (function StreamsSequenceStreamClosure() { +const StreamsSequenceStream = (function StreamsSequenceStreamClosure() { // eslint-disable-next-line no-shadow function StreamsSequenceStream(streams) { this.streams = streams; @@ -191,24 +190,24 @@ var StreamsSequenceStream = (function StreamsSequenceStreamClosure() { StreamsSequenceStream.prototype = Object.create(DecodeStream.prototype); StreamsSequenceStream.prototype.readBlock = function streamSequenceStreamReadBlock() { - var streams = this.streams; + const streams = this.streams; if (streams.length === 0) { this.eof = true; return; } - var stream = streams.shift(); - var chunk = stream.getBytes(); - var bufferLength = this.bufferLength; - var newLength = bufferLength + chunk.length; - var buffer = this.ensureBuffer(newLength); + const stream = streams.shift(); + const chunk = stream.getBytes(); + const bufferLength = this.bufferLength; + const newLength = bufferLength + chunk.length; + const buffer = this.ensureBuffer(newLength); buffer.set(chunk, bufferLength); this.bufferLength = newLength; }; StreamsSequenceStream.prototype.getBaseStreams = function StreamsSequenceStream_getBaseStreams() { - var baseStreams = []; - for (var i = 0, ii = this.streams.length; i < ii; i++) { - var stream = this.streams[i]; + const baseStreams = []; + for (let i = 0, ii = this.streams.length; i < ii; i++) { + const stream = this.streams[i]; if (stream.getBaseStreams) { baseStreams.push(...stream.getBaseStreams()); } From b11f012e520f1c390a6235907df7b88de3564976 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 27 Apr 2021 16:31:03 +0200 Subject: [PATCH 24/30] Convert `src/core/decode_stream.js` to use standard classes --- src/core/decode_stream.js | 295 +++++++++++++++++++------------------- 1 file changed, 146 insertions(+), 149 deletions(-) diff --git a/src/core/decode_stream.js b/src/core/decode_stream.js index 01059c7588aa5..143b9d62180c8 100644 --- a/src/core/decode_stream.js +++ b/src/core/decode_stream.js @@ -16,16 +16,15 @@ import { Stream } from "./stream.js"; import { unreachable } from "../shared/util.js"; -// super class for the decoding streams -const DecodeStream = (function DecodeStreamClosure() { - // Lots of DecodeStreams are created whose buffers are never used. For these - // we share a single empty buffer. This is (a) space-efficient and (b) avoids - // having special cases that would be required if we used |null| for an empty - // buffer. - const emptyBuffer = new Uint8Array(0); - - // eslint-disable-next-line no-shadow - function DecodeStream(maybeMinBufferLength) { +// Lots of DecodeStreams are created whose buffers are never used. For these +// we share a single empty buffer. This is (a) space-efficient and (b) avoids +// having special cases that would be required if we used |null| for an empty +// buffer. +const emptyBuffer = new Uint8Array(0); + +// Super class for the decoding streams. +class DecodeStream { + constructor(maybeMinBufferLength) { this._rawMinBufferLength = maybeMinBufferLength || 0; this.pos = 0; @@ -41,155 +40,156 @@ const DecodeStream = (function DecodeStreamClosure() { } } - DecodeStream.prototype = { - // eslint-disable-next-line getter-return - get length() { - unreachable("Should not access DecodeStream.length"); - }, + // eslint-disable-next-line getter-return + get length() { + unreachable("Should not access DecodeStream.length"); + } - get isEmpty() { - while (!this.eof && this.bufferLength === 0) { - this.readBlock(); - } - return this.bufferLength === 0; - }, - ensureBuffer: function DecodeStream_ensureBuffer(requested) { - const buffer = this.buffer; - if (requested <= buffer.byteLength) { - return buffer; - } - let size = this.minBufferLength; - while (size < requested) { - size *= 2; + get isEmpty() { + while (!this.eof && this.bufferLength === 0) { + this.readBlock(); + } + return this.bufferLength === 0; + } + + ensureBuffer(requested) { + const buffer = this.buffer; + if (requested <= buffer.byteLength) { + return buffer; + } + let size = this.minBufferLength; + while (size < requested) { + size *= 2; + } + const buffer2 = new Uint8Array(size); + buffer2.set(buffer); + return (this.buffer = buffer2); + } + + getByte() { + const pos = this.pos; + while (this.bufferLength <= pos) { + if (this.eof) { + return -1; } - const buffer2 = new Uint8Array(size); - buffer2.set(buffer); - return (this.buffer = buffer2); - }, - getByte: function DecodeStream_getByte() { - const pos = this.pos; - while (this.bufferLength <= pos) { - if (this.eof) { - return -1; - } + this.readBlock(); + } + return this.buffer[this.pos++]; + } + + getUint16() { + const b0 = this.getByte(); + const b1 = this.getByte(); + if (b0 === -1 || b1 === -1) { + return -1; + } + return (b0 << 8) + b1; + } + + getInt32() { + const b0 = this.getByte(); + const b1 = this.getByte(); + const b2 = this.getByte(); + const b3 = this.getByte(); + return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; + } + + getBytes(length, forceClamped = false) { + const pos = this.pos; + let end; + + if (length) { + this.ensureBuffer(pos + length); + end = pos + length; + + while (!this.eof && this.bufferLength < end) { this.readBlock(); } - return this.buffer[this.pos++]; - }, - getUint16: function DecodeStream_getUint16() { - const b0 = this.getByte(); - const b1 = this.getByte(); - if (b0 === -1 || b1 === -1) { - return -1; + const bufEnd = this.bufferLength; + if (end > bufEnd) { + end = bufEnd; } - return (b0 << 8) + b1; - }, - getInt32: function DecodeStream_getInt32() { - const b0 = this.getByte(); - const b1 = this.getByte(); - const b2 = this.getByte(); - const b3 = this.getByte(); - return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; - }, - getBytes(length, forceClamped = false) { - const pos = this.pos; - let end; - - if (length) { - this.ensureBuffer(pos + length); - end = pos + length; - - while (!this.eof && this.bufferLength < end) { - this.readBlock(); - } - const bufEnd = this.bufferLength; - if (end > bufEnd) { - end = bufEnd; - } - } else { - while (!this.eof) { - this.readBlock(); - } - end = this.bufferLength; + } else { + while (!this.eof) { + this.readBlock(); } + end = this.bufferLength; + } - this.pos = end; - const subarray = this.buffer.subarray(pos, end); - // `this.buffer` is either a `Uint8Array` or `Uint8ClampedArray` here. - return forceClamped && !(subarray instanceof Uint8ClampedArray) - ? new Uint8ClampedArray(subarray) - : subarray; - }, - peekByte: function DecodeStream_peekByte() { - const peekedByte = this.getByte(); - if (peekedByte !== -1) { - this.pos--; - } - return peekedByte; - }, - peekBytes(length, forceClamped = false) { - const bytes = this.getBytes(length, forceClamped); - this.pos -= bytes.length; - return bytes; - }, - makeSubStream: function DecodeStream_makeSubStream(start, length, dict) { - if (length === undefined) { - while (!this.eof) { - this.readBlock(); - } - } else { - const end = start + length; - while (this.bufferLength <= end && !this.eof) { - this.readBlock(); - } - } - return new Stream(this.buffer, start, length, dict); - }, + this.pos = end; + const subarray = this.buffer.subarray(pos, end); + // `this.buffer` is either a `Uint8Array` or `Uint8ClampedArray` here. + return forceClamped && !(subarray instanceof Uint8ClampedArray) + ? new Uint8ClampedArray(subarray) + : subarray; + } - getByteRange(begin, end) { - unreachable("Should not call DecodeStream.getByteRange"); - }, + peekByte() { + const peekedByte = this.getByte(); + if (peekedByte !== -1) { + this.pos--; + } + return peekedByte; + } - skip: function DecodeStream_skip(n) { - if (!n) { - n = 1; + peekBytes(length, forceClamped = false) { + const bytes = this.getBytes(length, forceClamped); + this.pos -= bytes.length; + return bytes; + } + + makeSubStream(start, length, dict = null) { + if (length === undefined) { + while (!this.eof) { + this.readBlock(); } - this.pos += n; - }, - reset: function DecodeStream_reset() { - this.pos = 0; - }, - getBaseStreams: function DecodeStream_getBaseStreams() { - if (this.str && this.str.getBaseStreams) { - return this.str.getBaseStreams(); + } else { + const end = start + length; + while (this.bufferLength <= end && !this.eof) { + this.readBlock(); } - return []; - }, - }; + } + return new Stream(this.buffer, start, length, dict); + } - return DecodeStream; -})(); + getByteRange(begin, end) { + unreachable("Should not call DecodeStream.getByteRange"); + } -const StreamsSequenceStream = (function StreamsSequenceStreamClosure() { - // eslint-disable-next-line no-shadow - function StreamsSequenceStream(streams) { - this.streams = streams; + skip(n) { + if (!n) { + n = 1; + } + this.pos += n; + } - let maybeLength = 0; - for (let i = 0, ii = streams.length; i < ii; i++) { - const stream = streams[i]; - if (stream instanceof DecodeStream) { - maybeLength += stream._rawMinBufferLength; - } else { - maybeLength += stream.length; - } + reset() { + this.pos = 0; + } + + getBaseStreams() { + if (this.str && this.str.getBaseStreams) { + return this.str.getBaseStreams(); } - DecodeStream.call(this, maybeLength); + return []; } +} - StreamsSequenceStream.prototype = Object.create(DecodeStream.prototype); +class StreamsSequenceStream extends DecodeStream { + constructor(streams) { + let maybeLength = 0; + for (const stream of streams) { + maybeLength += + stream instanceof DecodeStream + ? stream._rawMinBufferLength + : stream.length; + } + super(maybeLength); - StreamsSequenceStream.prototype.readBlock = function streamSequenceStreamReadBlock() { + this.streams = streams; + } + + readBlock() { const streams = this.streams; if (streams.length === 0) { this.eof = true; @@ -202,20 +202,17 @@ const StreamsSequenceStream = (function StreamsSequenceStreamClosure() { const buffer = this.ensureBuffer(newLength); buffer.set(chunk, bufferLength); this.bufferLength = newLength; - }; + } - StreamsSequenceStream.prototype.getBaseStreams = function StreamsSequenceStream_getBaseStreams() { + getBaseStreams() { const baseStreams = []; - for (let i = 0, ii = this.streams.length; i < ii; i++) { - const stream = this.streams[i]; + for (const stream of this.streams) { if (stream.getBaseStreams) { baseStreams.push(...stream.getBaseStreams()); } } return baseStreams; - }; - - return StreamsSequenceStream; -})(); + } +} export { DecodeStream, StreamsSequenceStream }; From 29cf415a69406d082f848b868692f48af61d45b7 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 27 Apr 2021 16:32:26 +0200 Subject: [PATCH 25/30] Enable the `no-var` rule in the `src/core/stream.js` file --- src/core/stream.js | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/core/stream.js b/src/core/stream.js index dbdc3e187fc1d..0f539df1597b9 100644 --- a/src/core/stream.js +++ b/src/core/stream.js @@ -12,11 +12,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* eslint-disable no-var */ import { stringToBytes } from "../shared/util.js"; -var Stream = (function StreamClosure() { +const Stream = (function StreamClosure() { // eslint-disable-next-line no-shadow function Stream(arrayBuffer, start, length, dict) { this.bytes = @@ -45,32 +44,32 @@ var Stream = (function StreamClosure() { return this.bytes[this.pos++]; }, getUint16: function Stream_getUint16() { - var b0 = this.getByte(); - var b1 = this.getByte(); + const b0 = this.getByte(); + const b1 = this.getByte(); if (b0 === -1 || b1 === -1) { return -1; } return (b0 << 8) + b1; }, getInt32: function Stream_getInt32() { - var b0 = this.getByte(); - var b1 = this.getByte(); - var b2 = this.getByte(); - var b3 = this.getByte(); + const b0 = this.getByte(); + const b1 = this.getByte(); + const b2 = this.getByte(); + const b3 = this.getByte(); return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; }, // Returns subarray of original buffer, should only be read. getBytes(length, forceClamped = false) { - var bytes = this.bytes; - var pos = this.pos; - var strEnd = this.end; + const bytes = this.bytes; + const pos = this.pos; + const strEnd = this.end; if (!length) { const subarray = bytes.subarray(pos, strEnd); // `this.bytes` is always a `Uint8Array` here. return forceClamped ? new Uint8ClampedArray(subarray) : subarray; } - var end = pos + length; + let end = pos + length; if (end > strEnd) { end = strEnd; } @@ -80,14 +79,14 @@ var Stream = (function StreamClosure() { return forceClamped ? new Uint8ClampedArray(subarray) : subarray; }, peekByte: function Stream_peekByte() { - var peekedByte = this.getByte(); + const peekedByte = this.getByte(); if (peekedByte !== -1) { this.pos--; } return peekedByte; }, peekBytes(length, forceClamped = false) { - var bytes = this.getBytes(length, forceClamped); + const bytes = this.getBytes(length, forceClamped); this.pos -= bytes.length; return bytes; }, @@ -122,7 +121,7 @@ var Stream = (function StreamClosure() { return Stream; })(); -var StringStream = (function StringStreamClosure() { +const StringStream = (function StringStreamClosure() { // eslint-disable-next-line no-shadow function StringStream(str) { const bytes = stringToBytes(str); @@ -134,7 +133,7 @@ var StringStream = (function StringStreamClosure() { return StringStream; })(); -var NullStream = (function NullStreamClosure() { +const NullStream = (function NullStreamClosure() { // eslint-disable-next-line no-shadow function NullStream() { Stream.call(this, new Uint8Array(0)); From 6151b4ecac955471dd7e48cbb01f758b12b2b9dc Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 27 Apr 2021 16:35:35 +0200 Subject: [PATCH 26/30] Convert `src/core/stream.js` to use standard classes --- src/core/stream.js | 224 ++++++++++++++++++++++----------------------- 1 file changed, 108 insertions(+), 116 deletions(-) diff --git a/src/core/stream.js b/src/core/stream.js index 0f539df1597b9..febe230b38a79 100644 --- a/src/core/stream.js +++ b/src/core/stream.js @@ -15,9 +15,8 @@ import { stringToBytes } from "../shared/util.js"; -const Stream = (function StreamClosure() { - // eslint-disable-next-line no-shadow - function Stream(arrayBuffer, start, length, dict) { +class Stream { + constructor(arrayBuffer, start, length, dict) { this.bytes = arrayBuffer instanceof Uint8Array ? arrayBuffer @@ -28,120 +27,113 @@ const Stream = (function StreamClosure() { this.dict = dict; } - // required methods for a stream. if a particular stream does not - // implement these, an error should be thrown - Stream.prototype = { - get length() { - return this.end - this.start; - }, - get isEmpty() { - return this.length === 0; - }, - getByte: function Stream_getByte() { - if (this.pos >= this.end) { - return -1; - } - return this.bytes[this.pos++]; - }, - getUint16: function Stream_getUint16() { - const b0 = this.getByte(); - const b1 = this.getByte(); - if (b0 === -1 || b1 === -1) { - return -1; - } - return (b0 << 8) + b1; - }, - getInt32: function Stream_getInt32() { - const b0 = this.getByte(); - const b1 = this.getByte(); - const b2 = this.getByte(); - const b3 = this.getByte(); - return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; - }, - // Returns subarray of original buffer, should only be read. - getBytes(length, forceClamped = false) { - const bytes = this.bytes; - const pos = this.pos; - const strEnd = this.end; - - if (!length) { - const subarray = bytes.subarray(pos, strEnd); - // `this.bytes` is always a `Uint8Array` here. - return forceClamped ? new Uint8ClampedArray(subarray) : subarray; - } - let end = pos + length; - if (end > strEnd) { - end = strEnd; - } - this.pos = end; - const subarray = bytes.subarray(pos, end); + get length() { + return this.end - this.start; + } + + get isEmpty() { + return this.length === 0; + } + + getByte() { + if (this.pos >= this.end) { + return -1; + } + return this.bytes[this.pos++]; + } + + getUint16() { + const b0 = this.getByte(); + const b1 = this.getByte(); + if (b0 === -1 || b1 === -1) { + return -1; + } + return (b0 << 8) + b1; + } + + getInt32() { + const b0 = this.getByte(); + const b1 = this.getByte(); + const b2 = this.getByte(); + const b3 = this.getByte(); + return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; + } + + // Returns subarray of original buffer, should only be read. + getBytes(length, forceClamped = false) { + const bytes = this.bytes; + const pos = this.pos; + const strEnd = this.end; + + if (!length) { + const subarray = bytes.subarray(pos, strEnd); // `this.bytes` is always a `Uint8Array` here. return forceClamped ? new Uint8ClampedArray(subarray) : subarray; - }, - peekByte: function Stream_peekByte() { - const peekedByte = this.getByte(); - if (peekedByte !== -1) { - this.pos--; - } - return peekedByte; - }, - peekBytes(length, forceClamped = false) { - const bytes = this.getBytes(length, forceClamped); - this.pos -= bytes.length; - return bytes; - }, - - getByteRange(begin, end) { - if (begin < 0) { - begin = 0; - } - if (end > this.end) { - end = this.end; - } - return this.bytes.subarray(begin, end); - }, - - skip: function Stream_skip(n) { - if (!n) { - n = 1; - } - this.pos += n; - }, - reset: function Stream_reset() { - this.pos = this.start; - }, - moveStart: function Stream_moveStart() { - this.start = this.pos; - }, - makeSubStream: function Stream_makeSubStream(start, length, dict) { - return new Stream(this.bytes.buffer, start, length, dict); - }, - }; - - return Stream; -})(); - -const StringStream = (function StringStreamClosure() { - // eslint-disable-next-line no-shadow - function StringStream(str) { - const bytes = stringToBytes(str); - Stream.call(this, bytes); - } - - StringStream.prototype = Stream.prototype; - - return StringStream; -})(); - -const NullStream = (function NullStreamClosure() { - // eslint-disable-next-line no-shadow - function NullStream() { - Stream.call(this, new Uint8Array(0)); - } - - NullStream.prototype = Stream.prototype; - - return NullStream; -})(); + } + let end = pos + length; + if (end > strEnd) { + end = strEnd; + } + this.pos = end; + const subarray = bytes.subarray(pos, end); + // `this.bytes` is always a `Uint8Array` here. + return forceClamped ? new Uint8ClampedArray(subarray) : subarray; + } + + peekByte() { + const peekedByte = this.getByte(); + if (peekedByte !== -1) { + this.pos--; + } + return peekedByte; + } + + peekBytes(length, forceClamped = false) { + const bytes = this.getBytes(length, forceClamped); + this.pos -= bytes.length; + return bytes; + } + + getByteRange(begin, end) { + if (begin < 0) { + begin = 0; + } + if (end > this.end) { + end = this.end; + } + return this.bytes.subarray(begin, end); + } + + skip(n) { + if (!n) { + n = 1; + } + this.pos += n; + } + + reset() { + this.pos = this.start; + } + + moveStart() { + this.start = this.pos; + } + + makeSubStream(start, length, dict = null) { + return new Stream(this.bytes.buffer, start, length, dict); + } +} + +class StringStream extends Stream { + constructor(str) { + super(stringToBytes(str)); + } +} + +class NullStream extends Stream { + constructor() { + super(new Uint8Array(0)); + } +} export { NullStream, Stream, StringStream }; From 67415bfabe02bf34f2819131aa3df30dfa81f2a9 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 27 Apr 2021 17:08:54 +0200 Subject: [PATCH 27/30] Add an abstract base-class, which all the various Stream implementations inherit from By having an abstract base-class, it becomes a lot clearer exactly which methods/getters are expected to exist on all Stream instances. Furthermore, since a number of the methods are *identical* for all Stream implementations, this reduces unnecessary code duplication in the `Stream`, `DecodeStream`, and `ChunkedStream` classes. For e.g. `gulp mozcentral`, the *built* `pdf.worker.js` files decreases from `1 619 329` to `1 616 115` bytes with this patch-series. --- src/core/base_stream.js | 99 ++++++++++++++++++++++++++++++++++++++ src/core/chunked_stream.js | 73 ++++++++-------------------- src/core/decode_stream.js | 56 ++------------------- src/core/object_loader.js | 21 +++----- src/core/primitives.js | 3 +- src/core/stream.js | 44 ++--------------- 6 files changed, 138 insertions(+), 158 deletions(-) create mode 100644 src/core/base_stream.js diff --git a/src/core/base_stream.js b/src/core/base_stream.js new file mode 100644 index 0000000000000..21333249b773b --- /dev/null +++ b/src/core/base_stream.js @@ -0,0 +1,99 @@ +/* Copyright 2021 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { shadow, unreachable } from "../shared/util.js"; + +class BaseStream { + constructor() { + if (this.constructor === BaseStream) { + unreachable("Cannot initialize BaseStream."); + } + } + + // eslint-disable-next-line getter-return + get length() { + unreachable("Abstract getter `length` accessed"); + } + + // eslint-disable-next-line getter-return + get isEmpty() { + unreachable("Abstract getter `isEmpty` accessed"); + } + + get isDataLoaded() { + return shadow(this, "isDataLoaded", true); + } + + getByte() { + unreachable("Abstract method `getByte` called"); + } + + getBytes(length, forceClamped = false) { + unreachable("Abstract method `getBytes` called"); + } + + peekByte() { + const peekedByte = this.getByte(); + if (peekedByte !== -1) { + this.pos--; + } + return peekedByte; + } + + peekBytes(length, forceClamped = false) { + const bytes = this.getBytes(length, forceClamped); + this.pos -= bytes.length; + return bytes; + } + + getUint16() { + const b0 = this.getByte(); + const b1 = this.getByte(); + if (b0 === -1 || b1 === -1) { + return -1; + } + return (b0 << 8) + b1; + } + + getInt32() { + const b0 = this.getByte(); + const b1 = this.getByte(); + const b2 = this.getByte(); + const b3 = this.getByte(); + return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; + } + + getByteRange(begin, end) { + unreachable("Abstract method `getByteRange` called"); + } + + skip(n) { + this.pos += n || 1; + } + + reset() { + unreachable("Abstract method `reset` called"); + } + + moveStart() { + unreachable("Abstract method `moveStart` called"); + } + + makeSubStream(start, length, dict = null) { + unreachable("Abstract method `makeSubStream` called"); + } +} + +export { BaseStream }; diff --git a/src/core/chunked_stream.js b/src/core/chunked_stream.js index 451984874b7e2..28b4ebe0d52bc 100644 --- a/src/core/chunked_stream.js +++ b/src/core/chunked_stream.js @@ -18,10 +18,13 @@ import { arraysToBytes, createPromiseCapability, } from "../shared/util.js"; +import { BaseStream } from "./base_stream.js"; import { MissingDataException } from "./core_utils.js"; -class ChunkedStream { +class ChunkedStream extends BaseStream { constructor(length, chunkSize, manager) { + super(); + this.bytes = new Uint8Array(length); this.start = 0; this.pos = 0; @@ -46,15 +49,11 @@ class ChunkedStream { return chunks; } - getBaseStreams() { - return [this]; - } - get numChunksLoaded() { return this._loadedChunks.size; } - allChunksLoaded() { + get isDataLoaded() { return this.numChunksLoaded === this.numChunks; } @@ -169,24 +168,6 @@ class ChunkedStream { return this.bytes[this.pos++]; } - getUint16() { - const b0 = this.getByte(); - const b1 = this.getByte(); - if (b0 === -1 || b1 === -1) { - return -1; - } - return (b0 << 8) + b1; - } - - getInt32() { - const b0 = this.getByte(); - const b1 = this.getByte(); - const b2 = this.getByte(); - const b3 = this.getByte(); - return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; - } - - // Returns subarray of original buffer, should only be read. getBytes(length, forceClamped = false) { const bytes = this.bytes; const pos = this.pos; @@ -215,20 +196,6 @@ class ChunkedStream { return forceClamped ? new Uint8ClampedArray(subarray) : subarray; } - peekByte() { - const peekedByte = this.getByte(); - if (peekedByte !== -1) { - this.pos--; - } - return peekedByte; - } - - peekBytes(length, forceClamped = false) { - const bytes = this.getBytes(length, forceClamped); - this.pos -= bytes.length; - return bytes; - } - getByteRange(begin, end) { if (begin < 0) { begin = 0; @@ -242,13 +209,6 @@ class ChunkedStream { return this.bytes.subarray(begin, end); } - skip(n) { - if (!n) { - n = 1; - } - this.pos += n; - } - reset() { this.pos = this.start; } @@ -257,7 +217,7 @@ class ChunkedStream { this.start = this.pos; } - makeSubStream(start, length, dict) { + makeSubStream(start, length, dict = null) { if (length) { if (start + length > this.progressiveDataLength) { this.ensureRange(start, start + length); @@ -291,12 +251,15 @@ class ChunkedStream { } return missingChunks; }; - ChunkedStreamSubstream.prototype.allChunksLoaded = function () { - if (this.numChunksLoaded === this.numChunks) { - return true; - } - return this.getMissingChunks().length === 0; - }; + Object.defineProperty(ChunkedStreamSubstream.prototype, "isDataLoaded", { + get() { + if (this.numChunksLoaded === this.numChunks) { + return true; + } + return this.getMissingChunks().length === 0; + }, + configurable: true, + }); const subStream = new ChunkedStreamSubstream(); subStream.pos = subStream.start = start; @@ -304,6 +267,10 @@ class ChunkedStream { subStream.dict = dict; return subStream; } + + getBaseStreams() { + return [this]; + } } class ChunkedStreamManager { @@ -521,7 +488,7 @@ class ChunkedStreamManager { this.stream.onReceiveData(begin, chunk); } - if (this.stream.allChunksLoaded()) { + if (this.stream.isDataLoaded) { this._loadedStreamCapability.resolve(this.stream); } diff --git a/src/core/decode_stream.js b/src/core/decode_stream.js index 143b9d62180c8..9c74243387d47 100644 --- a/src/core/decode_stream.js +++ b/src/core/decode_stream.js @@ -13,8 +13,8 @@ * limitations under the License. */ +import { BaseStream } from "./base_stream.js"; import { Stream } from "./stream.js"; -import { unreachable } from "../shared/util.js"; // Lots of DecodeStreams are created whose buffers are never used. For these // we share a single empty buffer. This is (a) space-efficient and (b) avoids @@ -23,8 +23,9 @@ import { unreachable } from "../shared/util.js"; const emptyBuffer = new Uint8Array(0); // Super class for the decoding streams. -class DecodeStream { +class DecodeStream extends BaseStream { constructor(maybeMinBufferLength) { + super(); this._rawMinBufferLength = maybeMinBufferLength || 0; this.pos = 0; @@ -40,11 +41,6 @@ class DecodeStream { } } - // eslint-disable-next-line getter-return - get length() { - unreachable("Should not access DecodeStream.length"); - } - get isEmpty() { while (!this.eof && this.bufferLength === 0) { this.readBlock(); @@ -77,23 +73,6 @@ class DecodeStream { return this.buffer[this.pos++]; } - getUint16() { - const b0 = this.getByte(); - const b1 = this.getByte(); - if (b0 === -1 || b1 === -1) { - return -1; - } - return (b0 << 8) + b1; - } - - getInt32() { - const b0 = this.getByte(); - const b1 = this.getByte(); - const b2 = this.getByte(); - const b3 = this.getByte(); - return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; - } - getBytes(length, forceClamped = false) { const pos = this.pos; let end; @@ -124,18 +103,8 @@ class DecodeStream { : subarray; } - peekByte() { - const peekedByte = this.getByte(); - if (peekedByte !== -1) { - this.pos--; - } - return peekedByte; - } - - peekBytes(length, forceClamped = false) { - const bytes = this.getBytes(length, forceClamped); - this.pos -= bytes.length; - return bytes; + reset() { + this.pos = 0; } makeSubStream(start, length, dict = null) { @@ -152,21 +121,6 @@ class DecodeStream { return new Stream(this.buffer, start, length, dict); } - getByteRange(begin, end) { - unreachable("Should not call DecodeStream.getByteRange"); - } - - skip(n) { - if (!n) { - n = 1; - } - this.pos += n; - } - - reset() { - this.pos = 0; - } - getBaseStreams() { if (this.str && this.str.getBaseStreams) { return this.str.getBaseStreams(); diff --git a/src/core/object_loader.js b/src/core/object_loader.js index f36016e6eb84f..1812bd84cd27a 100644 --- a/src/core/object_loader.js +++ b/src/core/object_loader.js @@ -61,12 +61,8 @@ class ObjectLoader { } async load() { - // Don't walk the graph if all the data is already loaded; note that only - // `ChunkedStream` instances have a `allChunksLoaded` method. - if ( - !this.xref.stream.allChunksLoaded || - this.xref.stream.allChunksLoaded() - ) { + // Don't walk the graph if all the data is already loaded. + if (this.xref.stream.isDataLoaded) { return undefined; } @@ -115,12 +111,12 @@ class ObjectLoader { if (currentNode && currentNode.getBaseStreams) { const baseStreams = currentNode.getBaseStreams(); let foundMissingData = false; - for (let i = 0, ii = baseStreams.length; i < ii; i++) { - const stream = baseStreams[i]; - if (stream.allChunksLoaded && !stream.allChunksLoaded()) { - foundMissingData = true; - pendingRequests.push({ begin: stream.start, end: stream.end }); + for (const stream of baseStreams) { + if (stream.isDataLoaded) { + continue; } + foundMissingData = true; + pendingRequests.push({ begin: stream.start, end: stream.end }); } if (foundMissingData) { nodesToRevisit.push(currentNode); @@ -133,8 +129,7 @@ class ObjectLoader { if (pendingRequests.length) { await this.xref.stream.manager.requestRanges(pendingRequests); - for (let i = 0, ii = nodesToRevisit.length; i < ii; i++) { - const node = nodesToRevisit[i]; + for (const node of nodesToRevisit) { // Remove any reference nodes from the current `RefSet` so they // aren't skipped when we revist them. if (node instanceof Ref) { diff --git a/src/core/primitives.js b/src/core/primitives.js index 7e0d36ea2092e..e58e513f8b4fd 100644 --- a/src/core/primitives.js +++ b/src/core/primitives.js @@ -14,6 +14,7 @@ */ import { assert, unreachable } from "../shared/util.js"; +import { BaseStream } from "./base_stream.js"; const EOF = {}; @@ -383,7 +384,7 @@ function isRefsEqual(v1, v2) { } function isStream(v) { - return typeof v === "object" && v !== null && v.getBytes !== undefined; + return v instanceof BaseStream; } function clearPrimitiveCaches() { diff --git a/src/core/stream.js b/src/core/stream.js index febe230b38a79..6f24c44709b1d 100644 --- a/src/core/stream.js +++ b/src/core/stream.js @@ -13,10 +13,13 @@ * limitations under the License. */ +import { BaseStream } from "./base_stream.js"; import { stringToBytes } from "../shared/util.js"; -class Stream { +class Stream extends BaseStream { constructor(arrayBuffer, start, length, dict) { + super(); + this.bytes = arrayBuffer instanceof Uint8Array ? arrayBuffer @@ -42,24 +45,6 @@ class Stream { return this.bytes[this.pos++]; } - getUint16() { - const b0 = this.getByte(); - const b1 = this.getByte(); - if (b0 === -1 || b1 === -1) { - return -1; - } - return (b0 << 8) + b1; - } - - getInt32() { - const b0 = this.getByte(); - const b1 = this.getByte(); - const b2 = this.getByte(); - const b3 = this.getByte(); - return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3; - } - - // Returns subarray of original buffer, should only be read. getBytes(length, forceClamped = false) { const bytes = this.bytes; const pos = this.pos; @@ -80,20 +65,6 @@ class Stream { return forceClamped ? new Uint8ClampedArray(subarray) : subarray; } - peekByte() { - const peekedByte = this.getByte(); - if (peekedByte !== -1) { - this.pos--; - } - return peekedByte; - } - - peekBytes(length, forceClamped = false) { - const bytes = this.getBytes(length, forceClamped); - this.pos -= bytes.length; - return bytes; - } - getByteRange(begin, end) { if (begin < 0) { begin = 0; @@ -104,13 +75,6 @@ class Stream { return this.bytes.subarray(begin, end); } - skip(n) { - if (!n) { - n = 1; - } - this.pos += n; - } - reset() { this.pos = this.start; } From 67a1cfc1b11563ac7ac574865be9bfe3ab180b6c Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Wed, 28 Apr 2021 11:57:29 +0200 Subject: [PATCH 28/30] Improve the handling `getBaseStreams`, on the various Stream implementations The way that `getBaseStreams` is currently handled has bothered me from time to time, especially how we're checking if the method exists before calling it. By adding a dummy `BaseStream.getBaseStreams` method, and having the call-sites simply check the return value, we can improve some of the relevant code. Note in particular how the `ObjectLoader._walk` method didn't actually check that the data in question is a Stream instance, and instead only checked the `currentNode` (which could be anything) for the existence of a `getBaseStreams` property. --- src/core/base_stream.js | 7 +++++++ src/core/decode_stream.js | 14 ++++++-------- src/core/object_loader.js | 22 ++++++++++++---------- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/core/base_stream.js b/src/core/base_stream.js index 21333249b773b..86f9eb7698760 100644 --- a/src/core/base_stream.js +++ b/src/core/base_stream.js @@ -94,6 +94,13 @@ class BaseStream { makeSubStream(start, length, dict = null) { unreachable("Abstract method `makeSubStream` called"); } + + /** + * @returns {Array | null} + */ + getBaseStreams() { + return null; + } } export { BaseStream }; diff --git a/src/core/decode_stream.js b/src/core/decode_stream.js index 9c74243387d47..701d78decb175 100644 --- a/src/core/decode_stream.js +++ b/src/core/decode_stream.js @@ -122,10 +122,7 @@ class DecodeStream extends BaseStream { } getBaseStreams() { - if (this.str && this.str.getBaseStreams) { - return this.str.getBaseStreams(); - } - return []; + return this.str ? this.str.getBaseStreams() : null; } } @@ -159,13 +156,14 @@ class StreamsSequenceStream extends DecodeStream { } getBaseStreams() { - const baseStreams = []; + const baseStreamsBuf = []; for (const stream of this.streams) { - if (stream.getBaseStreams) { - baseStreams.push(...stream.getBaseStreams()); + const baseStreams = stream.getBaseStreams(); + if (baseStreams) { + baseStreamsBuf.push(...baseStreams); } } - return baseStreams; + return baseStreamsBuf.length > 0 ? baseStreamsBuf : null; } } diff --git a/src/core/object_loader.js b/src/core/object_loader.js index 1812bd84cd27a..b79e90320055b 100644 --- a/src/core/object_loader.js +++ b/src/core/object_loader.js @@ -108,18 +108,20 @@ class ObjectLoader { pendingRequests.push({ begin: ex.begin, end: ex.end }); } } - if (currentNode && currentNode.getBaseStreams) { + if (isStream(currentNode)) { const baseStreams = currentNode.getBaseStreams(); - let foundMissingData = false; - for (const stream of baseStreams) { - if (stream.isDataLoaded) { - continue; + if (baseStreams) { + let foundMissingData = false; + for (const stream of baseStreams) { + if (stream.isDataLoaded) { + continue; + } + foundMissingData = true; + pendingRequests.push({ begin: stream.start, end: stream.end }); + } + if (foundMissingData) { + nodesToRevisit.push(currentNode); } - foundMissingData = true; - pendingRequests.push({ begin: stream.start, end: stream.end }); - } - if (foundMissingData) { - nodesToRevisit.push(currentNode); } } From fb0775525e62c0bc46bc2eea03f1df129b5ed1f9 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Tue, 27 Apr 2021 22:35:53 +0200 Subject: [PATCH 29/30] Stop special-casing the `dict` parameter in the `Jbig2Stream`/`JpegStream`/`JpxStream` constructors For all of the other `DecodeStream`s we're not passing in a `Dict`-instance manually, but instead get it from the `stream`-parameter. Hence there's no particularly good reason, as far as I can tell, to not do the same thing in `Jbig2Stream`/`JpegStream`/`JpxStream` as well. --- src/core/jbig2_stream.js | 4 ++-- src/core/jpeg_stream.js | 4 ++-- src/core/jpx_stream.js | 4 ++-- src/core/parser.js | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/core/jbig2_stream.js b/src/core/jbig2_stream.js index dda50f6d66ad4..172ea6aa08c4c 100644 --- a/src/core/jbig2_stream.js +++ b/src/core/jbig2_stream.js @@ -23,12 +23,12 @@ import { shadow } from "../shared/util.js"; * the stream behaves like all the other DecodeStreams. */ class Jbig2Stream extends DecodeStream { - constructor(stream, maybeLength, dict, params) { + constructor(stream, maybeLength, params) { super(maybeLength); this.stream = stream; + this.dict = stream.dict; this.maybeLength = maybeLength; - this.dict = dict; this.params = params; } diff --git a/src/core/jpeg_stream.js b/src/core/jpeg_stream.js index cd026f3dcc961..e8a0be58838bc 100644 --- a/src/core/jpeg_stream.js +++ b/src/core/jpeg_stream.js @@ -23,7 +23,7 @@ import { shadow } from "../shared/util.js"; * like all the other DecodeStreams. */ class JpegStream extends DecodeStream { - constructor(stream, maybeLength, dict, params) { + constructor(stream, maybeLength, params) { // Some images may contain 'junk' before the SOI (start-of-image) marker. // Note: this seems to mainly affect inline images. let ch; @@ -37,8 +37,8 @@ class JpegStream extends DecodeStream { super(maybeLength); this.stream = stream; + this.dict = stream.dict; this.maybeLength = maybeLength; - this.dict = dict; this.params = params; } diff --git a/src/core/jpx_stream.js b/src/core/jpx_stream.js index b9d904384cef6..82f0e5286a1b2 100644 --- a/src/core/jpx_stream.js +++ b/src/core/jpx_stream.js @@ -22,12 +22,12 @@ import { shadow } from "../shared/util.js"; * the stream behaves like all the other DecodeStreams. */ class JpxStream extends DecodeStream { - constructor(stream, maybeLength, dict, params) { + constructor(stream, maybeLength, params) { super(maybeLength); this.stream = stream; + this.dict = stream.dict; this.maybeLength = maybeLength; - this.dict = dict; this.params = params; } diff --git a/src/core/parser.js b/src/core/parser.js index 24b5cabf5fc21..ca56a09f79dee 100644 --- a/src/core/parser.js +++ b/src/core/parser.js @@ -765,11 +765,11 @@ class Parser { } if (name === "DCTDecode" || name === "DCT") { xrefStreamStats[StreamType.DCT] = true; - return new JpegStream(stream, maybeLength, stream.dict, params); + return new JpegStream(stream, maybeLength, params); } if (name === "JPXDecode" || name === "JPX") { xrefStreamStats[StreamType.JPX] = true; - return new JpxStream(stream, maybeLength, stream.dict, params); + return new JpxStream(stream, maybeLength, params); } if (name === "ASCII85Decode" || name === "A85") { xrefStreamStats[StreamType.A85] = true; @@ -789,7 +789,7 @@ class Parser { } if (name === "JBIG2Decode") { xrefStreamStats[StreamType.JBIG] = true; - return new Jbig2Stream(stream, maybeLength, stream.dict, params); + return new Jbig2Stream(stream, maybeLength, params); } warn(`Filter "${name}" is not supported.`); return stream; From 2ac4ad3111fb8a328d1d2fca1f75fb918c569f97 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Wed, 28 Apr 2021 14:05:25 +0200 Subject: [PATCH 30/30] Let `ChunkedStream` extend `Stream`, rather than `BaseStream` directly Looking at the `ChunkedStream` implementation, it's basically a "regular" `Stream` but with added functionality in order to deal with fetching/loading of missing data. Hence, by letting `ChunkedStream` extend `Stream`, we can remove some duplicate methods from the `ChunkedStream` class. --- src/core/chunked_stream.js | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/src/core/chunked_stream.js b/src/core/chunked_stream.js index 28b4ebe0d52bc..5bfe512eb30ea 100644 --- a/src/core/chunked_stream.js +++ b/src/core/chunked_stream.js @@ -18,17 +18,18 @@ import { arraysToBytes, createPromiseCapability, } from "../shared/util.js"; -import { BaseStream } from "./base_stream.js"; import { MissingDataException } from "./core_utils.js"; +import { Stream } from "./stream.js"; -class ChunkedStream extends BaseStream { +class ChunkedStream extends Stream { constructor(length, chunkSize, manager) { - super(); + super( + /* arrayBuffer = */ new Uint8Array(length), + /* start = */ 0, + /* length = */ length, + /* dict = */ null + ); - this.bytes = new Uint8Array(length); - this.start = 0; - this.pos = 0; - this.end = length; this.chunkSize = chunkSize; this._loadedChunks = new Set(); this.numChunks = Math.ceil(length / chunkSize); @@ -149,14 +150,6 @@ class ChunkedStream extends BaseStream { return this._loadedChunks.has(chunk); } - get length() { - return this.end - this.start; - } - - get isEmpty() { - return this.length === 0; - } - getByte() { const pos = this.pos; if (pos >= this.end) { @@ -209,14 +202,6 @@ class ChunkedStream extends BaseStream { return this.bytes.subarray(begin, end); } - reset() { - this.pos = this.start; - } - - moveStart() { - this.start = this.pos; - } - makeSubStream(start, length, dict = null) { if (length) { if (start + length > this.progressiveDataLength) {