Skip to content

Commit 471adfd

Browse files
Merge pull request #20596 from Snuffleupagus/FileSpec-fixes
Simplify the `FileSpec` class, and remove no longer needed polyfills
2 parents 7cdd03a + 5b368dd commit 471adfd

14 files changed

Lines changed: 59 additions & 137 deletions

src/core/annotation.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5290,8 +5290,8 @@ class FileAttachmentAnnotation extends MarkupAnnotation {
52905290
constructor(params) {
52915291
super(params);
52925292

5293-
const { dict, xref } = params;
5294-
const file = new FileSpec(dict.get("FS"), xref);
5293+
const { dict } = params;
5294+
const file = new FileSpec(dict.get("FS"));
52955295

52965296
this.data.annotationType = AnnotationType.FILEATTACHMENT;
52975297
this.data.hasOwnCanvas = this.data.noRotate;

src/core/catalog.js

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,7 +1057,7 @@ class Catalog {
10571057
if (obj instanceof Dict && obj.has("EmbeddedFiles")) {
10581058
const nameTree = new NameTree(obj.getRaw("EmbeddedFiles"), this.xref);
10591059
for (const [key, value] of nameTree.getAll()) {
1060-
const fs = new FileSpec(value, this.xref);
1060+
const fs = new FileSpec(value);
10611061
attachments ??= Object.create(null);
10621062
attachments[stringToPDFString(key, /* keepEscapeSequence = */ true)] =
10631063
fs.serializable;
@@ -1623,23 +1623,21 @@ class Catalog {
16231623
case "GoToR":
16241624
const urlDict = action.get("F");
16251625
if (urlDict instanceof Dict) {
1626-
const fs = new FileSpec(
1627-
urlDict,
1628-
/* xref = */ null,
1629-
/* skipContent = */ true
1630-
);
1631-
const { rawFilename } = fs.serializable;
1632-
url = rawFilename;
1626+
const fs = new FileSpec(urlDict, /* skipContent = */ true);
1627+
({ rawFilename: url } = fs.serializable);
16331628
} else if (typeof urlDict === "string") {
16341629
url = urlDict;
1630+
} else {
1631+
break;
16351632
}
16361633

16371634
// NOTE: the destination is relative to the *remote* document.
16381635
const remoteDest = fetchRemoteDest(action);
1639-
if (remoteDest && typeof url === "string") {
1636+
if (remoteDest) {
16401637
// NOTE: We don't use the `updateUrlHash` function here, since
1641-
// the `createValidAbsoluteUrl` function (see below) already
1642-
// handles parsing and validation of the final URL.
1638+
// the `createValidAbsoluteUrl` function (see below) already handles
1639+
// parsing/validation of the final URL and manual splitting also
1640+
// ensures that the `unsafeUrl` property will be available/correct.
16431641
url = /* baseUrl = */ url.split("#", 1)[0] + "#" + remoteDest;
16441642
}
16451643
// The 'NewWindow' property, equal to `LinkTarget.BLANK`.

src/core/document.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import {
2727
stringToBytes,
2828
stringToPDFString,
2929
stringToUTF8String,
30-
toHexUtil,
3130
unreachable,
3231
Util,
3332
warn,
@@ -1628,8 +1627,8 @@ class PDFDocument {
16281627
}
16291628

16301629
return shadow(this, "fingerprints", [
1631-
toHexUtil(hashOriginal),
1632-
hashModified ? toHexUtil(hashModified) : null,
1630+
hashOriginal.toHex(),
1631+
hashModified?.toHex() ?? null,
16331632
]);
16341633
}
16351634

src/core/file_spec.js

Lines changed: 25 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,18 @@
1313
* limitations under the License.
1414
*/
1515

16-
import { shadow, stringToPDFString, warn } from "../shared/util.js";
16+
import { stringToPDFString, warn } from "../shared/util.js";
1717
import { BaseStream } from "./base_stream.js";
1818
import { Dict } from "./primitives.js";
1919

2020
function pickPlatformItem(dict) {
21-
if (!(dict instanceof Dict)) {
22-
return null;
23-
}
24-
// Look for the filename in this order:
25-
// UF, F, Unix, Mac, DOS
26-
if (dict.has("UF")) {
27-
return dict.get("UF");
28-
} else if (dict.has("F")) {
29-
return dict.get("F");
30-
} else if (dict.has("Unix")) {
31-
return dict.get("Unix");
32-
} else if (dict.has("Mac")) {
33-
return dict.get("Mac");
34-
} else if (dict.has("DOS")) {
35-
return dict.get("DOS");
21+
if (dict instanceof Dict) {
22+
// Look for the filename in this order: UF, F, Unix, Mac, DOS
23+
for (const key of ["UF", "F", "Unix", "Mac", "DOS"]) {
24+
if (dict.has(key)) {
25+
return dict.get(key);
26+
}
27+
}
3628
}
3729
return null;
3830
}
@@ -51,11 +43,10 @@ function stripPath(str) {
5143
class FileSpec {
5244
#contentAvailable = false;
5345

54-
constructor(root, xref, skipContent = false) {
46+
constructor(root, skipContent = false) {
5547
if (!(root instanceof Dict)) {
5648
return;
5749
}
58-
this.xref = xref;
5950
this.root = root;
6051
if (root.has("FS")) {
6152
this.fs = root.get("FS");
@@ -73,56 +64,46 @@ class FileSpec {
7364
}
7465

7566
get filename() {
76-
let filename = "";
77-
7867
const item = pickPlatformItem(this.root);
7968
if (item && typeof item === "string") {
80-
filename = stringToPDFString(item, /* keepEscapeSequence = */ true)
69+
// NOTE: The following replacement order is INTENTIONAL, regardless of
70+
// what some static code analysers (e.g. CodeQL) may claim.
71+
return stringToPDFString(item, /* keepEscapeSequence = */ true)
8172
.replaceAll("\\\\", "\\")
8273
.replaceAll("\\/", "/")
8374
.replaceAll("\\", "/");
8475
}
85-
return shadow(this, "filename", filename || "unnamed");
76+
return "";
8677
}
8778

8879
get content() {
8980
if (!this.#contentAvailable) {
9081
return null;
9182
}
92-
this._contentRef ||= pickPlatformItem(this.root?.get("EF"));
83+
const ef = pickPlatformItem(this.root?.get("EF"));
9384

94-
let content = null;
95-
if (this._contentRef) {
96-
const fileObj = this.xref.fetchIfRef(this._contentRef);
97-
if (fileObj instanceof BaseStream) {
98-
content = fileObj.getBytes();
99-
} else {
100-
warn(
101-
"Embedded file specification points to non-existing/invalid content"
102-
);
103-
}
104-
} else {
105-
warn("Embedded file specification does not have any content");
85+
if (ef instanceof BaseStream) {
86+
return ef.getBytes();
10687
}
107-
return content;
88+
warn("Embedded file specification points to non-existing/invalid content");
89+
return null;
10890
}
10991

11092
get description() {
111-
let description = "";
112-
11393
const desc = this.root?.get("Desc");
11494
if (desc && typeof desc === "string") {
115-
description = stringToPDFString(desc);
95+
return stringToPDFString(desc);
11696
}
117-
return shadow(this, "description", description);
97+
return "";
11898
}
11999

120100
get serializable() {
101+
const { filename, content, description } = this;
121102
return {
122-
rawFilename: this.filename,
123-
filename: stripPath(this.filename),
124-
content: this.content,
125-
description: this.description,
103+
rawFilename: filename,
104+
filename: stripPath(filename) || "unnamed",
105+
content,
106+
description,
126107
};
127108
}
128109
}

src/core/xfa/template.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ import {
9090
XFAObject,
9191
XFAObjectArray,
9292
} from "./xfa_object.js";
93-
import { fromBase64Util, Util, warn } from "../../shared/util.js";
9493
import {
9594
getBBox,
9695
getColor,
@@ -103,6 +102,7 @@ import {
103102
getStringOption,
104103
HTMLResult,
105104
} from "./utils.js";
105+
import { Util, warn } from "../../shared/util.js";
106106
import { getMetrics } from "./fonts.js";
107107
import { recoverJsURL } from "../core_utils.js";
108108
import { searchNode } from "./som.js";
@@ -3420,7 +3420,7 @@ class Image extends StringObject {
34203420
}
34213421

34223422
if (!buffer && this.transferEncoding === "base64") {
3423-
buffer = fromBase64Util(this[$content]);
3423+
buffer = Uint8Array.fromBase64(this[$content]);
34243424
}
34253425

34263426
if (!buffer) {

src/display/editor/drawers/signaturedraw.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
* limitations under the License.
1414
*/
1515

16-
import { fromBase64Util, toBase64Util, warn } from "../../../shared/util.js";
1716
import { ContourDrawOutline } from "./contour.js";
1817
import { InkDrawOutline } from "./inkdraw.js";
1918
import { Outline } from "./outline.js";
19+
import { warn } from "../../../shared/util.js";
2020

2121
const BASE_HEADER_LENGTH = 8;
2222
const POINTS_PROPERTIES_NUMBER = 3;
@@ -749,12 +749,12 @@ class SignatureExtractor {
749749
const buf = await new Response(cs.readable).arrayBuffer();
750750
const bytes = new Uint8Array(buf);
751751

752-
return toBase64Util(bytes);
752+
return bytes.toBase64();
753753
}
754754

755755
static async decompressSignature(signatureData) {
756756
try {
757-
const bytes = fromBase64Util(signatureData);
757+
const bytes = Uint8Array.fromBase64(signatureData);
758758
const { readable, writable } = new DecompressionStream("deflate-raw");
759759
const writer = writable.getWriter();
760760
await writer.ready;

src/display/font_loader.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import {
1919
isNodeJS,
2020
shadow,
2121
string32,
22-
toBase64Util,
2322
unreachable,
2423
warn,
2524
} from "../shared/util.js";
@@ -408,7 +407,7 @@ class FontFaceObject {
408407
return null;
409408
}
410409
// Add the @font-face rule to the document.
411-
const url = `url(data:${this.mimetype};base64,${toBase64Util(this.data)});`;
410+
const url = `url(data:${this.mimetype};base64,${this.data.toBase64()});`;
412411
let rule;
413412
if (!this.cssFontInfo) {
414413
rule = `@font-face {font-family:"${this.loadedName}";src:${url}}`;

src/shared/util.js

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,44 +1235,6 @@ function MathClamp(v, min, max) {
12351235
return Math.min(Math.max(v, min), max);
12361236
}
12371237

1238-
// TODO: Remove this once `Uint8Array.prototype.toHex` is generally available.
1239-
function toHexUtil(arr) {
1240-
if (Uint8Array.prototype.toHex) {
1241-
return arr.toHex();
1242-
}
1243-
return Array.from(arr, num => hexNumbers[num]).join("");
1244-
}
1245-
1246-
// TODO: Remove this once `Uint8Array.prototype.toBase64` is generally
1247-
// available.
1248-
function toBase64Util(arr) {
1249-
if (Uint8Array.prototype.toBase64) {
1250-
return arr.toBase64();
1251-
}
1252-
return btoa(bytesToString(arr));
1253-
}
1254-
1255-
// TODO: Remove this once `Uint8Array.fromBase64` is generally available.
1256-
function fromBase64Util(str) {
1257-
if (Uint8Array.fromBase64) {
1258-
return Uint8Array.fromBase64(str);
1259-
}
1260-
return stringToBytes(atob(str));
1261-
}
1262-
1263-
// TODO: Remove this once https://bugzilla.mozilla.org/show_bug.cgi?id=1928493
1264-
// is fixed.
1265-
if (
1266-
(typeof PDFJSDev === "undefined" || PDFJSDev.test("SKIP_BABEL")) &&
1267-
typeof Promise.try !== "function"
1268-
) {
1269-
Promise.try = function (fn, ...args) {
1270-
return new Promise(resolve => {
1271-
resolve(fn(...args));
1272-
});
1273-
};
1274-
}
1275-
12761238
// TODO: Remove this once the `javascript.options.experimental.math_sumprecise`
12771239
// preference is removed from Firefox.
12781240
if (typeof Math.sumPrecise !== "function") {
@@ -1338,7 +1300,6 @@ export {
13381300
FeatureTest,
13391301
FONT_IDENTITY_MATRIX,
13401302
FormatError,
1341-
fromBase64Util,
13421303
getModificationDate,
13431304
getUuid,
13441305
getVerbosityLevel,
@@ -1368,8 +1329,6 @@ export {
13681329
stringToPDFString,
13691330
stringToUTF8String,
13701331
TextRenderingMode,
1371-
toBase64Util,
1372-
toHexUtil,
13731332
UnknownErrorException,
13741333
unreachable,
13751334
updateUrlHash,

test/font/font_core_spec.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/font/font_fpgm_spec.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)