@awacloud/pdf 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +609 -0
- package/LICENSE +661 -0
- package/NOTICE +77 -0
- package/README.md +363 -2
- package/dist/build/index.js +21 -0
- package/dist/build/pdf-full-rw.js +10972 -0
- package/dist/build/pdf-full-rw.meta.json +105 -0
- package/dist/build/pdf-full-rw.min.js +53 -0
- package/dist/build/pdf-full.js +6078 -0
- package/dist/build/pdf-full.meta.json +90 -0
- package/dist/build/pdf-full.min.js +32 -0
- package/dist/build/pdf-large-rw.js +10367 -0
- package/dist/build/pdf-large-rw.meta.json +99 -0
- package/dist/build/pdf-large-rw.min.js +53 -0
- package/dist/build/pdf-large.js +5473 -0
- package/dist/build/pdf-large.meta.json +84 -0
- package/dist/build/pdf-large.min.js +32 -0
- package/dist/build/pdf-legacy-rw.js +12402 -0
- package/dist/build/pdf-legacy-rw.meta.json +110 -0
- package/dist/build/pdf-legacy-rw.min.js +53 -0
- package/dist/build/pdf-legacy.js +7508 -0
- package/dist/build/pdf-legacy.meta.json +95 -0
- package/dist/build/pdf-legacy.min.js +32 -0
- package/dist/build/pdf-rw.js +7578 -0
- package/dist/build/pdf-rw.meta.json +77 -0
- package/dist/build/pdf-rw.min.js +53 -0
- package/dist/build/pdf.js +2684 -0
- package/dist/build/pdf.meta.json +62 -0
- package/dist/build/pdf.min.js +32 -0
- package/dist/standalone/pdf-full-rw.js +16798 -0
- package/dist/standalone/pdf-full-rw.meta.json +78 -0
- package/dist/standalone/pdf-full-rw.min.js +56 -0
- package/dist/standalone/pdf-full.js +11904 -0
- package/dist/standalone/pdf-full.meta.json +63 -0
- package/dist/standalone/pdf-full.min.js +35 -0
- package/dist/standalone/pdf-large-rw.js +16193 -0
- package/dist/standalone/pdf-large-rw.meta.json +72 -0
- package/dist/standalone/pdf-large-rw.min.js +56 -0
- package/dist/standalone/pdf-large.js +11299 -0
- package/dist/standalone/pdf-large.meta.json +57 -0
- package/dist/standalone/pdf-large.min.js +35 -0
- package/dist/standalone/pdf-legacy-rw.js +18228 -0
- package/dist/standalone/pdf-legacy-rw.meta.json +83 -0
- package/dist/standalone/pdf-legacy-rw.min.js +56 -0
- package/dist/standalone/pdf-legacy.js +13334 -0
- package/dist/standalone/pdf-legacy.meta.json +68 -0
- package/dist/standalone/pdf-legacy.min.js +35 -0
- package/dist/standalone/pdf-rw.js +13404 -0
- package/dist/standalone/pdf-rw.meta.json +50 -0
- package/dist/standalone/pdf-rw.min.js +56 -0
- package/dist/standalone/pdf.js +8510 -0
- package/dist/standalone/pdf.meta.json +35 -0
- package/dist/standalone/pdf.min.js +35 -0
- package/docs/README.md +53 -0
- package/docs/api/README.md +38 -0
- package/docs/api/_shared/README.md +91 -0
- package/docs/api/action/README.md +29 -0
- package/docs/api/action/action.md +81 -0
- package/docs/api/action/goTo.md +66 -0
- package/docs/api/action/launch.md +58 -0
- package/docs/api/action/named.md +55 -0
- package/docs/api/action/uri.md +54 -0
- package/docs/api/annot/README.md +53 -0
- package/docs/api/annot/annot.md +114 -0
- package/docs/api/annot/fileAttach.md +53 -0
- package/docs/api/annot/freeText.md +68 -0
- package/docs/api/annot/ink.md +69 -0
- package/docs/api/annot/link.md +74 -0
- package/docs/api/annot/markup.md +83 -0
- package/docs/api/annot/popup.md +52 -0
- package/docs/api/annot/projection.md +56 -0
- package/docs/api/annot/redact.md +67 -0
- package/docs/api/annot/square.md +87 -0
- package/docs/api/annot/stamp.md +54 -0
- package/docs/api/annot/text.md +69 -0
- package/docs/api/annot/widget.md +69 -0
- package/docs/api/associatedFiles/README.md +9 -0
- package/docs/api/associatedFiles/associatedFiles.md +78 -0
- package/docs/api/bundles/README.md +68 -0
- package/docs/api/bundles/dist-matrix.md +165 -0
- package/docs/api/bundles/pdf-full.md +148 -0
- package/docs/api/bundles/pdf-large.md +144 -0
- package/docs/api/bundles/pdf-legacy.md +169 -0
- package/docs/api/content/README.md +29 -0
- package/docs/api/content/color.md +99 -0
- package/docs/api/content/graphics.md +114 -0
- package/docs/api/content/images.md +124 -0
- package/docs/api/content/ops.md +100 -0
- package/docs/api/content/stream.md +107 -0
- package/docs/api/content/text.md +98 -0
- package/docs/api/crypto/README.md +29 -0
- package/docs/api/crypto/aesGcm.md +72 -0
- package/docs/api/crypto/permissions.md +79 -0
- package/docs/api/crypto/security.md +98 -0
- package/docs/api/crypto/standardV4.md +104 -0
- package/docs/api/crypto/standardV5.md +84 -0
- package/docs/api/crypto/standardV6.md +93 -0
- package/docs/api/destination/README.md +9 -0
- package/docs/api/destination/destination.md +79 -0
- package/docs/api/document/README.md +29 -0
- package/docs/api/document/builder.md +281 -0
- package/docs/api/document/catalog.md +98 -0
- package/docs/api/document/document.md +187 -0
- package/docs/api/document/encryptedWriter.md +149 -0
- package/docs/api/document/incrementalWriter.md +148 -0
- package/docs/api/document/page.md +99 -0
- package/docs/api/document/pages.md +82 -0
- package/docs/api/document/resources.md +102 -0
- package/docs/api/document/writer.md +157 -0
- package/docs/api/document/xrefStreamWriter.md +122 -0
- package/docs/api/embedded/README.md +13 -0
- package/docs/api/embedded/collection.md +80 -0
- package/docs/api/embedded/embeddedFile.md +86 -0
- package/docs/api/embedded/fileSpec.md +87 -0
- package/docs/api/errors.md +110 -0
- package/docs/api/extra/3d-richmedia.md +76 -0
- package/docs/api/extra/README.md +99 -0
- package/docs/api/extra/annot-extended.md +71 -0
- package/docs/api/extra/associated-files.md +70 -0
- package/docs/api/extra/ccitt-fax-decoder.md +74 -0
- package/docs/api/extra/color-spaces-extended.md +72 -0
- package/docs/api/extra/content-ops-extended.md +82 -0
- package/docs/api/extra/document-parts.md +69 -0
- package/docs/api/extra/embedded-files-portfolio.md +87 -0
- package/docs/api/extra/font-cid-typed.md +77 -0
- package/docs/api/extra/font-color-tagging.md +76 -0
- package/docs/api/extra/form-actions-extended.md +75 -0
- package/docs/api/extra/info-dict-deprecated.md +72 -0
- package/docs/api/extra/jbig2-read.md +80 -0
- package/docs/api/extra/legacy-deprecated-annots.md +89 -0
- package/docs/api/extra/legacy-deprecated-filters.md +78 -0
- package/docs/api/extra/legacy-rc4-read.md +74 -0
- package/docs/api/extra/legacy-xfa-read.md +65 -0
- package/docs/api/extra/linearization-write.md +71 -0
- package/docs/api/extra/misc.md +93 -0
- package/docs/api/extra/optional-content-extended.md +83 -0
- package/docs/api/extra/pdf-a-output-intent.md +65 -0
- package/docs/api/extra/pdf-sandbox.md +76 -0
- package/docs/api/extra/pdf-ua-tagged.md +63 -0
- package/docs/api/extra/pdf-x-prepress.md +65 -0
- package/docs/api/extra/redaction-iso32005.md +65 -0
- package/docs/api/extra/shading-typed.md +73 -0
- package/docs/api/extra/sig-aes-gcm.md +69 -0
- package/docs/api/extra/sig-pades.md +103 -0
- package/docs/api/extra/tagged-pdf-typed.md +78 -0
- package/docs/api/extra/transparency-typed.md +74 -0
- package/docs/api/extra/well-tagged-pdf.md +61 -0
- package/docs/api/extra/xmp-extended.md +65 -0
- package/docs/api/font/README.md +25 -0
- package/docs/api/font/embed.md +157 -0
- package/docs/api/font/encoding.md +95 -0
- package/docs/api/font/font.md +97 -0
- package/docs/api/font/type3.md +89 -0
- package/docs/api/form/README.md +35 -0
- package/docs/api/form/acroform.md +88 -0
- package/docs/api/form/appearance.md +87 -0
- package/docs/api/form/button.md +97 -0
- package/docs/api/form/choice.md +96 -0
- package/docs/api/form/fieldTree.md +93 -0
- package/docs/api/form/signature.md +90 -0
- package/docs/api/form/text.md +88 -0
- package/docs/api/linearization/README.md +11 -0
- package/docs/api/linearization/linearization.md +81 -0
- package/docs/api/main.md +116 -0
- package/docs/api/metadata/README.md +10 -0
- package/docs/api/metadata/info.md +70 -0
- package/docs/api/metadata/xmp.md +62 -0
- package/docs/api/ocg/README.md +23 -0
- package/docs/api/ocg/config.md +95 -0
- package/docs/api/ocg/ocg.md +77 -0
- package/docs/api/outline/README.md +11 -0
- package/docs/api/outline/outline.md +107 -0
- package/docs/api/pdf.md +152 -0
- package/docs/api/prepress/README.md +10 -0
- package/docs/api/prepress/outputIntent.md +79 -0
- package/docs/api/prepress/pageBoundary.md +75 -0
- package/docs/api/sig/README.md +32 -0
- package/docs/api/sig/byteRange.md +120 -0
- package/docs/api/sig/certChain.md +84 -0
- package/docs/api/sig/dss.md +111 -0
- package/docs/api/sig/oids.md +76 -0
- package/docs/api/sig/sha1.md +72 -0
- package/docs/api/sig/sign.md +317 -0
- package/docs/api/sig/signature.md +178 -0
- package/docs/api/sig/timestamp.md +84 -0
- package/docs/api/syntax/README.md +29 -0
- package/docs/api/syntax/crossRefStream.md +115 -0
- package/docs/api/syntax/filters/README.md +50 -0
- package/docs/api/syntax/filters/ascii85.md +76 -0
- package/docs/api/syntax/filters/asciiHex.md +73 -0
- package/docs/api/syntax/filters/dispatch.md +125 -0
- package/docs/api/syntax/filters/flate.md +134 -0
- package/docs/api/syntax/filters/runLength.md +78 -0
- package/docs/api/syntax/objStream.md +88 -0
- package/docs/api/syntax/parser-obj.md +97 -0
- package/docs/api/syntax/parser.md +151 -0
- package/docs/api/syntax/serializer.md +109 -0
- package/docs/api/syntax/tokenizer.md +104 -0
- package/docs/api/syntax/trailer.md +85 -0
- package/docs/api/syntax/xref.md +139 -0
- package/docs/api/tagged/README.md +25 -0
- package/docs/api/tagged/classMap.md +67 -0
- package/docs/api/tagged/markedContent.md +62 -0
- package/docs/api/tagged/parentTree.md +67 -0
- package/docs/api/tagged/roleMap.md +67 -0
- package/docs/api/tagged/structElement.md +76 -0
- package/docs/api/tagged/structTree.md +75 -0
- package/docs/guide/coverage.md +113 -0
- package/docs/guide/crypto.md +121 -0
- package/docs/guide/extending.md +76 -0
- package/docs/guide/getting-started.md +75 -0
- package/docs/guide/legacy-1.7.md +42 -0
- package/docs/guide/pades-integration.md +579 -0
- package/docs/guide/read-pdf.md +89 -0
- package/package.json +97 -4
- package/src/_shared/index.js +179 -0
- package/src/action/action.js +119 -0
- package/src/action/goTo.js +89 -0
- package/src/action/launch.js +61 -0
- package/src/action/named.js +54 -0
- package/src/action/uri.js +51 -0
- package/src/annot/annot.js +212 -0
- package/src/annot/fileAttach.js +55 -0
- package/src/annot/freeText.js +82 -0
- package/src/annot/ink.js +77 -0
- package/src/annot/link.js +77 -0
- package/src/annot/markup.js +91 -0
- package/src/annot/popup.js +53 -0
- package/src/annot/projection.js +52 -0
- package/src/annot/redact.js +87 -0
- package/src/annot/square.js +132 -0
- package/src/annot/stamp.js +48 -0
- package/src/annot/text.js +54 -0
- package/src/annot/widget.js +61 -0
- package/src/associatedFiles/associatedFiles.js +86 -0
- package/src/bundles/pdf-full.js +91 -0
- package/src/bundles/pdf-large.js +81 -0
- package/src/bundles/pdf-legacy.js +107 -0
- package/src/content/color.js +114 -0
- package/src/content/graphics.js +192 -0
- package/src/content/images.js +160 -0
- package/src/content/ops.js +137 -0
- package/src/content/stream.js +154 -0
- package/src/content/text.js +125 -0
- package/src/crypto/aesGcm.js +123 -0
- package/src/crypto/permissions.js +112 -0
- package/src/crypto/security.js +327 -0
- package/src/crypto/standardV4.js +443 -0
- package/src/crypto/standardV5.js +306 -0
- package/src/crypto/standardV6.js +334 -0
- package/src/destination/destination.js +183 -0
- package/src/document/builder.js +618 -0
- package/src/document/catalog.js +100 -0
- package/src/document/document.js +472 -0
- package/src/document/encryptedWriter.js +554 -0
- package/src/document/incrementalWriter.js +514 -0
- package/src/document/page.js +131 -0
- package/src/document/pages.js +103 -0
- package/src/document/resources.js +146 -0
- package/src/document/writer.js +211 -0
- package/src/document/xrefStreamWriter.js +353 -0
- package/src/embedded/collection.js +102 -0
- package/src/embedded/embeddedFile.js +99 -0
- package/src/embedded/fileSpec.js +137 -0
- package/src/errors.js +78 -0
- package/src/extra/3d-richmedia.js +171 -0
- package/src/extra/annot-extended.js +200 -0
- package/src/extra/associated-files.js +131 -0
- package/src/extra/ccitt-fax-decoder.js +776 -0
- package/src/extra/color-spaces-extended.js +196 -0
- package/src/extra/content-ops-extended.js +153 -0
- package/src/extra/document-parts.js +149 -0
- package/src/extra/embedded-files-portfolio.js +234 -0
- package/src/extra/font-cid-typed.js +185 -0
- package/src/extra/font-color-tagging.js +144 -0
- package/src/extra/form-actions-extended.js +196 -0
- package/src/extra/info-dict-deprecated.js +137 -0
- package/src/extra/jbig2-read.js +169 -0
- package/src/extra/legacy-deprecated-annots.js +198 -0
- package/src/extra/legacy-deprecated-filters.js +167 -0
- package/src/extra/legacy-rc4-read.js +235 -0
- package/src/extra/legacy-xfa-read.js +104 -0
- package/src/extra/linearization-write.js +97 -0
- package/src/extra/misc.js +217 -0
- package/src/extra/optional-content-extended.js +142 -0
- package/src/extra/pdf-a-output-intent.js +112 -0
- package/src/extra/pdf-sandbox.js +88 -0
- package/src/extra/pdf-ua-tagged.js +116 -0
- package/src/extra/pdf-x-prepress.js +114 -0
- package/src/extra/redaction-iso32005.js +136 -0
- package/src/extra/shading-typed.js +222 -0
- package/src/extra/sig-aes-gcm.js +135 -0
- package/src/extra/sig-pades.js +242 -0
- package/src/extra/tagged-pdf-typed.js +203 -0
- package/src/extra/transparency-typed.js +135 -0
- package/src/extra/well-tagged-pdf.js +138 -0
- package/src/extra/xmp-extended.js +190 -0
- package/src/font/embed.js +480 -0
- package/src/font/encoding.js +92 -0
- package/src/font/font.js +101 -0
- package/src/font/type3.js +75 -0
- package/src/form/acroform.js +94 -0
- package/src/form/appearance.js +90 -0
- package/src/form/button.js +105 -0
- package/src/form/choice.js +152 -0
- package/src/form/fieldTree.js +120 -0
- package/src/form/signature.js +100 -0
- package/src/form/text.js +101 -0
- package/src/linearization/linearization.js +107 -0
- package/src/main.js +411 -0
- package/src/metadata/info.js +87 -0
- package/src/metadata/xmp.js +62 -0
- package/src/ocg/config.js +156 -0
- package/src/ocg/ocg.js +124 -0
- package/src/outline/outline.js +157 -0
- package/src/pdf.js +133 -0
- package/src/prepress/outputIntent.js +118 -0
- package/src/prepress/pageBoundary.js +108 -0
- package/src/sig/byteRange.js +306 -0
- package/src/sig/certChain.js +247 -0
- package/src/sig/dss.js +317 -0
- package/src/sig/oids.js +157 -0
- package/src/sig/sha1.js +142 -0
- package/src/sig/sign.js +1899 -0
- package/src/sig/signature.js +1441 -0
- package/src/sig/timestamp.js +236 -0
- package/src/syntax/crossRefStream.js +133 -0
- package/src/syntax/filters/ascii85.js +122 -0
- package/src/syntax/filters/asciiHex.js +83 -0
- package/src/syntax/filters/dispatch.js +176 -0
- package/src/syntax/filters/flate.js +316 -0
- package/src/syntax/filters/runLength.js +96 -0
- package/src/syntax/objStream.js +99 -0
- package/src/syntax/parser-obj.js +52 -0
- package/src/syntax/parser.js +321 -0
- package/src/syntax/serializer.js +221 -0
- package/src/syntax/tokenizer.js +290 -0
- package/src/syntax/trailer.js +76 -0
- package/src/syntax/xref.js +341 -0
- package/src/tagged/classMap.js +81 -0
- package/src/tagged/markedContent.js +123 -0
- package/src/tagged/parentTree.js +126 -0
- package/src/tagged/roleMap.js +107 -0
- package/src/tagged/structElement.js +138 -0
- package/src/tagged/structTree.js +94 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// Copyright (c) 2026 AwaCloud SAS
|
|
2
|
+
// Author: Matthieu Bouilloux
|
|
3
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
4
|
+
// Dual-licensed; see the NOTICE file for licensing and any additional terms.
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @fileoverview Output Intent typing per ISO 32000-2:2020 §14.11.5.
|
|
8
|
+
*
|
|
9
|
+
* Each entry in the Catalog's `/OutputIntents` array is a dictionary
|
|
10
|
+
* `/Type /OutputIntent` describing the colour environment the document
|
|
11
|
+
* was prepared for. Entries:
|
|
12
|
+
* /S — subtype: GTS_PDFA1, GTS_PDFX, ISO_PDFE1, …
|
|
13
|
+
* /OutputCondition — human-readable description.
|
|
14
|
+
* /OutputConditionIdentifier — registry identifier.
|
|
15
|
+
* /RegistryName — URL of registry.
|
|
16
|
+
* /Info — additional textual info.
|
|
17
|
+
* /DestOutputProfile — ICC profile stream (ref).
|
|
18
|
+
* /DestOutputProfileRef — PDF 2.0 indirect URI to ICC.
|
|
19
|
+
* /MixingHints — dict (mixing hints).
|
|
20
|
+
* /SpectralData — dict (spectral data).
|
|
21
|
+
*
|
|
22
|
+
* @module pdf/prepress/outputIntent
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Module factory.
|
|
27
|
+
*/
|
|
28
|
+
import { pdfErrors } from '../errors.js';
|
|
29
|
+
import { pdfParser } from '../syntax/parser.js';
|
|
30
|
+
|
|
31
|
+
export const pdfOutputIntent = {
|
|
32
|
+
name: 'pdfOutputIntent',
|
|
33
|
+
dependencies: ['pdfErrors', 'pdfParser'],
|
|
34
|
+
deps: [pdfErrors, pdfParser],
|
|
35
|
+
factory(errors, parser) {
|
|
36
|
+
const { ParseError } = errors;
|
|
37
|
+
const { isType } = parser;
|
|
38
|
+
|
|
39
|
+
const KNOWN = new Set([
|
|
40
|
+
'Type', 'S', 'OutputCondition', 'OutputConditionIdentifier',
|
|
41
|
+
'RegistryName', 'Info', 'DestOutputProfile', 'DestOutputProfileRef',
|
|
42
|
+
'MixingHints', 'SpectralData'
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
function lower(s) { return s.charAt(0).toLowerCase() + s.slice(1); }
|
|
46
|
+
|
|
47
|
+
function typeOutputIntent(dict) {
|
|
48
|
+
if (!isType(dict, 'dict')) {
|
|
49
|
+
throw new ParseError('pdf/output-intent/not-dict',
|
|
50
|
+
'OutputIntent must be a dictionary',
|
|
51
|
+
{ context: { type: dict && dict.type } });
|
|
52
|
+
}
|
|
53
|
+
const e = dict.entries;
|
|
54
|
+
if (e.Type && (e.Type.type !== 'name' || e.Type.value !== 'OutputIntent')) {
|
|
55
|
+
throw new ParseError('pdf/output-intent/bad-type',
|
|
56
|
+
'/Type must be /OutputIntent',
|
|
57
|
+
{ context: { actual: e.Type.value } });
|
|
58
|
+
}
|
|
59
|
+
if (!e.S || e.S.type !== 'name') {
|
|
60
|
+
throw new ParseError('pdf/output-intent/missing-s',
|
|
61
|
+
'OutputIntent missing /S subtype name',
|
|
62
|
+
{ context: { type: e.S && e.S.type } });
|
|
63
|
+
}
|
|
64
|
+
const out = { subtype: e.S.value, raw: dict, _extras: {} };
|
|
65
|
+
|
|
66
|
+
for (const k of ['OutputCondition', 'OutputConditionIdentifier',
|
|
67
|
+
'RegistryName', 'Info']) {
|
|
68
|
+
if (e[k] !== undefined) {
|
|
69
|
+
if (e[k].type !== 'string') {
|
|
70
|
+
throw new ParseError('pdf/output-intent/bad-str',
|
|
71
|
+
'/' + k + ' must be a string',
|
|
72
|
+
{ context: { key: k, type: e[k].type } });
|
|
73
|
+
}
|
|
74
|
+
out[lower(k)] = e[k].value;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (e.DestOutputProfile) {
|
|
78
|
+
if (e.DestOutputProfile.type !== 'ref' && e.DestOutputProfile.type !== 'stream') {
|
|
79
|
+
throw new ParseError('pdf/output-intent/bad-profile',
|
|
80
|
+
'/DestOutputProfile must be a ref or stream',
|
|
81
|
+
{ context: { type: e.DestOutputProfile.type } });
|
|
82
|
+
}
|
|
83
|
+
out.destOutputProfile = e.DestOutputProfile;
|
|
84
|
+
}
|
|
85
|
+
if (e.DestOutputProfileRef) {
|
|
86
|
+
if (e.DestOutputProfileRef.type !== 'dict' && e.DestOutputProfileRef.type !== 'ref') {
|
|
87
|
+
throw new ParseError('pdf/output-intent/bad-profile-ref',
|
|
88
|
+
'/DestOutputProfileRef must be a dict or ref',
|
|
89
|
+
{ context: { type: e.DestOutputProfileRef.type } });
|
|
90
|
+
}
|
|
91
|
+
out.destOutputProfileRef = e.DestOutputProfileRef;
|
|
92
|
+
}
|
|
93
|
+
if (e.MixingHints) {
|
|
94
|
+
if (e.MixingHints.type !== 'dict') {
|
|
95
|
+
throw new ParseError('pdf/output-intent/bad-mixing',
|
|
96
|
+
'/MixingHints must be a dictionary',
|
|
97
|
+
{ context: { type: e.MixingHints.type } });
|
|
98
|
+
}
|
|
99
|
+
out.mixingHints = e.MixingHints;
|
|
100
|
+
}
|
|
101
|
+
if (e.SpectralData) {
|
|
102
|
+
if (e.SpectralData.type !== 'dict') {
|
|
103
|
+
throw new ParseError('pdf/output-intent/bad-spectral',
|
|
104
|
+
'/SpectralData must be a dictionary',
|
|
105
|
+
{ context: { type: e.SpectralData.type } });
|
|
106
|
+
}
|
|
107
|
+
out.spectralData = e.SpectralData;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
for (const k of Object.keys(e)) {
|
|
111
|
+
if (!KNOWN.has(k)) out._extras[k] = e[k];
|
|
112
|
+
}
|
|
113
|
+
return out;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return { typeOutputIntent };
|
|
117
|
+
}
|
|
118
|
+
};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// Copyright (c) 2026 AwaCloud SAS
|
|
2
|
+
// Author: Matthieu Bouilloux
|
|
3
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
4
|
+
// Dual-licensed; see the NOTICE file for licensing and any additional terms.
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @fileoverview Page boundary helpers per ISO 32000-2:2020 §14.11.2.
|
|
8
|
+
*
|
|
9
|
+
* Each Page may declare four optional boundary rectangles —
|
|
10
|
+
* `/CropBox`, `/TrimBox`, `/BleedBox`, `/ArtBox` — each defaulting to
|
|
11
|
+
* `/MediaBox` (which is mandatory on every page) when absent. These
|
|
12
|
+
* helpers resolve the effective rectangle following the spec's
|
|
13
|
+
* inheritance rules:
|
|
14
|
+
* - MediaBox itself is inheritable from ancestor /Pages nodes (already
|
|
15
|
+
* handled at L2 by the page-typing layer; we expect callers to pass
|
|
16
|
+
* a Page record carrying its effective `/MediaBox`).
|
|
17
|
+
* - CropBox defaults to MediaBox; Trim/Bleed/ArtBox default to
|
|
18
|
+
* CropBox.
|
|
19
|
+
*
|
|
20
|
+
* The input is the *typed* page record returned by the page typer,
|
|
21
|
+
* carrying `{ mediaBox, cropBox?, trimBox?, bleedBox?, artBox? }` —
|
|
22
|
+
* each a `[llx, lly, urx, ury]` array of numbers. To stay loosely
|
|
23
|
+
* coupled we also accept raw dict-shape objects with `entries.MediaBox`
|
|
24
|
+
* etc.
|
|
25
|
+
*
|
|
26
|
+
* @module pdf/prepress/pageBoundary
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Module factory.
|
|
31
|
+
*/
|
|
32
|
+
import { pdfErrors } from '../errors.js';
|
|
33
|
+
import { pdfParser } from '../syntax/parser.js';
|
|
34
|
+
|
|
35
|
+
export const pdfPageBoundary = {
|
|
36
|
+
name: 'pdfPageBoundary',
|
|
37
|
+
dependencies: ['pdfErrors', 'pdfParser'],
|
|
38
|
+
deps: [pdfErrors, pdfParser],
|
|
39
|
+
factory(errors, _p) {
|
|
40
|
+
const { ParseError } = errors;
|
|
41
|
+
|
|
42
|
+
const KEYS = {
|
|
43
|
+
mediaBox: 'MediaBox',
|
|
44
|
+
cropBox: 'CropBox',
|
|
45
|
+
trimBox: 'TrimBox',
|
|
46
|
+
bleedBox: 'BleedBox',
|
|
47
|
+
artBox: 'ArtBox'
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
function readBox(page, normKey) {
|
|
51
|
+
if (!page) return undefined;
|
|
52
|
+
if (page[normKey] !== undefined) return page[normKey];
|
|
53
|
+
// Raw dict shape.
|
|
54
|
+
const k = KEYS[normKey];
|
|
55
|
+
const dict = page.entries ? page : page.raw;
|
|
56
|
+
if (dict && dict.entries && dict.entries[k]) {
|
|
57
|
+
const arr = dict.entries[k];
|
|
58
|
+
if (arr.type !== 'array' || arr.items.length !== 4) {
|
|
59
|
+
throw new ParseError('pdf/page-boundary/bad-box',
|
|
60
|
+
'/' + k + ' must be a 4-element array',
|
|
61
|
+
{ context: { key: k } });
|
|
62
|
+
}
|
|
63
|
+
return arr.items.map((x) => {
|
|
64
|
+
if (x.type !== 'int' && x.type !== 'real') {
|
|
65
|
+
throw new ParseError('pdf/page-boundary/bad-box-element',
|
|
66
|
+
'/' + k + ' elements must be numbers',
|
|
67
|
+
{ context: { key: k, type: x.type } });
|
|
68
|
+
}
|
|
69
|
+
return x.value;
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function effectiveMediaBox(page) {
|
|
76
|
+
const v = readBox(page, 'mediaBox');
|
|
77
|
+
if (!v) {
|
|
78
|
+
throw new ParseError('pdf/page-boundary/no-mediabox',
|
|
79
|
+
'page has no /MediaBox');
|
|
80
|
+
}
|
|
81
|
+
return v;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function effectiveCropBox(page) {
|
|
85
|
+
return readBox(page, 'cropBox') || effectiveMediaBox(page);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function effectiveTrimBox(page) {
|
|
89
|
+
return readBox(page, 'trimBox') || effectiveCropBox(page);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function effectiveBleedBox(page) {
|
|
93
|
+
return readBox(page, 'bleedBox') || effectiveCropBox(page);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function effectiveArtBox(page) {
|
|
97
|
+
return readBox(page, 'artBox') || effectiveCropBox(page);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
effectiveMediaBox,
|
|
102
|
+
effectiveCropBox,
|
|
103
|
+
effectiveTrimBox,
|
|
104
|
+
effectiveBleedBox,
|
|
105
|
+
effectiveArtBox
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
};
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
// Copyright (c) 2026 AwaCloud SAS
|
|
2
|
+
// Author: Matthieu Bouilloux
|
|
3
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
4
|
+
// Dual-licensed; see the NOTICE file for licensing and any additional terms.
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @fileoverview ByteRange computation around a signature's `/Contents`
|
|
8
|
+
* hex string.
|
|
9
|
+
*
|
|
10
|
+
* ISO 32000-2:2020 §12.8.1 — a signature dictionary's `/ByteRange` is
|
|
11
|
+
* an array `[a b c d]` of four integers selecting the two byte ranges
|
|
12
|
+
* `[a, a+b)` and `[c, c+d)` of the document. The gap `[a+b, c)` between
|
|
13
|
+
* them holds the `/Contents` value, the PKCS#7 / CMS blob; its bytes are
|
|
14
|
+
* excluded from the signature digest — otherwise the digest would have
|
|
15
|
+
* to depend on its own value.
|
|
16
|
+
*
|
|
17
|
+
* Gap forms. ISO 32000-2 §12.8.3.3.1 requires the `/Contents`
|
|
18
|
+
* hex string, "with "<" and ">" delimiters", to "fit precisely in the
|
|
19
|
+
* space between the ranges": the gap is the whole `<…>` token — form
|
|
20
|
+
* (b), `gapForm: 'token'`, what `pdfSign` emits and what PDFBox and
|
|
21
|
+
* pyHanko emit and check. Signatures earlier `pdfSign` releases
|
|
22
|
+
* produced left out the hex digits only — form (a), `gapForm: 'digits'`.
|
|
23
|
+
* `auditByteRange` accepts exactly these two gaps.
|
|
24
|
+
*
|
|
25
|
+
* @module pdf/sig/byteRange
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Module factory.
|
|
30
|
+
*/
|
|
31
|
+
import { pdfErrors } from '../errors.js';
|
|
32
|
+
|
|
33
|
+
export const pdfByteRange = {
|
|
34
|
+
name: 'pdfByteRange',
|
|
35
|
+
dependencies: ['pdfErrors'],
|
|
36
|
+
deps: [pdfErrors],
|
|
37
|
+
factory(errors) {
|
|
38
|
+
const { ParseError } = errors;
|
|
39
|
+
|
|
40
|
+
const CONTENTS_KEY = new Uint8Array([
|
|
41
|
+
0x2F, 0x43, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x73 // /Contents
|
|
42
|
+
]);
|
|
43
|
+
const ENDOBJ = new Uint8Array([0x65, 0x6E, 0x64, 0x6F, 0x62, 0x6A]);
|
|
44
|
+
|
|
45
|
+
function _indexOfBytes(haystack, needle, from, to) {
|
|
46
|
+
const n = needle.length;
|
|
47
|
+
const limit = to - n;
|
|
48
|
+
outer: for (let i = from; i <= limit; i++) {
|
|
49
|
+
for (let k = 0; k < n; k++) {
|
|
50
|
+
if (haystack[i + k] !== needle[k]) continue outer;
|
|
51
|
+
}
|
|
52
|
+
return i;
|
|
53
|
+
}
|
|
54
|
+
return -1;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function _findEndobj(bytes, from) {
|
|
58
|
+
const at = _indexOfBytes(bytes, ENDOBJ, from, bytes.length);
|
|
59
|
+
return at < 0 ? bytes.length : at;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function _isWhitespace(b) {
|
|
63
|
+
return b === 0x00 || b === 0x09 || b === 0x0A || b === 0x0C
|
|
64
|
+
|| b === 0x0D || b === 0x20;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* `[0, gapStart, gapEnd, total - gapEnd]` around a `/Contents` value.
|
|
69
|
+
*
|
|
70
|
+
* Without `opts` the gap is `[contentsOffset, contentsOffset +
|
|
71
|
+
* contentsLength)` — whatever span the caller passes (historically
|
|
72
|
+
* the hex digits, form a). With `opts.token` the gap is that token
|
|
73
|
+
* span instead (form b): it must enclose the digit span by exactly
|
|
74
|
+
* one byte on each side, and those two bytes must be `<` and `>`.
|
|
75
|
+
*
|
|
76
|
+
* @throws {ParseError} `pdf/sig/byterange/bad-input`, `bad-offset`,
|
|
77
|
+
* `bad-length`, `overflow`; `bad-token` when `opts.token` is not
|
|
78
|
+
* the `<…>` token around the digit span.
|
|
79
|
+
*/
|
|
80
|
+
function computeByteRange(documentBytes, contentsOffset, contentsLength, opts) {
|
|
81
|
+
if (!(documentBytes instanceof Uint8Array)) {
|
|
82
|
+
throw new ParseError('pdf/sig/byterange/bad-input',
|
|
83
|
+
'documentBytes must be a Uint8Array');
|
|
84
|
+
}
|
|
85
|
+
const total = documentBytes.length;
|
|
86
|
+
if (!Number.isInteger(contentsOffset) || contentsOffset < 0
|
|
87
|
+
|| contentsOffset > total) {
|
|
88
|
+
throw new ParseError('pdf/sig/byterange/bad-offset',
|
|
89
|
+
'contentsOffset out of range',
|
|
90
|
+
{ context: { contentsOffset, total } });
|
|
91
|
+
}
|
|
92
|
+
if (!Number.isInteger(contentsLength) || contentsLength < 0) {
|
|
93
|
+
throw new ParseError('pdf/sig/byterange/bad-length',
|
|
94
|
+
'contentsLength must be a non-negative integer',
|
|
95
|
+
{ context: { contentsLength } });
|
|
96
|
+
}
|
|
97
|
+
const end = contentsOffset + contentsLength;
|
|
98
|
+
if (end > total) {
|
|
99
|
+
throw new ParseError('pdf/sig/byterange/overflow',
|
|
100
|
+
'/Contents extends past end of document',
|
|
101
|
+
{ context: { end, total } });
|
|
102
|
+
}
|
|
103
|
+
if (opts && opts.token) {
|
|
104
|
+
const tOff = opts.token.offset;
|
|
105
|
+
const tLen = opts.token.length;
|
|
106
|
+
const tEnd = tOff + tLen;
|
|
107
|
+
if (!Number.isInteger(tOff) || !Number.isInteger(tLen)
|
|
108
|
+
|| tOff !== contentsOffset - 1 || tEnd !== end + 1
|
|
109
|
+
|| tOff < 0 || tEnd > total
|
|
110
|
+
|| documentBytes[tOff] !== 0x3C // '<'
|
|
111
|
+
|| documentBytes[tEnd - 1] !== 0x3E) { // '>'
|
|
112
|
+
throw new ParseError('pdf/sig/byterange/bad-token',
|
|
113
|
+
'token span must be the "<…>" token enclosing the '
|
|
114
|
+
+ '/Contents hex digits',
|
|
115
|
+
{ context: { token: { offset: tOff, length: tLen },
|
|
116
|
+
contentsOffset, contentsLength } });
|
|
117
|
+
}
|
|
118
|
+
return [0, tOff, tEnd, total - tEnd];
|
|
119
|
+
}
|
|
120
|
+
return [0, contentsOffset, end, total - end];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function extractSignedBytes(documentBytes, byteRange) {
|
|
124
|
+
if (!(documentBytes instanceof Uint8Array)) {
|
|
125
|
+
throw new ParseError('pdf/sig/byterange/bad-input',
|
|
126
|
+
'documentBytes must be a Uint8Array');
|
|
127
|
+
}
|
|
128
|
+
if (!byteRange || byteRange.length !== 4) {
|
|
129
|
+
throw new ParseError('pdf/sig/byterange/bad-shape',
|
|
130
|
+
'byteRange must have 4 entries',
|
|
131
|
+
{ context: { length: byteRange && byteRange.length } });
|
|
132
|
+
}
|
|
133
|
+
const a = byteRange[0] | 0;
|
|
134
|
+
const b = byteRange[1] | 0;
|
|
135
|
+
const c = byteRange[2] | 0;
|
|
136
|
+
const d = byteRange[3] | 0;
|
|
137
|
+
if (a < 0 || b < 0 || c < 0 || d < 0
|
|
138
|
+
|| a + b > documentBytes.length
|
|
139
|
+
|| c + d > documentBytes.length
|
|
140
|
+
|| c < a + b) {
|
|
141
|
+
throw new ParseError('pdf/sig/byterange/inconsistent',
|
|
142
|
+
'byteRange entries inconsistent with documentBytes',
|
|
143
|
+
{ context: { a, b, c, d, total: documentBytes.length } });
|
|
144
|
+
}
|
|
145
|
+
const out = new Uint8Array(b + d);
|
|
146
|
+
out.set(documentBytes.subarray(a, a + b), 0);
|
|
147
|
+
out.set(documentBytes.subarray(c, c + d), b);
|
|
148
|
+
return out;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Non-throwing `/ByteRange` audit.
|
|
153
|
+
*
|
|
154
|
+
* With `opts.contents` (the hex-digit span `findContentsField`
|
|
155
|
+
* returns), the gap must be exactly the `<…>` token (form b) or
|
|
156
|
+
* exactly the digits (form a); any other gap yields
|
|
157
|
+
* `gap-start-mismatch` / `gap-end-mismatch`, measured against the
|
|
158
|
+
* token bounds. `gapForm` names the accepted form: `'token'`,
|
|
159
|
+
* `'digits'`, or `null` (no `opts.contents`, or neither form).
|
|
160
|
+
*
|
|
161
|
+
* @returns {{ok: boolean, issues: Array<{code: string, message: string,
|
|
162
|
+
* context: object}>, gapForm: ('token'|'digits'|null)}}
|
|
163
|
+
* @throws {ParseError} `pdf/sig/byterange/bad-input`, `bad-shape`.
|
|
164
|
+
*/
|
|
165
|
+
function auditByteRange(documentBytes, byteRange, opts) {
|
|
166
|
+
if (!(documentBytes instanceof Uint8Array)) {
|
|
167
|
+
throw new ParseError('pdf/sig/byterange/bad-input',
|
|
168
|
+
'documentBytes must be a Uint8Array');
|
|
169
|
+
}
|
|
170
|
+
if (!byteRange || byteRange.length !== 4) {
|
|
171
|
+
throw new ParseError('pdf/sig/byterange/bad-shape',
|
|
172
|
+
'byteRange must have 4 entries',
|
|
173
|
+
{ context: { length: byteRange && byteRange.length } });
|
|
174
|
+
}
|
|
175
|
+
const issues = [];
|
|
176
|
+
const a = byteRange[0] | 0;
|
|
177
|
+
const b = byteRange[1] | 0;
|
|
178
|
+
const c = byteRange[2] | 0;
|
|
179
|
+
const d = byteRange[3] | 0;
|
|
180
|
+
const total = documentBytes.length;
|
|
181
|
+
if (a !== 0) {
|
|
182
|
+
issues.push({
|
|
183
|
+
code: 'pdf/sig/byterange/non-zero-start',
|
|
184
|
+
message: 'first range does not start at offset 0',
|
|
185
|
+
context: { a }
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
if (c < a + b) {
|
|
189
|
+
issues.push({
|
|
190
|
+
code: 'pdf/sig/byterange/self-overlap',
|
|
191
|
+
message: 'second range starts before first range ends',
|
|
192
|
+
context: { firstEnd: a + b, secondStart: c }
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
if (a + b > total || c + d > total) {
|
|
196
|
+
issues.push({
|
|
197
|
+
code: 'pdf/sig/byterange/out-of-bounds',
|
|
198
|
+
message: 'range extends past document end',
|
|
199
|
+
context: { firstEnd: a + b, secondEnd: c + d, total }
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
let gapForm = null;
|
|
203
|
+
if (opts && opts.contents) {
|
|
204
|
+
const cOff = opts.contents.offset | 0;
|
|
205
|
+
const cLen = opts.contents.length | 0;
|
|
206
|
+
// Form (b): the whole `<…>` token. Form (a): the digits.
|
|
207
|
+
const expectedGapStart = cOff - 1;
|
|
208
|
+
const expectedGapEnd = cOff + cLen + 1;
|
|
209
|
+
if (a + b === expectedGapStart && c === expectedGapEnd) {
|
|
210
|
+
gapForm = 'token';
|
|
211
|
+
} else if (a + b === cOff && c === cOff + cLen) {
|
|
212
|
+
gapForm = 'digits';
|
|
213
|
+
}
|
|
214
|
+
// Any other gap is refused, measured against form (b).
|
|
215
|
+
if (gapForm === null && a + b !== expectedGapStart) {
|
|
216
|
+
issues.push({
|
|
217
|
+
code: 'pdf/sig/byterange/gap-start-mismatch',
|
|
218
|
+
message: 'first range end does not align with /Contents '
|
|
219
|
+
+ 'literal start',
|
|
220
|
+
context: { firstEnd: a + b, expected: expectedGapStart }
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
if (gapForm === null && c !== expectedGapEnd) {
|
|
224
|
+
issues.push({
|
|
225
|
+
code: 'pdf/sig/byterange/gap-end-mismatch',
|
|
226
|
+
message: 'second range start does not align with /Contents '
|
|
227
|
+
+ 'literal end',
|
|
228
|
+
context: { secondStart: c, expected: expectedGapEnd }
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (opts && Array.isArray(opts.others)) {
|
|
233
|
+
for (let i = 0; i < opts.others.length; i++) {
|
|
234
|
+
const other = opts.others[i];
|
|
235
|
+
if (!other || other.length !== 4) continue;
|
|
236
|
+
const r1 = [[a, a + b], [c, c + d]];
|
|
237
|
+
const oa = other[0] | 0, ob = other[1] | 0;
|
|
238
|
+
const oc = other[2] | 0, od = other[3] | 0;
|
|
239
|
+
const r2 = [[oa, oa + ob], [oc, oc + od]];
|
|
240
|
+
for (const s of r1) {
|
|
241
|
+
for (const t of r2) {
|
|
242
|
+
if (s[0] < t[1] && t[0] < s[1]) {
|
|
243
|
+
issues.push({
|
|
244
|
+
code: 'pdf/sig/byterange/cross-overlap',
|
|
245
|
+
message: 'byteRange overlaps with another '
|
|
246
|
+
+ 'signature ByteRange',
|
|
247
|
+
context: { thisRange: s, otherRange: t,
|
|
248
|
+
otherIndex: i }
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (opts && opts.requireFullCoverage && c + d !== total) {
|
|
256
|
+
issues.push({
|
|
257
|
+
code: 'pdf/sig/byterange/incomplete-coverage',
|
|
258
|
+
message: 'byteRange does not cover the document up to its end',
|
|
259
|
+
context: { secondEnd: c + d, total }
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
return { ok: issues.length === 0, issues, gapForm };
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function findContentsField(documentBytes, sigObjectOffset) {
|
|
266
|
+
if (!(documentBytes instanceof Uint8Array)) {
|
|
267
|
+
throw new ParseError('pdf/sig/byterange/bad-input',
|
|
268
|
+
'documentBytes must be a Uint8Array');
|
|
269
|
+
}
|
|
270
|
+
if (!Number.isInteger(sigObjectOffset) || sigObjectOffset < 0
|
|
271
|
+
|| sigObjectOffset >= documentBytes.length) {
|
|
272
|
+
throw new ParseError('pdf/sig/byterange/bad-offset',
|
|
273
|
+
'sigObjectOffset out of range');
|
|
274
|
+
}
|
|
275
|
+
const stop = _findEndobj(documentBytes, sigObjectOffset);
|
|
276
|
+
const keyAt = _indexOfBytes(documentBytes, CONTENTS_KEY,
|
|
277
|
+
sigObjectOffset, stop);
|
|
278
|
+
if (keyAt < 0) {
|
|
279
|
+
throw new ParseError('pdf/sig/byterange/no-contents',
|
|
280
|
+
'/Contents key not found in signature object',
|
|
281
|
+
{ context: { sigObjectOffset } });
|
|
282
|
+
}
|
|
283
|
+
let p = keyAt + CONTENTS_KEY.length;
|
|
284
|
+
while (p < stop && _isWhitespace(documentBytes[p])) p++;
|
|
285
|
+
if (p >= stop || documentBytes[p] !== 0x3C) { // '<'
|
|
286
|
+
throw new ParseError('pdf/sig/byterange/contents-not-hex',
|
|
287
|
+
'/Contents must be a hex literal');
|
|
288
|
+
}
|
|
289
|
+
const start = p + 1;
|
|
290
|
+
let end = start;
|
|
291
|
+
while (end < stop && documentBytes[end] !== 0x3E) end++; // '>'
|
|
292
|
+
if (end >= stop) {
|
|
293
|
+
throw new ParseError('pdf/sig/byterange/contents-unterminated',
|
|
294
|
+
'/Contents hex literal not terminated before endobj');
|
|
295
|
+
}
|
|
296
|
+
return { offset: start, length: end - start };
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return {
|
|
300
|
+
computeByteRange,
|
|
301
|
+
extractSignedBytes,
|
|
302
|
+
findContentsField,
|
|
303
|
+
auditByteRange
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
};
|