Merge pull request #11482 from Snuffleupagus/more-core-utils

Convert `src/core/jpg.js` to use the `readUint16` helper function in `src/core/core_utils.js`, rather than re-implementing it twice
This commit is contained in:
Tim van der Meij 2020-01-25 21:38:34 +01:00 committed by GitHub
commit 3775b711ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 118 additions and 128 deletions

View File

@ -132,6 +132,39 @@ function toRomanNumerals(number, lowerCase = false) {
return lowerCase ? romanStr.toLowerCase() : romanStr; return lowerCase ? romanStr.toLowerCase() : romanStr;
} }
// Calculate the base 2 logarithm of the number `x`. This differs from the
// native function in the sense that it returns the ceiling value and that it
// returns 0 instead of `Infinity`/`NaN` for `x` values smaller than/equal to 0.
function log2(x) {
if (x <= 0) {
return 0;
}
return Math.ceil(Math.log2(x));
}
function readInt8(data, offset) {
return (data[offset] << 24) >> 24;
}
function readUint16(data, offset) {
return (data[offset] << 8) | data[offset + 1];
}
function readUint32(data, offset) {
return (
((data[offset] << 24) |
(data[offset + 1] << 16) |
(data[offset + 2] << 8) |
data[offset + 3]) >>>
0
);
}
// Checks if ch is one of the following characters: SPACE, TAB, CR or LF.
function isSpace(ch) {
return ch === 0x20 || ch === 0x09 || ch === 0x0d || ch === 0x0a;
}
export { export {
getLookupTableFactory, getLookupTableFactory,
MissingDataException, MissingDataException,
@ -139,4 +172,9 @@ export {
XRefParseException, XRefParseException,
getInheritableProperty, getInheritableProperty,
toRomanNumerals, toRomanNumerals,
log2,
readInt8,
readUint16,
readUint32,
isSpace,
}; };

View File

@ -23,7 +23,6 @@ import {
isArrayEqual, isArrayEqual,
isBool, isBool,
isNum, isNum,
isSpace,
isString, isString,
OPS, OPS,
shadow, shadow,
@ -43,6 +42,7 @@ import {
} from "./primitives.js"; } from "./primitives.js";
import { import {
getInheritableProperty, getInheritableProperty,
isSpace,
MissingDataException, MissingDataException,
XRefEntryException, XRefEntryException,
XRefParseException, XRefParseException,

View File

@ -21,8 +21,6 @@ import {
FormatError, FormatError,
info, info,
isNum, isNum,
isSpace,
readUint32,
shadow, shadow,
string32, string32,
unreachable, unreachable,
@ -60,9 +58,9 @@ import {
getUnicodeRangeFor, getUnicodeRangeFor,
mapSpecialUnicodeValues, mapSpecialUnicodeValues,
} from "./unicode.js"; } from "./unicode.js";
import { isSpace, MissingDataException, readUint32 } from "./core_utils.js";
import { FontRendererFactory } from "./font_renderer.js"; import { FontRendererFactory } from "./font_renderer.js";
import { IdentityCMap } from "./cmap.js"; import { IdentityCMap } from "./cmap.js";
import { MissingDataException } from "./core_utils.js";
import { Stream } from "./stream.js"; import { Stream } from "./stream.js";
import { Type1Parser } from "./type1_parser.js"; import { Type1Parser } from "./type1_parser.js";

View File

@ -13,14 +13,8 @@
* limitations under the License. * limitations under the License.
*/ */
import { import { BaseException, shadow } from "../shared/util.js";
BaseException, import { log2, readInt8, readUint16, readUint32 } from "./core_utils.js";
log2,
readInt8,
readUint16,
readUint32,
shadow,
} from "../shared/util.js";
import { ArithmeticDecoder } from "./arithmetic_decoder.js"; import { ArithmeticDecoder } from "./arithmetic_decoder.js";
import { CCITTFaxDecoder } from "./ccitt.js"; import { CCITTFaxDecoder } from "./ccitt.js";

View File

@ -14,6 +14,7 @@
*/ */
import { assert, BaseException, warn } from "../shared/util.js"; import { assert, BaseException, warn } from "../shared/util.js";
import { readUint16 } from "./core_utils.js";
class JpegError extends BaseException { class JpegError extends BaseException {
constructor(msg) { constructor(msg) {
@ -148,8 +149,10 @@ var JpegImage = (function JpegImageClosure() {
var nextByte = data[offset++]; var nextByte = data[offset++];
if (nextByte) { if (nextByte) {
if (nextByte === 0xdc && parseDNLMarker) { if (nextByte === 0xdc && parseDNLMarker) {
offset += 2; // Skip data length. offset += 2; // Skip marker length.
const scanLines = (data[offset++] << 8) | data[offset++];
const scanLines = readUint16(data, offset);
offset += 2;
if (scanLines > 0 && scanLines !== frame.scanLines) { if (scanLines > 0 && scanLines !== frame.scanLines) {
throw new DNLMarkerError( throw new DNLMarkerError(
"Found DNL marker (0xFFDC) while parsing scan data", "Found DNL marker (0xFFDC) while parsing scan data",
@ -706,17 +709,13 @@ var JpegImage = (function JpegImageClosure() {
} }
function findNextFileMarker(data, currentPos, startPos = currentPos) { function findNextFileMarker(data, currentPos, startPos = currentPos) {
function peekUint16(pos) {
return (data[pos] << 8) | data[pos + 1];
}
const maxPos = data.length - 1; const maxPos = data.length - 1;
var newPos = startPos < currentPos ? startPos : currentPos; var newPos = startPos < currentPos ? startPos : currentPos;
if (currentPos >= maxPos) { if (currentPos >= maxPos) {
return null; // Don't attempt to read non-existent data and just return. return null; // Don't attempt to read non-existent data and just return.
} }
var currentMarker = peekUint16(currentPos); var currentMarker = readUint16(data, currentPos);
if (currentMarker >= 0xffc0 && currentMarker <= 0xfffe) { if (currentMarker >= 0xffc0 && currentMarker <= 0xfffe) {
return { return {
invalid: null, invalid: null,
@ -724,12 +723,12 @@ var JpegImage = (function JpegImageClosure() {
offset: currentPos, offset: currentPos,
}; };
} }
var newMarker = peekUint16(newPos); var newMarker = readUint16(data, newPos);
while (!(newMarker >= 0xffc0 && newMarker <= 0xfffe)) { while (!(newMarker >= 0xffc0 && newMarker <= 0xfffe)) {
if (++newPos >= maxPos) { if (++newPos >= maxPos) {
return null; // Don't attempt to read non-existent data and just return. return null; // Don't attempt to read non-existent data and just return.
} }
newMarker = peekUint16(newPos); newMarker = readUint16(data, newPos);
} }
return { return {
invalid: currentMarker.toString(16), invalid: currentMarker.toString(16),
@ -740,15 +739,10 @@ var JpegImage = (function JpegImageClosure() {
JpegImage.prototype = { JpegImage.prototype = {
parse(data, { dnlScanLines = null } = {}) { parse(data, { dnlScanLines = null } = {}) {
function readUint16() {
var value = (data[offset] << 8) | data[offset + 1];
offset += 2;
return value;
}
function readDataBlock() { function readDataBlock() {
var length = readUint16(); const length = readUint16(data, offset);
var endOffset = offset + length - 2; offset += 2;
let endOffset = offset + length - 2;
var fileMarker = findNextFileMarker(data, endOffset, offset); var fileMarker = findNextFileMarker(data, endOffset, offset);
if (fileMarker && fileMarker.invalid) { if (fileMarker && fileMarker.invalid) {
@ -796,12 +790,15 @@ var JpegImage = (function JpegImageClosure() {
var quantizationTables = []; var quantizationTables = [];
var huffmanTablesAC = [], var huffmanTablesAC = [],
huffmanTablesDC = []; huffmanTablesDC = [];
var fileMarker = readUint16();
let fileMarker = readUint16(data, offset);
offset += 2;
if (fileMarker !== /* SOI (Start of Image) = */ 0xffd8) { if (fileMarker !== /* SOI (Start of Image) = */ 0xffd8) {
throw new JpegError("SOI not found"); throw new JpegError("SOI not found");
} }
fileMarker = readUint16(data, offset);
offset += 2;
fileMarker = readUint16();
markerLoop: while (fileMarker !== /* EOI (End of Image) = */ 0xffd9) { markerLoop: while (fileMarker !== /* EOI (End of Image) = */ 0xffd9) {
var i, j, l; var i, j, l;
switch (fileMarker) { switch (fileMarker) {
@ -868,7 +865,8 @@ var JpegImage = (function JpegImageClosure() {
break; break;
case 0xffdb: // DQT (Define Quantization Tables) case 0xffdb: // DQT (Define Quantization Tables)
var quantizationTablesLength = readUint16(); const quantizationTablesLength = readUint16(data, offset);
offset += 2;
var quantizationTablesEnd = quantizationTablesLength + offset - 2; var quantizationTablesEnd = quantizationTablesLength + offset - 2;
var z; var z;
while (offset < quantizationTablesEnd) { while (offset < quantizationTablesEnd) {
@ -884,7 +882,8 @@ var JpegImage = (function JpegImageClosure() {
// 16 bit values // 16 bit values
for (j = 0; j < 64; j++) { for (j = 0; j < 64; j++) {
z = dctZigZag[j]; z = dctZigZag[j];
tableData[z] = readUint16(); tableData[z] = readUint16(data, offset);
offset += 2;
} }
} else { } else {
throw new JpegError("DQT - invalid table spec"); throw new JpegError("DQT - invalid table spec");
@ -899,14 +898,17 @@ var JpegImage = (function JpegImageClosure() {
if (frame) { if (frame) {
throw new JpegError("Only single frame JPEGs supported"); throw new JpegError("Only single frame JPEGs supported");
} }
readUint16(); // skip data length offset += 2; // Skip marker length.
frame = {}; frame = {};
frame.extended = fileMarker === 0xffc1; frame.extended = fileMarker === 0xffc1;
frame.progressive = fileMarker === 0xffc2; frame.progressive = fileMarker === 0xffc2;
frame.precision = data[offset++]; frame.precision = data[offset++];
const sofScanLines = readUint16(); const sofScanLines = readUint16(data, offset);
offset += 2;
frame.scanLines = dnlScanLines || sofScanLines; frame.scanLines = dnlScanLines || sofScanLines;
frame.samplesPerLine = readUint16(); frame.samplesPerLine = readUint16(data, offset);
offset += 2;
frame.components = []; frame.components = [];
frame.componentIds = {}; frame.componentIds = {};
var componentsCount = data[offset++], var componentsCount = data[offset++],
@ -939,7 +941,8 @@ var JpegImage = (function JpegImageClosure() {
break; break;
case 0xffc4: // DHT (Define Huffman Tables) case 0xffc4: // DHT (Define Huffman Tables)
var huffmanLength = readUint16(); const huffmanLength = readUint16(data, offset);
offset += 2;
for (i = 2; i < huffmanLength; ) { for (i = 2; i < huffmanLength; ) {
var huffmanTableSpec = data[offset++]; var huffmanTableSpec = data[offset++];
var codeLengths = new Uint8Array(16); var codeLengths = new Uint8Array(16);
@ -960,8 +963,10 @@ var JpegImage = (function JpegImageClosure() {
break; break;
case 0xffdd: // DRI (Define Restart Interval) case 0xffdd: // DRI (Define Restart Interval)
readUint16(); // skip data length offset += 2; // Skip marker length.
resetInterval = readUint16();
resetInterval = readUint16(data, offset);
offset += 2;
break; break;
case 0xffda: // SOS (Start of Scan) case 0xffda: // SOS (Start of Scan)
@ -971,7 +976,8 @@ var JpegImage = (function JpegImageClosure() {
// parse DNL markers during re-parsing of the JPEG scan data. // parse DNL markers during re-parsing of the JPEG scan data.
const parseDNLMarker = ++numSOSMarkers === 1 && !dnlScanLines; const parseDNLMarker = ++numSOSMarkers === 1 && !dnlScanLines;
readUint16(); // scanLength offset += 2; // Skip marker length.
var selectorsCount = data[offset++]; var selectorsCount = data[offset++];
var components = [], var components = [],
component; component;
@ -1055,7 +1061,8 @@ var JpegImage = (function JpegImageClosure() {
"JpegImage.parse - unknown marker: " + fileMarker.toString(16) "JpegImage.parse - unknown marker: " + fileMarker.toString(16)
); );
} }
fileMarker = readUint16(); fileMarker = readUint16(data, offset);
offset += 2;
} }
this.width = frame.samplesPerLine; this.width = frame.samplesPerLine;

View File

@ -13,14 +13,8 @@
* limitations under the License. * limitations under the License.
*/ */
import { import { BaseException, info, warn } from "../shared/util.js";
BaseException, import { log2, readUint16, readUint32 } from "./core_utils.js";
info,
log2,
readUint16,
readUint32,
warn,
} from "../shared/util.js";
import { ArithmeticDecoder } from "./arithmetic_decoder.js"; import { ArithmeticDecoder } from "./arithmetic_decoder.js";
class JpxError extends BaseException { class JpxError extends BaseException {

View File

@ -29,7 +29,6 @@ import {
FormatError, FormatError,
info, info,
isNum, isNum,
isSpace,
StreamType, StreamType,
warn, warn,
} from "../shared/util.js"; } from "../shared/util.js";
@ -44,11 +43,11 @@ import {
Name, Name,
Ref, Ref,
} from "./primitives.js"; } from "./primitives.js";
import { isSpace, MissingDataException } from "./core_utils.js";
import { CCITTFaxStream } from "./ccitt_stream.js"; import { CCITTFaxStream } from "./ccitt_stream.js";
import { Jbig2Stream } from "./jbig2_stream.js"; import { Jbig2Stream } from "./jbig2_stream.js";
import { JpegStream } from "./jpeg_stream.js"; import { JpegStream } from "./jpeg_stream.js";
import { JpxStream } from "./jpx_stream.js"; import { JpxStream } from "./jpx_stream.js";
import { MissingDataException } from "./core_utils.js";
const MAX_LENGTH_TO_CACHE = 1000; const MAX_LENGTH_TO_CACHE = 1000;
const MAX_ADLER32_LENGTH = 5552; const MAX_ADLER32_LENGTH = 5552;

View File

@ -14,8 +14,9 @@
*/ */
/* eslint no-var: error */ /* eslint no-var: error */
import { FormatError, isSpace, shadow } from "../shared/util.js"; import { FormatError, shadow } from "../shared/util.js";
import { EOF } from "./primitives.js"; import { EOF } from "./primitives.js";
import { isSpace } from "./core_utils.js";
class PostScriptParser { class PostScriptParser {
constructor(lexer) { constructor(lexer) {

View File

@ -19,13 +19,9 @@
* license. * license.
*/ */
import { import { FormatError, stringToBytes, unreachable } from "../shared/util.js";
FormatError,
isSpace,
stringToBytes,
unreachable,
} from "../shared/util.js";
import { isDict } from "./primitives.js"; import { isDict } from "./primitives.js";
import { isSpace } from "./core_utils.js";
var Stream = (function StreamClosure() { var Stream = (function StreamClosure() {
function Stream(arrayBuffer, start, length, dict) { function Stream(arrayBuffer, start, length, dict) {

View File

@ -13,9 +13,10 @@
* limitations under the License. * limitations under the License.
*/ */
import { isSpace, warn } from "../shared/util.js";
import { getEncoding } from "./encodings.js"; import { getEncoding } from "./encodings.js";
import { isSpace } from "./core_utils.js";
import { Stream } from "./stream.js"; import { Stream } from "./stream.js";
import { warn } from "../shared/util.js";
// Hinting is currently disabled due to unknown problems on windows // Hinting is currently disabled due to unknown problems on windows
// in tracemonkey and various other pdfs with type1 fonts. // in tracemonkey and various other pdfs with type1 fonts.

View File

@ -547,34 +547,6 @@ function string32(value) {
); );
} }
// Calculate the base 2 logarithm of the number `x`. This differs from the
// native function in the sense that it returns the ceiling value and that it
// returns 0 instead of `Infinity`/`NaN` for `x` values smaller than/equal to 0.
function log2(x) {
if (x <= 0) {
return 0;
}
return Math.ceil(Math.log2(x));
}
function readInt8(data, start) {
return (data[start] << 24) >> 24;
}
function readUint16(data, offset) {
return (data[offset] << 8) | data[offset + 1];
}
function readUint32(data, offset) {
return (
((data[offset] << 24) |
(data[offset + 1] << 16) |
(data[offset + 2] << 8) |
data[offset + 3]) >>>
0
);
}
// Lazy test the endianness of the platform // Lazy test the endianness of the platform
// NOTE: This will be 'true' for simulated TypedArrays // NOTE: This will be 'true' for simulated TypedArrays
function isLittleEndian() { function isLittleEndian() {
@ -835,11 +807,6 @@ function isArrayEqual(arr1, arr2) {
}); });
} }
// Checks if ch is one of the following characters: SPACE, TAB, CR or LF.
function isSpace(ch) {
return ch === 0x20 || ch === 0x09 || ch === 0x0d || ch === 0x0a;
}
/** /**
* Promise Capability object. * Promise Capability object.
* *
@ -949,15 +916,10 @@ export {
isEmptyObj, isEmptyObj,
isNum, isNum,
isString, isString,
isSpace,
isSameOrigin, isSameOrigin,
createValidAbsoluteUrl, createValidAbsoluteUrl,
isLittleEndian, isLittleEndian,
isEvalSupported, isEvalSupported,
log2,
readInt8,
readUint16,
readUint32,
removeNullCharacters, removeNullCharacters,
setVerbosityLevel, setVerbosityLevel,
shadow, shadow,

View File

@ -16,6 +16,8 @@
import { Dict, Ref } from "../../src/core/primitives.js"; import { Dict, Ref } from "../../src/core/primitives.js";
import { import {
getInheritableProperty, getInheritableProperty,
isSpace,
log2,
toRomanNumerals, toRomanNumerals,
} from "../../src/core/core_utils.js"; } from "../../src/core/core_utils.js";
import { XRefMock } from "./test_utils.js"; import { XRefMock } from "./test_utils.js";
@ -180,4 +182,33 @@ describe("core_utils", function() {
expect(toRomanNumerals(2019, /* lowercase = */ true)).toEqual("mmxix"); expect(toRomanNumerals(2019, /* lowercase = */ true)).toEqual("mmxix");
}); });
}); });
describe("log2", function() {
it("handles values smaller than/equal to zero", function() {
expect(log2(0)).toEqual(0);
expect(log2(-1)).toEqual(0);
});
it("handles values larger than zero", function() {
expect(log2(1)).toEqual(0);
expect(log2(2)).toEqual(1);
expect(log2(3)).toEqual(2);
expect(log2(3.14)).toEqual(2);
});
});
describe("isSpace", function() {
it("handles space characters", function() {
expect(isSpace(0x20)).toEqual(true);
expect(isSpace(0x09)).toEqual(true);
expect(isSpace(0x0d)).toEqual(true);
expect(isSpace(0x0a)).toEqual(true);
});
it("handles non-space characters", function() {
expect(isSpace(0x0b)).toEqual(false);
expect(isSpace(null)).toEqual(false);
expect(isSpace(undefined)).toEqual(false);
});
});
}); });

View File

@ -22,9 +22,7 @@ import {
isEmptyObj, isEmptyObj,
isNum, isNum,
isSameOrigin, isSameOrigin,
isSpace,
isString, isString,
log2,
removeNullCharacters, removeNullCharacters,
string32, string32,
stringToBytes, stringToBytes,
@ -118,21 +116,6 @@ describe("util", function() {
}); });
}); });
describe("isSpace", function() {
it("handles space characters", function() {
expect(isSpace(0x20)).toEqual(true);
expect(isSpace(0x09)).toEqual(true);
expect(isSpace(0x0d)).toEqual(true);
expect(isSpace(0x0a)).toEqual(true);
});
it("handles non-space characters", function() {
expect(isSpace(0x0b)).toEqual(false);
expect(isSpace(null)).toEqual(false);
expect(isSpace(undefined)).toEqual(false);
});
});
describe("isString", function() { describe("isString", function() {
it("handles string values", function() { it("handles string values", function() {
expect(isString("foo")).toEqual(true); expect(isString("foo")).toEqual(true);
@ -147,20 +130,6 @@ describe("util", function() {
}); });
}); });
describe("log2", function() {
it("handles values smaller than/equal to zero", function() {
expect(log2(0)).toEqual(0);
expect(log2(-1)).toEqual(0);
});
it("handles values larger than zero", function() {
expect(log2(1)).toEqual(0);
expect(log2(2)).toEqual(1);
expect(log2(3)).toEqual(2);
expect(log2(3.14)).toEqual(2);
});
});
describe("string32", function() { describe("string32", function() {
it("converts unsigned 32-bit integers to strings", function() { it("converts unsigned 32-bit integers to strings", function() {
expect(string32(0x74727565)).toEqual("true"); expect(string32(0x74727565)).toEqual("true");