diff --git a/src/core/chunked_stream.js b/src/core/chunked_stream.js index 4105dcd89..940c419a0 100644 --- a/src/core/chunked_stream.js +++ b/src/core/chunked_stream.js @@ -13,12 +13,8 @@ * limitations under the License. */ -import { - arrayBuffersToBytes, - assert, - createPromiseCapability, -} from "../shared/util.js"; -import { MissingDataException } from "./core_utils.js"; +import { arrayBuffersToBytes, MissingDataException } from "./core_utils.js"; +import { assert, createPromiseCapability } from "../shared/util.js"; import { Stream } from "./stream.js"; class ChunkedStream extends Stream { diff --git a/src/core/core_utils.js b/src/core/core_utils.js index af1d01246..f4541dabe 100644 --- a/src/core/core_utils.js +++ b/src/core/core_utils.js @@ -80,6 +80,44 @@ class XRefParseException extends BaseException { } } +/** + * Combines multiple ArrayBuffers into a single Uint8Array. + * @param {Array} arr - An array of ArrayBuffers. + * @returns {Uint8Array} + */ +function arrayBuffersToBytes(arr) { + if ( + typeof PDFJSDev === "undefined" || + PDFJSDev.test("!PRODUCTION || TESTING") + ) { + for (const item of arr) { + assert( + item instanceof ArrayBuffer, + "arrayBuffersToBytes - expected an ArrayBuffer." + ); + } + } + const length = arr.length; + if (length === 0) { + return new Uint8Array(0); + } + if (length === 1) { + return new Uint8Array(arr[0]); + } + let dataLength = 0; + for (let i = 0; i < length; i++) { + dataLength += arr[i].byteLength; + } + const data = new Uint8Array(dataLength); + let pos = 0; + for (let i = 0; i < length; i++) { + const item = new Uint8Array(arr[i]); + data.set(item, pos); + pos += item.byteLength; + } + return data; +} + /** * Get the value of an inheritable property. * @@ -579,6 +617,7 @@ function getRotationMatrix(rotation, width, height) { } export { + arrayBuffersToBytes, collectActions, encodeToXmlString, escapePDFName, diff --git a/src/core/worker.js b/src/core/worker.js index e82f7aef5..0f8c0003c 100644 --- a/src/core/worker.js +++ b/src/core/worker.js @@ -15,7 +15,6 @@ import { AbortException, - arrayBuffersToBytes, assert, createPromiseCapability, getVerbosityLevel, @@ -30,8 +29,12 @@ import { VerbosityLevel, warn, } from "../shared/util.js"; +import { + arrayBuffersToBytes, + getNewAnnotationsMap, + XRefParseException, +} from "./core_utils.js"; import { Dict, Ref } from "./primitives.js"; -import { getNewAnnotationsMap, XRefParseException } from "./core_utils.js"; import { LocalPdfManager, NetworkPdfManager } from "./pdf_manager.js"; import { clearGlobalCaches } from "./cleanup_helper.js"; import { incrementalUpdate } from "./writer.js"; diff --git a/src/shared/util.js b/src/shared/util.js index 520341698..8dca9842d 100644 --- a/src/shared/util.js +++ b/src/shared/util.js @@ -597,44 +597,6 @@ function stringToBytes(str) { return bytes; } -/** - * Combines multiple ArrayBuffers into a single Uint8Array. - * @param {Array} arr - An array of ArrayBuffers. - * @returns {Uint8Array} - */ -function arrayBuffersToBytes(arr) { - if ( - typeof PDFJSDev === "undefined" || - PDFJSDev.test("!PRODUCTION || TESTING") - ) { - for (const item of arr) { - assert( - item instanceof ArrayBuffer, - "arrayBuffersToBytes - expected an ArrayBuffer." - ); - } - } - const length = arr.length; - if (length === 0) { - return new Uint8Array(0); - } - if (length === 1) { - return new Uint8Array(arr[0]); - } - let dataLength = 0; - for (let i = 0; i < length; i++) { - dataLength += arr[i].byteLength; - } - const data = new Uint8Array(dataLength); - let pos = 0; - for (let i = 0; i < length; i++) { - const item = new Uint8Array(arr[i]); - data.set(item, pos); - pos += item.byteLength; - } - return data; -} - function string32(value) { if ( typeof PDFJSDev === "undefined" || @@ -1103,7 +1065,6 @@ export { AnnotationReviewState, AnnotationStateModelType, AnnotationType, - arrayBuffersToBytes, assert, BaseException, BASELINE_FACTOR, diff --git a/test/unit/core_utils_spec.js b/test/unit/core_utils_spec.js index f8fb8da16..bc7266ba1 100644 --- a/test/unit/core_utils_spec.js +++ b/test/unit/core_utils_spec.js @@ -13,8 +13,8 @@ * limitations under the License. */ -import { Dict, Ref } from "../../src/core/primitives.js"; import { + arrayBuffersToBytes, encodeToXmlString, escapePDFName, escapeString, @@ -30,9 +30,36 @@ import { toRomanNumerals, validateCSSFont, } from "../../src/core/core_utils.js"; +import { Dict, Ref } from "../../src/core/primitives.js"; import { XRefMock } from "./test_utils.js"; describe("core_utils", function () { + describe("arrayBuffersToBytes", function () { + it("handles zero ArrayBuffers", function () { + const bytes = arrayBuffersToBytes([]); + + expect(bytes).toEqual(new Uint8Array(0)); + }); + + it("handles one ArrayBuffer", function () { + const buffer = new Uint8Array([1, 2, 3]).buffer; + const bytes = arrayBuffersToBytes([buffer]); + + expect(bytes).toEqual(new Uint8Array([1, 2, 3])); + // Ensure that the fast-path works correctly. + expect(bytes.buffer).toBe(buffer); + }); + + it("handles multiple ArrayBuffers", function () { + const buffer1 = new Uint8Array([1, 2, 3]).buffer, + buffer2 = new Uint8Array(0).buffer, + buffer3 = new Uint8Array([4, 5]).buffer; + const bytes = arrayBuffersToBytes([buffer1, buffer2, buffer3]); + + expect(bytes).toEqual(new Uint8Array([1, 2, 3, 4, 5])); + }); + }); + describe("getInheritableProperty", function () { it("handles non-dictionary arguments", function () { expect(getInheritableProperty({ dict: null, key: "foo" })).toEqual(