From dc4eb71ff152460afdd8762043226443f005f503 Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Wed, 9 Sep 2020 18:39:14 +0200 Subject: [PATCH] PDF names need to be escaped when saving --- src/core/core_utils.js | 26 ++++++++++++++++++++++++++ src/core/writer.js | 4 ++-- test/unit/core_utils_spec.js | 13 +++++++++++++ test/unit/writer_spec.js | 15 +++++++++++++++ 4 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/core/core_utils.js b/src/core/core_utils.js index 32ffab86d54b4..464442ee33d09 100644 --- a/src/core/core_utils.js +++ b/src/core/core_utils.js @@ -185,7 +185,33 @@ function parseXFAPath(path) { }); } +function escapePDFName(str) { + const buffer = []; + let start = 0; + for (let i = 0, ii = str.length; i < ii; i++) { + const char = str.charCodeAt(i); + if (char < 0x21 || char > 0x7e || char === 0x23) { + if (start < i) { + buffer.push(str.substring(start, i)); + } + buffer.push(`#${char.toString(16)}`); + start = i + 1; + } + } + + if (buffer.length === 0) { + return str; + } + + if (start < str.length) { + buffer.push(str.substring(start, str.length)); + } + + return buffer.join(""); +} + export { + escapePDFName, getLookupTableFactory, MissingDataException, XRefEntryException, diff --git a/src/core/writer.js b/src/core/writer.js index 43294bfdb6f5e..630357fd0bb2a 100644 --- a/src/core/writer.js +++ b/src/core/writer.js @@ -16,9 +16,9 @@ import { bytesToString, escapeString, warn } from "../shared/util.js"; import { Dict, isDict, isName, isRef, isStream, Name } from "./primitives.js"; +import { escapePDFName, parseXFAPath } from "./core_utils.js"; import { SimpleDOMNode, SimpleXMLParser } from "../shared/xml_parser.js"; import { calculateMD5 } from "./crypto.js"; -import { parseXFAPath } from "./core_utils.js"; function writeDict(dict, buffer, transform) { buffer.push("<<"); @@ -73,7 +73,7 @@ function numberToString(value) { function writeValue(value, buffer, transform) { if (isName(value)) { - buffer.push(`/${value.name}`); + buffer.push(`/${escapePDFName(value.name)}`); } else if (isRef(value)) { buffer.push(`${value.num} ${value.gen} R`); } else if (Array.isArray(value)) { diff --git a/test/unit/core_utils_spec.js b/test/unit/core_utils_spec.js index 392440848c02b..74c99558d7e2d 100644 --- a/test/unit/core_utils_spec.js +++ b/test/unit/core_utils_spec.js @@ -15,6 +15,7 @@ import { Dict, Ref } from "../../src/core/primitives.js"; import { + escapePDFName, getInheritableProperty, isWhiteSpace, log2, @@ -226,4 +227,16 @@ describe("core_utils", function () { ]); }); }); + + describe("escapePDFName", function () { + it("should escape PDF name", function () { + expect(escapePDFName("hello")).toEqual("hello"); + expect(escapePDFName("\xfehello")).toEqual("#fehello"); + expect(escapePDFName("he\xfell\xffo")).toEqual("he#fell#ffo"); + expect(escapePDFName("\xfehe\xfell\xffo\xff")).toEqual( + "#fehe#fell#ffo#ff" + ); + expect(escapePDFName("#h#e#l#l#o")).toEqual("#23h#23e#23l#23l#23o"); + }); + }); }); diff --git a/test/unit/writer_spec.js b/test/unit/writer_spec.js index 21c917d6e2552..6f4d47f45e108 100644 --- a/test/unit/writer_spec.js +++ b/test/unit/writer_spec.js @@ -95,5 +95,20 @@ describe("Writer", function () { expect(buffer.join("")).toEqual(expected); done(); }); + + it("should write a Dict in escaping PDF names", function (done) { + const dict = new Dict(null); + dict.set("A", Name.get("hello")); + dict.set("B", Name.get("#hello")); + dict.set("C", Name.get("he\xfello\xff")); + + const buffer = []; + writeDict(dict, buffer, null); + + const expected = "<< /A /hello /B /#23hello /C /he#fello#ff>>"; + + expect(buffer.join("")).toEqual(expected); + done(); + }); }); });