1
0
Fork 0
mirror of https://github.com/mozilla/pdf.js.git synced 2025-04-19 14:48:08 +02:00

Merge pull request #18026 from Snuffleupagus/validate-more-getArray

Validate even more dictionary properties
This commit is contained in:
Jonas Jenwald 2024-05-06 22:09:42 +02:00 committed by GitHub
commit b6765403a1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 140 additions and 85 deletions

View file

@ -43,6 +43,10 @@ import {
getInheritableProperty,
getRotationMatrix,
isAscii,
isNumberArray,
lookupMatrix,
lookupNormalRect,
lookupRect,
numberToString,
stringToUTF16String,
} from "./core_utils.js";
@ -550,7 +554,7 @@ function getQuadPoints(dict, rect) {
// Each quadrilateral must consist of eight coordinates.
const quadPoints = dict.getArray("QuadPoints");
if (
!Array.isArray(quadPoints) ||
!isNumberArray(quadPoints, null) ||
quadPoints.length === 0 ||
quadPoints.length % 8 > 0
) {
@ -914,10 +918,7 @@ class Annotation {
* @param {Array} rectangle - The rectangle array with exactly four entries
*/
setRectangle(rectangle) {
this.rectangle =
Array.isArray(rectangle) && rectangle.length === 4
? Util.normalizeRect(rectangle)
: [0, 0, 0, 0];
this.rectangle = lookupNormalRect(rectangle, [0, 0, 0, 0]);
}
/**
@ -1150,8 +1151,11 @@ class Annotation {
["ExtGState", "ColorSpace", "Pattern", "Shading", "XObject", "Font"],
appearance
);
const bbox = appearanceDict.getArray("BBox") || [0, 0, 1, 1];
const matrix = appearanceDict.getArray("Matrix") || [1, 0, 0, 1, 0, 0];
const bbox = lookupRect(appearanceDict.getArray("BBox"), [0, 0, 1, 1]);
const matrix = lookupMatrix(
appearanceDict.getArray("Matrix"),
IDENTITY_MATRIX
);
const transform = getTransformMatrix(rect, bbox, matrix);
const opList = new OperatorList();
@ -1248,10 +1252,13 @@ class Annotation {
if (text.length > 1 || text[0]) {
const appearanceDict = this.appearance.dict;
const bbox = lookupRect(appearanceDict.getArray("BBox"), null);
const matrix = lookupMatrix(appearanceDict.getArray("Matrix"), null);
this.data.textPosition = this._transformPoint(
firstPosition,
appearanceDict.getArray("BBox"),
appearanceDict.getArray("Matrix")
bbox,
matrix
);
this.data.textContent = text;
}
@ -1401,7 +1408,7 @@ class AnnotationBorderStyle {
setWidth(width, rect = [0, 0, 0, 0]) {
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
assert(
Array.isArray(rect) && rect.length === 4,
isNumberArray(rect, 4),
"A valid `rect` parameter must be provided."
);
}
@ -2972,7 +2979,10 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
: this.uncheckedAppearance;
if (appearance) {
const savedAppearance = this.appearance;
const savedMatrix = appearance.dict.getArray("Matrix") || IDENTITY_MATRIX;
const savedMatrix = lookupMatrix(
appearance.dict.getArray("Matrix"),
IDENTITY_MATRIX
);
if (rotation) {
appearance.dict.set(
@ -3737,12 +3747,7 @@ class PopupAnnotation extends Annotation {
warn("Popup annotation has a missing or invalid parent annotation.");
return;
}
const parentRect = parentItem.getArray("Rect");
this.data.parentRect =
Array.isArray(parentRect) && parentRect.length === 4
? Util.normalizeRect(parentRect)
: null;
this.data.parentRect = lookupNormalRect(parentItem.getArray("Rect"), null);
const rt = parentItem.get("RT");
if (isName(rt, AnnotationReplyType.GROUP)) {
@ -4030,7 +4035,7 @@ class LineAnnotation extends MarkupAnnotation {
this.data.hasOwnCanvas = this.data.noRotate;
this.data.noHTML = false;
const lineCoordinates = dict.getArray("L");
const lineCoordinates = lookupRect(dict.getArray("L"), [0, 0, 0, 0]);
this.data.lineCoordinates = Util.normalizeRect(lineCoordinates);
if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("MOZCENTRAL")) {
@ -4225,7 +4230,7 @@ class PolylineAnnotation extends MarkupAnnotation {
// horizontal and vertical coordinates, respectively, of each vertex.
// Convert this to an array of objects with x and y coordinates.
const rawVertices = dict.getArray("Vertices");
if (!Array.isArray(rawVertices)) {
if (!isNumberArray(rawVertices, null)) {
return;
}
for (let i = 0, ii = rawVertices.length; i < ii; i += 2) {
@ -4314,11 +4319,15 @@ class InkAnnotation extends MarkupAnnotation {
// of each vertex. Convert this to an array of objects with x and y
// coordinates.
this.data.inkLists.push([]);
if (!Array.isArray(rawInkLists[i])) {
continue;
}
for (let j = 0, jj = rawInkLists[i].length; j < jj; j += 2) {
this.data.inkLists[i].push({
x: xref.fetchIfRef(rawInkLists[i][j]),
y: xref.fetchIfRef(rawInkLists[i][j + 1]),
});
const x = xref.fetchIfRef(rawInkLists[i][j]),
y = xref.fetchIfRef(rawInkLists[i][j + 1]);
if (typeof x === "number" && typeof y === "number") {
this.data.inkLists[i].push({ x, y });
}
}
}

View file

@ -15,6 +15,7 @@
import {
collectActions,
isNumberArray,
MissingDataException,
PDF_VERSION_REGEXP,
recoverJsURL,
@ -388,8 +389,7 @@ class Catalog {
// We only need to parse the color when it's valid, and non-default.
if (
Array.isArray(color) &&
color.length === 3 &&
isNumberArray(color, 3) &&
(color[0] !== 0 || color[1] !== 0 || color[2] !== 0)
) {
rgbColor = ColorSpace.singletons.rgb.getRgb(color, 0);

View file

@ -19,6 +19,7 @@ import {
BaseException,
objectSize,
stringToPDFString,
Util,
warn,
} from "../shared/util.js";
import { Dict, isName, Ref, RefSet } from "./primitives.js";
@ -218,6 +219,21 @@ function isWhiteSpace(ch) {
return ch === 0x20 || ch === 0x09 || ch === 0x0d || ch === 0x0a;
}
/**
* Checks if something is an Array containing only boolean values,
* and (optionally) checks its length.
* @param {any} arr
* @param {number | null} len
* @returns {boolean}
*/
function isBooleanArray(arr, len) {
return (
Array.isArray(arr) &&
(len === null || arr.length === len) &&
arr.every(x => typeof x === "boolean")
);
}
/**
* Checks if something is an Array containing only numbers,
* and (optionally) checks its length.
@ -233,6 +249,21 @@ function isNumberArray(arr, len) {
);
}
// Returns the matrix, or the fallback value if it's invalid.
function lookupMatrix(arr, fallback) {
return isNumberArray(arr, 6) ? arr : fallback;
}
// Returns the rectangle, or the fallback value if it's invalid.
function lookupRect(arr, fallback) {
return isNumberArray(arr, 4) ? arr : fallback;
}
// Returns the normalized rectangle, or the fallback value if it's invalid.
function lookupNormalRect(arr, fallback) {
return isNumberArray(arr, 4) ? Util.normalizeRect(arr) : fallback;
}
/**
* AcroForm field names use an array like notation to refer to
* repeated XFA elements e.g. foo.bar[nnn].
@ -652,9 +683,13 @@ export {
getRotationMatrix,
getSizeInBytes,
isAscii,
isBooleanArray,
isNumberArray,
isWhiteSpace,
log2,
lookupMatrix,
lookupNormalRect,
lookupRect,
MissingDataException,
numberToString,
ParserEOFException,

View file

@ -40,6 +40,7 @@ import {
getInheritableProperty,
getNewAnnotationsMap,
isWhiteSpace,
lookupNormalRect,
MissingDataException,
PDF_VERSION_REGEXP,
validateCSSFont,
@ -160,10 +161,12 @@ class Page {
if (this.xfaData) {
return this.xfaData.bbox;
}
let box = this._getInheritableProperty(name, /* getArray = */ true);
const box = lookupNormalRect(
this._getInheritableProperty(name, /* getArray = */ true),
null
);
if (Array.isArray(box) && box.length === 4) {
box = Util.normalizeRect(box);
if (box) {
if (box[2] - box[0] > 0 && box[3] - box[1] > 0) {
return box;
}

View file

@ -53,6 +53,7 @@ import {
import { getTilingPatternIR, Pattern } from "./pattern.js";
import { getXfaFontDict, getXfaFontName } from "./xfa_fonts.js";
import { IdentityToUnicodeMap, ToUnicodeMap } from "./to_unicode_map.js";
import { isNumberArray, lookupMatrix, lookupNormalRect } from "./core_utils.js";
import { isPDFFunction, PDFFunctionFactory } from "./function.js";
import { Lexer, Parser } from "./parser.js";
import {
@ -73,7 +74,6 @@ import { getGlyphsUnicode } from "./glyphlist.js";
import { getMetrics } from "./metrics.js";
import { getUnicodeForGlyph } from "./unicode.js";
import { ImageResizer } from "./image_resizer.js";
import { isNumberArray } from "./core_utils.js";
import { MurmurHash3_64 } from "../shared/murmurhash3.js";
import { OperatorList } from "./operator_list.js";
import { PDFImage } from "./image.js";
@ -460,12 +460,8 @@ class PartialEvaluator {
localColorSpaceCache
) {
const dict = xobj.dict;
const matrix = dict.getArray("Matrix");
let bbox = dict.getArray("BBox");
bbox =
Array.isArray(bbox) && bbox.length === 4
? Util.normalizeRect(bbox)
: null;
const matrix = lookupMatrix(dict.getArray("Matrix"), null);
const bbox = lookupNormalRect(dict.getArray("BBox"), null);
let optionalContent, groupOptions;
if (dict.has("OC")) {
@ -1578,7 +1574,7 @@ class PartialEvaluator {
localShadingPatternCache,
});
if (objId) {
const matrix = dict.getArray("Matrix");
const matrix = lookupMatrix(dict.getArray("Matrix"), null);
operatorList.addOp(fn, ["Shading", objId, matrix]);
}
return undefined;
@ -3265,8 +3261,8 @@ class PartialEvaluator {
const currentState = stateManager.state.clone();
const xObjStateManager = new StateManager(currentState);
const matrix = xobj.dict.getArray("Matrix");
if (Array.isArray(matrix) && matrix.length === 6) {
const matrix = lookupMatrix(xobj.dict.getArray("Matrix"), null);
if (matrix) {
xObjStateManager.transform(matrix);
}
@ -4244,10 +4240,7 @@ class PartialEvaluator {
if (!descriptor) {
if (isType3Font) {
let bbox = dict.getArray("FontBBox");
if (!isNumberArray(bbox, 4)) {
bbox = [0, 0, 0, 0];
}
const bbox = lookupNormalRect(dict.getArray("FontBBox"), [0, 0, 0, 0]);
// FontDescriptor is only required for Type3 fonts when the document
// is a tagged pdf. Create a barbebones one to get by.
descriptor = new Dict(null);
@ -4437,14 +4430,14 @@ class PartialEvaluator {
}
}
let fontMatrix = dict.getArray("FontMatrix");
if (!isNumberArray(fontMatrix, 6)) {
fontMatrix = FONT_IDENTITY_MATRIX;
}
let bbox = descriptor.getArray("FontBBox") || dict.getArray("FontBBox");
if (!isNumberArray(bbox, 4)) {
bbox = undefined;
}
const fontMatrix = lookupMatrix(
dict.getArray("FontMatrix"),
FONT_IDENTITY_MATRIX
);
const bbox = lookupNormalRect(
descriptor.getArray("FontBBox") || dict.getArray("FontBBox"),
undefined
);
let ascent = descriptor.get("Ascent");
if (typeof ascent !== "number") {
ascent = undefined;

View file

@ -16,14 +16,21 @@
import {
assert,
FormatError,
IDENTITY_MATRIX,
info,
unreachable,
Util,
warn,
} from "../shared/util.js";
import {
isBooleanArray,
isNumberArray,
lookupMatrix,
lookupNormalRect,
MissingDataException,
} from "./core_utils.js";
import { BaseStream } from "./base_stream.js";
import { ColorSpace } from "./colorspace.js";
import { MissingDataException } from "./core_utils.js";
const ShadingType = {
FUNCTION_BASED: 1,
@ -106,8 +113,17 @@ class BaseShading {
class RadialAxialShading extends BaseShading {
constructor(dict, xref, resources, pdfFunctionFactory, localColorSpaceCache) {
super();
this.coordsArr = dict.getArray("Coords");
this.shadingType = dict.get("ShadingType");
let coordsLen = 0;
if (this.shadingType === ShadingType.AXIAL) {
coordsLen = 4;
} else if (this.shadingType === ShadingType.RADIAL) {
coordsLen = 6;
}
this.coordsArr = dict.getArray("Coords");
if (!isNumberArray(this.coordsArr, coordsLen)) {
throw new FormatError("RadialAxialShading: Invalid /Coords array.");
}
const cs = ColorSpace.parse({
cs: dict.getRaw("CS") || dict.getRaw("ColorSpace"),
xref,
@ -115,26 +131,20 @@ class RadialAxialShading extends BaseShading {
pdfFunctionFactory,
localColorSpaceCache,
});
const bbox = dict.getArray("BBox");
this.bbox =
Array.isArray(bbox) && bbox.length === 4
? Util.normalizeRect(bbox)
: null;
this.bbox = lookupNormalRect(dict.getArray("BBox"), null);
let t0 = 0.0,
t1 = 1.0;
if (dict.has("Domain")) {
const domainArr = dict.getArray("Domain");
t0 = domainArr[0];
t1 = domainArr[1];
const domainArr = dict.getArray("Domain");
if (isNumberArray(domainArr, 2)) {
[t0, t1] = domainArr;
}
let extendStart = false,
extendEnd = false;
if (dict.has("Extend")) {
const extendArr = dict.getArray("Extend");
extendStart = extendArr[0];
extendEnd = extendArr[1];
const extendArr = dict.getArray("Extend");
if (isBooleanArray(extendArr, 2)) {
[extendStart, extendEnd] = extendArr;
}
if (
@ -271,8 +281,7 @@ class RadialAxialShading extends BaseShading {
}
getIR() {
const coordsArr = this.coordsArr;
const shadingType = this.shadingType;
const { coordsArr, shadingType } = this;
let type, p0, p1, r0, r1;
if (shadingType === ShadingType.AXIAL) {
p0 = [coordsArr[0], coordsArr[1]];
@ -453,11 +462,7 @@ class MeshShading extends BaseShading {
}
const dict = stream.dict;
this.shadingType = dict.get("ShadingType");
const bbox = dict.getArray("BBox");
this.bbox =
Array.isArray(bbox) && bbox.length === 4
? Util.normalizeRect(bbox)
: null;
this.bbox = lookupNormalRect(dict.getArray("BBox"), null);
const cs = ColorSpace.parse({
cs: dict.getRaw("CS") || dict.getRaw("ColorSpace"),
xref,
@ -983,17 +988,28 @@ class DummyShading extends BaseShading {
}
function getTilingPatternIR(operatorList, dict, color) {
const matrix = dict.getArray("Matrix");
const bbox = Util.normalizeRect(dict.getArray("BBox"));
const xstep = dict.get("XStep");
const ystep = dict.get("YStep");
const paintType = dict.get("PaintType");
const tilingType = dict.get("TilingType");
const matrix = lookupMatrix(dict.getArray("Matrix"), IDENTITY_MATRIX);
const bbox = lookupNormalRect(dict.getArray("BBox"), null);
// Ensure that the pattern has a non-zero width and height, to prevent errors
// in `pattern_helper.js` (fixes issue8330.pdf).
if (bbox[2] - bbox[0] === 0 || bbox[3] - bbox[1] === 0) {
throw new FormatError(`Invalid getTilingPatternIR /BBox array: [${bbox}].`);
if (!bbox || bbox[2] - bbox[0] === 0 || bbox[3] - bbox[1] === 0) {
throw new FormatError(`Invalid getTilingPatternIR /BBox array.`);
}
const xstep = dict.get("XStep");
if (typeof xstep !== "number") {
throw new FormatError(`Invalid getTilingPatternIR /XStep value.`);
}
const ystep = dict.get("YStep");
if (typeof ystep !== "number") {
throw new FormatError(`Invalid getTilingPatternIR /YStep value.`);
}
const paintType = dict.get("PaintType");
if (!Number.isInteger(paintType)) {
throw new FormatError(`Invalid getTilingPatternIR /PaintType value.`);
}
const tilingType = dict.get("TilingType");
if (!Number.isInteger(tilingType)) {
throw new FormatError(`Invalid getTilingPatternIR /TilingType value.`);
}
return [

View file

@ -2465,10 +2465,9 @@ class CanvasGraphics {
this.save();
this.baseTransformStack.push(this.baseTransform);
if (Array.isArray(matrix) && matrix.length === 6) {
if (matrix) {
this.transform(...matrix);
}
this.baseTransform = getCurrentTransform(this.ctx);
if (bbox) {
@ -2652,7 +2651,7 @@ class CanvasGraphics {
this.ctx.setTransform(...this.baseTransform);
}
if (Array.isArray(rect) && rect.length === 4) {
if (rect) {
const width = rect[2] - rect[0];
const height = rect[3] - rect[1];

View file

@ -455,7 +455,7 @@ class TilingPattern {
constructor(IR, color, ctx, canvasGraphicsFactory, baseTransform) {
this.operatorList = IR[2];
this.matrix = IR[3] || [1, 0, 0, 1, 0, 0];
this.matrix = IR[3];
this.bbox = IR[4];
this.xstep = IR[5];
this.ystep = IR[6];