Skip to content

Commit

Permalink
Merge pull request #18014 from Snuffleupagus/validate-font-properties
Browse files Browse the repository at this point in the history
Validate additional font-dictionary properties
  • Loading branch information
Snuffleupagus authored Apr 29, 2024
2 parents 85e64b5 + 08eb056 commit 234067e
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 26 deletions.
16 changes: 16 additions & 0 deletions src/core/core_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,21 @@ function isWhiteSpace(ch) {
return ch === 0x20 || ch === 0x09 || ch === 0x0d || ch === 0x0a;
}

/**
* Checks if something is an Array containing only numbers,
* and (optionally) checks its length.
* @param {any} arr
* @param {number | null} len
* @returns {boolean}
*/
function isNumberArray(arr, len) {
return (
Array.isArray(arr) &&
(len === null || arr.length === len) &&
arr.every(x => typeof x === "number")
);
}

/**
* AcroForm field names use an array like notation to refer to
* repeated XFA elements e.g. foo.bar[nnn].
Expand Down Expand Up @@ -637,6 +652,7 @@ export {
getRotationMatrix,
getSizeInBytes,
isAscii,
isNumberArray,
isWhiteSpace,
log2,
MissingDataException,
Expand Down
65 changes: 50 additions & 15 deletions src/core/evaluator.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ 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";
Expand Down Expand Up @@ -4077,8 +4078,14 @@ class PartialEvaluator {
composite = true;
}

const firstChar = dict.get("FirstChar") || 0,
lastChar = dict.get("LastChar") || (composite ? 0xffff : 0xff);
let firstChar = dict.get("FirstChar");
if (!Number.isInteger(firstChar)) {
firstChar = 0;
}
let lastChar = dict.get("LastChar");
if (!Number.isInteger(lastChar)) {
lastChar = composite ? 0xffff : 0xff;
}
const descriptor = dict.get("FontDescriptor");
const toUnicode = dict.get("ToUnicode") || baseDict.get("ToUnicode");

Expand Down Expand Up @@ -4206,11 +4213,15 @@ class PartialEvaluator {

if (!descriptor) {
if (isType3Font) {
let bbox = dict.getArray("FontBBox");
if (!isNumberArray(bbox, 4)) {
bbox = [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);
descriptor.set("FontName", Name.get(type));
descriptor.set("FontBBox", dict.getArray("FontBBox") || [0, 0, 0, 0]);
descriptor.set("FontBBox", bbox);
} else {
// Before PDF 1.5 if the font was one of the base 14 fonts, having a
// FontDescriptor was not required.
Expand Down Expand Up @@ -4392,13 +4403,37 @@ class PartialEvaluator {
}

let fontMatrix = dict.getArray("FontMatrix");
if (
!Array.isArray(fontMatrix) ||
fontMatrix.length !== 6 ||
fontMatrix.some(x => typeof x !== "number")
) {
if (!isNumberArray(fontMatrix, 6)) {
fontMatrix = FONT_IDENTITY_MATRIX;
}
let bbox = descriptor.getArray("FontBBox") || dict.getArray("FontBBox");
if (!isNumberArray(bbox, 4)) {
bbox = undefined;
}
let ascent = descriptor.get("Ascent");
if (typeof ascent !== "number") {
ascent = undefined;
}
let descent = descriptor.get("Descent");
if (typeof descent !== "number") {
descent = undefined;
}
let xHeight = descriptor.get("XHeight");
if (typeof xHeight !== "number") {
xHeight = 0;
}
let capHeight = descriptor.get("CapHeight");
if (typeof capHeight !== "number") {
capHeight = 0;
}
let flags = descriptor.get("Flags");
if (!Number.isInteger(flags)) {
flags = 0;
}
let italicAngle = descriptor.get("ItalicAngle");
if (typeof italicAngle !== "number") {
italicAngle = 0;
}

const properties = {
type,
Expand All @@ -4416,13 +4451,13 @@ class PartialEvaluator {
firstChar,
lastChar,
toUnicode,
bbox: descriptor.getArray("FontBBox") || dict.getArray("FontBBox"),
ascent: descriptor.get("Ascent"),
descent: descriptor.get("Descent"),
xHeight: descriptor.get("XHeight") || 0,
capHeight: descriptor.get("CapHeight") || 0,
flags: descriptor.get("Flags"),
italicAngle: descriptor.get("ItalicAngle") || 0,
bbox,
ascent,
descent,
xHeight,
capHeight,
flags,
italicAngle,
isType3Font,
cssFontInfo,
scaleFactors: glyphScaleFactors,
Expand Down
3 changes: 2 additions & 1 deletion src/core/font_renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
} from "../shared/util.js";
import { CFFParser } from "./cff_parser.js";
import { getGlyphsUnicode } from "./glyphlist.js";
import { isNumberArray } from "./core_utils.js";
import { StandardEncoding } from "./encodings.js";
import { Stream } from "./stream.js";

Expand Down Expand Up @@ -750,7 +751,7 @@ class Commands {

add(cmd, args) {
if (args) {
if (args.some(arg => typeof arg !== "number")) {
if (!isNumberArray(args, null)) {
warn(
`Commands.add - "${cmd}" has at least one non-number arg: "${args}".`
);
Expand Down
14 changes: 4 additions & 10 deletions src/core/function.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
} from "../shared/util.js";
import { PostScriptLexer, PostScriptParser } from "./ps_parser.js";
import { BaseStream } from "./base_stream.js";
import { isNumberArray } from "./core_utils.js";
import { LocalFunctionCache } from "./image_utils.js";

class PDFFunctionFactory {
Expand Down Expand Up @@ -117,16 +118,9 @@ function toNumberArray(arr) {
if (!Array.isArray(arr)) {
return null;
}
const length = arr.length;
for (let i = 0; i < length; i++) {
if (typeof arr[i] !== "number") {
// Non-number is found -- convert all items to numbers.
const result = new Array(length);
for (let j = 0; j < length; j++) {
result[j] = +arr[j];
}
return result;
}
if (!isNumberArray(arr, null)) {
// Non-number is found -- convert all items to numbers.
return arr.map(x => +x);
}
return arr;
}
Expand Down

0 comments on commit 234067e

Please sign in to comment.