Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve the implementation of the PDFDocument.fingerprints-getter #17862

Merged
merged 3 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 12 additions & 21 deletions src/core/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
stringToBytes,
stringToPDFString,
stringToUTF8String,
toHexUtil,
unreachable,
Util,
warn,
Expand Down Expand Up @@ -862,10 +863,6 @@ const STARTXREF_SIGNATURE = new Uint8Array([
]);
const ENDOBJ_SIGNATURE = new Uint8Array([0x65, 0x6e, 0x64, 0x6f, 0x62, 0x6a]);

const FINGERPRINT_FIRST_BYTES = 1024;
const EMPTY_FINGERPRINT =
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";

function find(stream, signature, limit = 1024, backwards = false) {
if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
assert(limit > 0, 'The "limit" must be a positive integer.');
Expand Down Expand Up @@ -1548,30 +1545,24 @@ class PDFDocument {
}

get fingerprints() {
const FINGERPRINT_FIRST_BYTES = 1024;
const EMPTY_FINGERPRINT = "\x00".repeat(16);

function validate(data) {
return (
typeof data === "string" &&
data.length > 0 &&
data.length === 16 &&
data !== EMPTY_FINGERPRINT
);
}

function hexString(hash) {
const buf = [];
for (const num of hash) {
const hex = num.toString(16);
buf.push(hex.padStart(2, "0"));
}
return buf.join("");
}

const idArray = this.xref.trailer.get("ID");
const id = this.xref.trailer.get("ID");
let hashOriginal, hashModified;
if (Array.isArray(idArray) && validate(idArray[0])) {
hashOriginal = stringToBytes(idArray[0]);
if (Array.isArray(id) && validate(id[0])) {
hashOriginal = stringToBytes(id[0]);

if (idArray[1] !== idArray[0] && validate(idArray[1])) {
hashModified = stringToBytes(idArray[1]);
if (id[1] !== id[0] && validate(id[1])) {
hashModified = stringToBytes(id[1]);
}
} else {
hashOriginal = calculateMD5(
Expand All @@ -1582,8 +1573,8 @@ class PDFDocument {
}

return shadow(this, "fingerprints", [
hexString(hashOriginal),
hashModified ? hexString(hashModified) : null,
toHexUtil(hashOriginal),
hashModified ? toHexUtil(hashModified) : null,
]);
}

Expand Down
4 changes: 2 additions & 2 deletions src/core/xfa/template.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ import {
XFAObject,
XFAObjectArray,
} from "./xfa_object.js";
import { fromBase64Util, Util, warn } from "../../shared/util.js";
import {
getBBox,
getColor,
Expand All @@ -102,7 +103,6 @@ import {
getStringOption,
HTMLResult,
} from "./utils.js";
import { stringToBytes, Util, warn } from "../../shared/util.js";
import { getMetrics } from "./fonts.js";
import { recoverJsURL } from "../core_utils.js";
import { searchNode } from "./som.js";
Expand Down Expand Up @@ -3427,7 +3427,7 @@ class Image extends StringObject {
}

if (!buffer && this.transferEncoding === "base64") {
buffer = stringToBytes(atob(this[$content]));
buffer = fromBase64Util(this[$content]);
}

if (!buffer) {
Expand Down
5 changes: 2 additions & 3 deletions src/display/font_loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@

import {
assert,
bytesToString,
FontRenderOps,
isNodeJS,
shadow,
string32,
toBase64Util,
unreachable,
warn,
} from "../shared/util.js";
Expand Down Expand Up @@ -399,9 +399,8 @@ class FontFaceObject {
if (!this.data || this.disableFontFace) {
return null;
}
const data = bytesToString(this.data);
// Add the @font-face rule to the document.
const url = `url(data:${this.mimetype};base64,${btoa(data)});`;
const url = `url(data:${this.mimetype};base64,${toBase64Util(this.data)});`;
let rule;
if (!this.cssFontInfo) {
rule = `@font-face {font-family:"${this.loadedName}";src:${url}}`;
Expand Down
32 changes: 32 additions & 0 deletions src/shared/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -1097,6 +1097,35 @@ const FontRenderOps = {
TRANSLATE: 8,
};

// TODO: Remove this once `Uint8Array.prototype.toHex` is generally available.
function toHexUtil(arr) {
if (Uint8Array.prototype.toHex) {
calixteman marked this conversation as resolved.
Show resolved Hide resolved
return arr.toHex();
}
const buf = [];
for (const num of arr) {
buf.push(num.toString(16).padStart(2, "0"));
}
return buf.join("");
}

// TODO: Remove this once `Uint8Array.prototype.toBase64` is generally
// available.
function toBase64Util(arr) {
if (Uint8Array.prototype.toBase64) {
return arr.toBase64();
}
return btoa(bytesToString(arr));
}

// TODO: Remove this once `Uint8Array.fromBase64` is generally available.
function fromBase64Util(str) {
if (Uint8Array.fromBase64) {
return Uint8Array.fromBase64(str);
}
return stringToBytes(atob(str));
}

export {
AbortException,
AnnotationActionEventType,
Expand All @@ -1120,6 +1149,7 @@ export {
FONT_IDENTITY_MATRIX,
FontRenderOps,
FormatError,
fromBase64Util,
getModificationDate,
getUuid,
getVerbosityLevel,
Expand Down Expand Up @@ -1149,6 +1179,8 @@ export {
stringToPDFString,
stringToUTF8String,
TextRenderingMode,
toBase64Util,
toHexUtil,
UnexpectedResponseException,
UnknownErrorException,
unreachable,
Expand Down