pdf-lite 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/.commitlintrc.cjs +25 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +19 -0
- package/.github/workflows/docs.yaml +93 -0
- package/.github/workflows/prepare-release.yaml +79 -0
- package/.github/workflows/release.yaml +80 -0
- package/.github/workflows/test.yaml +35 -0
- package/.husky/commit-msg +1 -0
- package/.husky/pre-commit +1 -0
- package/.prettierignore +4 -0
- package/.prettierrc +4 -0
- package/CONTRIBUTING.md +109 -0
- package/EXAMPLES.md +1515 -0
- package/LICENSE +21 -0
- package/README.md +285 -0
- package/examples/001-create-pdf.ts +112 -0
- package/examples/002-create-encrypted-pdf.ts +121 -0
- package/examples/003-sign-pdf.ts +347 -0
- package/examples/004-incremental-update.ts +206 -0
- package/examples/005-modify-acroform.ts +374 -0
- package/examples/006-tokeniser-example.ts +131 -0
- package/examples/007-decoder-example.ts +197 -0
- package/package.json +72 -0
- package/packages/pdf-lite/README.md +3 -0
- package/packages/pdf-lite/package.json +68 -0
- package/packages/pdf-lite/scripts/create-encryption-tests.sh +41 -0
- package/packages/pdf-lite/scripts/gen-signing-keys.sh +290 -0
- package/packages/pdf-lite/scripts/generate-all-signing-keys.sh +70 -0
- package/packages/pdf-lite/src/core/decoder.ts +454 -0
- package/packages/pdf-lite/src/core/generators.ts +128 -0
- package/packages/pdf-lite/src/core/incremental-parser.ts +221 -0
- package/packages/pdf-lite/src/core/index.ts +2 -0
- package/packages/pdf-lite/src/core/objects/pdf-array.ts +54 -0
- package/packages/pdf-lite/src/core/objects/pdf-boolean.ts +19 -0
- package/packages/pdf-lite/src/core/objects/pdf-comment.ts +50 -0
- package/packages/pdf-lite/src/core/objects/pdf-date.ts +74 -0
- package/packages/pdf-lite/src/core/objects/pdf-dictionary.ts +171 -0
- package/packages/pdf-lite/src/core/objects/pdf-hexadecimal.ts +54 -0
- package/packages/pdf-lite/src/core/objects/pdf-indirect-object.ts +137 -0
- package/packages/pdf-lite/src/core/objects/pdf-name.ts +19 -0
- package/packages/pdf-lite/src/core/objects/pdf-null.ts +15 -0
- package/packages/pdf-lite/src/core/objects/pdf-number.ts +98 -0
- package/packages/pdf-lite/src/core/objects/pdf-object-reference.ts +30 -0
- package/packages/pdf-lite/src/core/objects/pdf-object.ts +107 -0
- package/packages/pdf-lite/src/core/objects/pdf-start-xref.ts +39 -0
- package/packages/pdf-lite/src/core/objects/pdf-stream.ts +687 -0
- package/packages/pdf-lite/src/core/objects/pdf-string.ts +38 -0
- package/packages/pdf-lite/src/core/objects/pdf-trailer.ts +57 -0
- package/packages/pdf-lite/src/core/objects/pdf-xref-table.ts +264 -0
- package/packages/pdf-lite/src/core/parser.ts +22 -0
- package/packages/pdf-lite/src/core/ref.ts +102 -0
- package/packages/pdf-lite/src/core/serializer.ts +68 -0
- package/packages/pdf-lite/src/core/streams/object-stream.ts +20 -0
- package/packages/pdf-lite/src/core/tokeniser.ts +687 -0
- package/packages/pdf-lite/src/core/tokens/boolean-token.ts +20 -0
- package/packages/pdf-lite/src/core/tokens/byte-offset-token.ts +20 -0
- package/packages/pdf-lite/src/core/tokens/comment-token.ts +32 -0
- package/packages/pdf-lite/src/core/tokens/end-array-token.ts +10 -0
- package/packages/pdf-lite/src/core/tokens/end-dictionary-token.ts +10 -0
- package/packages/pdf-lite/src/core/tokens/end-object-token.ts +10 -0
- package/packages/pdf-lite/src/core/tokens/end-stream-token.ts +11 -0
- package/packages/pdf-lite/src/core/tokens/hexadecimal-token.ts +22 -0
- package/packages/pdf-lite/src/core/tokens/name-token.ts +19 -0
- package/packages/pdf-lite/src/core/tokens/null-token.ts +9 -0
- package/packages/pdf-lite/src/core/tokens/number-token.ts +164 -0
- package/packages/pdf-lite/src/core/tokens/object-reference-token.ts +24 -0
- package/packages/pdf-lite/src/core/tokens/start-array-token.ts +10 -0
- package/packages/pdf-lite/src/core/tokens/start-dictionary-token.ts +10 -0
- package/packages/pdf-lite/src/core/tokens/start-object-token.ts +28 -0
- package/packages/pdf-lite/src/core/tokens/start-stream-token.ts +52 -0
- package/packages/pdf-lite/src/core/tokens/start-xref-token.ts +10 -0
- package/packages/pdf-lite/src/core/tokens/stream-chunk-token.ts +8 -0
- package/packages/pdf-lite/src/core/tokens/string-token.ts +17 -0
- package/packages/pdf-lite/src/core/tokens/token.ts +43 -0
- package/packages/pdf-lite/src/core/tokens/trailer-token.ts +12 -0
- package/packages/pdf-lite/src/core/tokens/whitespace-token.ts +43 -0
- package/packages/pdf-lite/src/core/tokens/xref-table-entry-token.ts +65 -0
- package/packages/pdf-lite/src/core/tokens/xref-table-section-start-token.ts +31 -0
- package/packages/pdf-lite/src/core/tokens/xref-table-start-token.ts +13 -0
- package/packages/pdf-lite/src/crypto/ciphers/aes128.ts +63 -0
- package/packages/pdf-lite/src/crypto/ciphers/aes256.ts +50 -0
- package/packages/pdf-lite/src/crypto/ciphers/rc4.ts +82 -0
- package/packages/pdf-lite/src/crypto/constants.ts +10 -0
- package/packages/pdf-lite/src/crypto/key-derivation/key-derivation-aes256.ts +213 -0
- package/packages/pdf-lite/src/crypto/key-derivation/key-derivation.ts +122 -0
- package/packages/pdf-lite/src/crypto/key-gen/key-gen-aes256.ts +79 -0
- package/packages/pdf-lite/src/crypto/key-gen/key-gen-rc4-128.ts +190 -0
- package/packages/pdf-lite/src/crypto/key-gen/key-gen-rc4-40.ts +129 -0
- package/packages/pdf-lite/src/crypto/types.ts +6 -0
- package/packages/pdf-lite/src/crypto/utils.ts +81 -0
- package/packages/pdf-lite/src/filters/ascii85.ts +128 -0
- package/packages/pdf-lite/src/filters/asciihex.ts +55 -0
- package/packages/pdf-lite/src/filters/flate.ts +39 -0
- package/packages/pdf-lite/src/filters/lzw.ts +144 -0
- package/packages/pdf-lite/src/filters/pass-through.ts +37 -0
- package/packages/pdf-lite/src/filters/runlength.ts +92 -0
- package/packages/pdf-lite/src/filters/types.ts +21 -0
- package/packages/pdf-lite/src/index.ts +4 -0
- package/packages/pdf-lite/src/pdf/errors.ts +5 -0
- package/packages/pdf-lite/src/pdf/index.ts +4 -0
- package/packages/pdf-lite/src/pdf/pdf-document.ts +924 -0
- package/packages/pdf-lite/src/pdf/pdf-reader.ts +57 -0
- package/packages/pdf-lite/src/pdf/pdf-revision.ts +234 -0
- package/packages/pdf-lite/src/pdf/pdf-xref-lookup.ts +527 -0
- package/packages/pdf-lite/src/security/crypt-filters/aesv2.ts +58 -0
- package/packages/pdf-lite/src/security/crypt-filters/aesv3.ts +56 -0
- package/packages/pdf-lite/src/security/crypt-filters/base.ts +140 -0
- package/packages/pdf-lite/src/security/crypt-filters/identity.ts +40 -0
- package/packages/pdf-lite/src/security/crypt-filters/v2.ts +59 -0
- package/packages/pdf-lite/src/security/handlers/base.ts +625 -0
- package/packages/pdf-lite/src/security/handlers/pubSec.ts +413 -0
- package/packages/pdf-lite/src/security/handlers/utils.ts +304 -0
- package/packages/pdf-lite/src/security/handlers/v1.ts +225 -0
- package/packages/pdf-lite/src/security/handlers/v2.ts +128 -0
- package/packages/pdf-lite/src/security/handlers/v4.ts +379 -0
- package/packages/pdf-lite/src/security/handlers/v5.ts +298 -0
- package/packages/pdf-lite/src/security/types.ts +158 -0
- package/packages/pdf-lite/src/signing/document-security-store.ts +224 -0
- package/packages/pdf-lite/src/signing/index.ts +3 -0
- package/packages/pdf-lite/src/signing/signatures/adbe-pkcs7-detached.ts +154 -0
- package/packages/pdf-lite/src/signing/signatures/adbe-pkcs7-sha1.ts +161 -0
- package/packages/pdf-lite/src/signing/signatures/adbe-x509-rsa-sha1.ts +106 -0
- package/packages/pdf-lite/src/signing/signatures/base.ts +229 -0
- package/packages/pdf-lite/src/signing/signatures/etsi-cades-detached.ts +229 -0
- package/packages/pdf-lite/src/signing/signatures/etsi-rfc3161.ts +92 -0
- package/packages/pdf-lite/src/signing/signatures/index.ts +6 -0
- package/packages/pdf-lite/src/signing/signer.ts +120 -0
- package/packages/pdf-lite/src/signing/types.ts +86 -0
- package/packages/pdf-lite/src/signing/utils.ts +71 -0
- package/packages/pdf-lite/src/types.ts +44 -0
- package/packages/pdf-lite/src/utils/IterableReadableStream.ts +30 -0
- package/packages/pdf-lite/src/utils/algos.ts +446 -0
- package/packages/pdf-lite/src/utils/assert.ts +42 -0
- package/packages/pdf-lite/src/utils/bytesToHex.ts +18 -0
- package/packages/pdf-lite/src/utils/bytesToHexBytes.ts +27 -0
- package/packages/pdf-lite/src/utils/bytesToString.ts +17 -0
- package/packages/pdf-lite/src/utils/concatUint8Arrays.ts +26 -0
- package/packages/pdf-lite/src/utils/escapeString.ts +49 -0
- package/packages/pdf-lite/src/utils/hexBytesToBytes.ts +22 -0
- package/packages/pdf-lite/src/utils/hexBytesToString.ts +21 -0
- package/packages/pdf-lite/src/utils/hexToBytes.ts +18 -0
- package/packages/pdf-lite/src/utils/padBytes.ts +25 -0
- package/packages/pdf-lite/src/utils/predictors.ts +332 -0
- package/packages/pdf-lite/src/utils/replaceInBuffer.ts +56 -0
- package/packages/pdf-lite/src/utils/stringToBytes.ts +22 -0
- package/packages/pdf-lite/src/utils/stringToHexBytes.ts +23 -0
- package/packages/pdf-lite/src/utils/unescapeString.ts +123 -0
- package/packages/pdf-lite/test/acceptance/__snapshots__/versions.node.test.ts.snap +60766 -0
- package/packages/pdf-lite/test/acceptance/fixtures/1.3/basic.pdf +0 -0
- package/packages/pdf-lite/test/acceptance/fixtures/1.4/basic-aes-128.pdf +0 -0
- package/packages/pdf-lite/test/acceptance/fixtures/1.4/basic-aes-256.pdf +0 -0
- package/packages/pdf-lite/test/acceptance/fixtures/1.4/basic-rc4-128.pdf +0 -0
- package/packages/pdf-lite/test/acceptance/fixtures/1.4/basic-rc4-40.pdf +0 -0
- package/packages/pdf-lite/test/acceptance/fixtures/1.4/basic.pdf +0 -0
- package/packages/pdf-lite/test/acceptance/fixtures/1.5/basic.pdf +0 -0
- package/packages/pdf-lite/test/acceptance/fixtures/1.6/basic.pdf +0 -0
- package/packages/pdf-lite/test/acceptance/fixtures/1.7/basic.pdf +0 -0
- package/packages/pdf-lite/test/acceptance/fixtures/2.0/basic-aes-128.pdf +43 -0
- package/packages/pdf-lite/test/acceptance/fixtures/2.0/basic-aes-256.pdf +43 -0
- package/packages/pdf-lite/test/acceptance/fixtures/2.0/basic-rc4-128.pdf +43 -0
- package/packages/pdf-lite/test/acceptance/fixtures/2.0/basic-rc4-40.pdf +44 -0
- package/packages/pdf-lite/test/acceptance/fixtures/2.0/basic.pdf +79 -0
- package/packages/pdf-lite/test/acceptance/versions.node.test.ts +41 -0
- package/packages/pdf-lite/test/unit/__snapshots__/decoder.node.test.ts.snap +86947 -0
- package/packages/pdf-lite/test/unit/__snapshots__/tokeniser.node.test.ts.snap +131829 -0
- package/packages/pdf-lite/test/unit/ciphers.test.ts +61 -0
- package/packages/pdf-lite/test/unit/decoder.node.test.ts +21 -0
- package/packages/pdf-lite/test/unit/decoder.test.ts +567 -0
- package/packages/pdf-lite/test/unit/filters.test.ts +67 -0
- package/packages/pdf-lite/test/unit/fixtures/basic.pdf +0 -0
- package/packages/pdf-lite/test/unit/fixtures/encrypted_v1/basic-aes-128.pdf +0 -0
- package/packages/pdf-lite/test/unit/fixtures/encrypted_v1/basic-aes-256.pdf +0 -0
- package/packages/pdf-lite/test/unit/fixtures/encrypted_v1/basic-rc4-128.pdf +0 -0
- package/packages/pdf-lite/test/unit/fixtures/encrypted_v1/basic-rc4-40.pdf +43 -0
- package/packages/pdf-lite/test/unit/fixtures/protectedAdobeLivecycle.pdf +0 -0
- package/packages/pdf-lite/test/unit/fixtures/rsa-2048/index.ts +187 -0
- package/packages/pdf-lite/test/unit/fixtures/template.pdf +0 -0
- package/packages/pdf-lite/test/unit/incremental-update.test.ts +0 -0
- package/packages/pdf-lite/test/unit/objects.test.ts +0 -0
- package/packages/pdf-lite/test/unit/pdf-document-signing.test.ts +0 -0
- package/packages/pdf-lite/test/unit/pdf-revision.test.ts +195 -0
- package/packages/pdf-lite/test/unit/pdf.browser.test.ts +0 -0
- package/packages/pdf-lite/test/unit/predictors.test.ts +226 -0
- package/packages/pdf-lite/test/unit/ref.test.ts +158 -0
- package/packages/pdf-lite/test/unit/security-handlers.test.ts +645 -0
- package/packages/pdf-lite/test/unit/serializer.test.ts +81 -0
- package/packages/pdf-lite/test/unit/signature-objects.test.ts +814 -0
- package/packages/pdf-lite/test/unit/string-escaping.test.ts +84 -0
- package/packages/pdf-lite/test/unit/tokeniser.node.test.ts +38 -0
- package/packages/pdf-lite/test/unit/tokeniser.test.ts +1213 -0
- package/packages/pdf-lite/test/unit/utils.test.ts +248 -0
- package/packages/pdf-lite/test/unit/xref-lookup.test.ts +72 -0
- package/packages/pdf-lite/tsconfig.json +4 -0
- package/packages/pdf-lite/tsconfig.prod.json +8 -0
- package/packages/pdf-lite/typedoc.json +14 -0
- package/packages/pdf-lite/vitest.config.ts +43 -0
- package/pnpm-workspace.yaml +2 -0
- package/renovate.json +34 -0
- package/scripts/build-examples.ts +30 -0
- package/scripts/bump-version.sh +56 -0
- package/scripts/gen-html-docs.sh +21 -0
- package/scripts/gen-md-docs.sh +15 -0
- package/scripts/prepare-release.sh +33 -0
- package/tsconfig.json +22 -0
- package/tsconfig.prod.json +12 -0
- package/typedoc.json +34 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { PdfEndObjectToken } from '../tokens/end-object-token'
|
|
2
|
+
import { PdfStartObjectToken } from '../tokens/start-object-token'
|
|
3
|
+
import { PdfWhitespaceToken } from '../tokens/whitespace-token'
|
|
4
|
+
import { PdfNull } from './pdf-null'
|
|
5
|
+
import { PdfObject } from './pdf-object'
|
|
6
|
+
import { PdfObjectReference } from './pdf-object-reference'
|
|
7
|
+
import { PdfStream } from './pdf-stream'
|
|
8
|
+
import { Ref } from '../ref'
|
|
9
|
+
import { PdfByteOffsetToken } from '../tokens/byte-offset-token'
|
|
10
|
+
|
|
11
|
+
export class PdfIndirectObject<
|
|
12
|
+
T extends PdfObject = PdfObject,
|
|
13
|
+
> extends PdfObjectReference {
|
|
14
|
+
static readonly MAX_ORDER_INDEX = 2147483647
|
|
15
|
+
|
|
16
|
+
content: T
|
|
17
|
+
offset: Ref<number>
|
|
18
|
+
encryptable?: boolean
|
|
19
|
+
orderIndex?: number
|
|
20
|
+
|
|
21
|
+
constructor(
|
|
22
|
+
options:
|
|
23
|
+
| {
|
|
24
|
+
objectNumber?: number
|
|
25
|
+
generationNumber?: number
|
|
26
|
+
content: T
|
|
27
|
+
offset?: number | Ref<number>
|
|
28
|
+
encryptable?: boolean
|
|
29
|
+
}
|
|
30
|
+
| T,
|
|
31
|
+
) {
|
|
32
|
+
if (options instanceof PdfObject) {
|
|
33
|
+
super(-1, 0)
|
|
34
|
+
this.content = options
|
|
35
|
+
this.offset = new Ref(0)
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
super(options.objectNumber ?? -1, options.generationNumber ?? 0)
|
|
40
|
+
this.content = options.content
|
|
41
|
+
this.offset =
|
|
42
|
+
options.offset instanceof Ref
|
|
43
|
+
? options.offset
|
|
44
|
+
: new Ref(options.offset ?? 0)
|
|
45
|
+
this.encryptable = options.encryptable
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
get reference(): PdfObjectReference {
|
|
49
|
+
return new Proxy(this, {
|
|
50
|
+
get: (target, prop) => {
|
|
51
|
+
const value = new PdfObjectReference(
|
|
52
|
+
target.objectNumber,
|
|
53
|
+
target.generationNumber,
|
|
54
|
+
)
|
|
55
|
+
if (prop === 'objectNumber') {
|
|
56
|
+
return target.objectNumber
|
|
57
|
+
} else if (prop === 'generationNumber') {
|
|
58
|
+
return target.generationNumber
|
|
59
|
+
} else {
|
|
60
|
+
return value[prop as keyof PdfObjectReference]
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
isEncryptable() {
|
|
67
|
+
if (this.encryptable === undefined) {
|
|
68
|
+
if (
|
|
69
|
+
this.content instanceof PdfStream &&
|
|
70
|
+
this.content.isType('XRef')
|
|
71
|
+
) {
|
|
72
|
+
return false
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return this.encryptable ?? true
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
static createPlaceholder<T extends PdfObject>(
|
|
80
|
+
objectNumber?: number,
|
|
81
|
+
generationNumber?: number,
|
|
82
|
+
content?: T,
|
|
83
|
+
): PdfIndirectObject<T extends unknown ? PdfNull : T> {
|
|
84
|
+
return new PdfIndirectObject({
|
|
85
|
+
objectNumber: objectNumber ?? -1,
|
|
86
|
+
generationNumber: generationNumber ?? 0,
|
|
87
|
+
content: content ?? (new PdfNull() as any),
|
|
88
|
+
offset: -1,
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
inPdf() {
|
|
93
|
+
return this.objectNumber >= 1
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
matchesReference(ref?: PdfObjectReference) {
|
|
97
|
+
if (!ref) {
|
|
98
|
+
return false
|
|
99
|
+
}
|
|
100
|
+
return (
|
|
101
|
+
this.objectNumber === ref.objectNumber &&
|
|
102
|
+
this.generationNumber === ref.generationNumber
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
protected tokenize() {
|
|
107
|
+
return [
|
|
108
|
+
new PdfByteOffsetToken(this.offset),
|
|
109
|
+
new PdfStartObjectToken(this.objectNumber, this.generationNumber),
|
|
110
|
+
...(this.content.preTokens ? [] : [PdfWhitespaceToken.NEWLINE]),
|
|
111
|
+
...this.content.toTokens(),
|
|
112
|
+
...(this.content.postTokens ? [] : [PdfWhitespaceToken.NEWLINE]),
|
|
113
|
+
new PdfEndObjectToken(),
|
|
114
|
+
]
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
clone(): this {
|
|
118
|
+
return new PdfIndirectObject({
|
|
119
|
+
objectNumber: this.objectNumber,
|
|
120
|
+
generationNumber: this.generationNumber,
|
|
121
|
+
content: this.content.clone(),
|
|
122
|
+
offset: this.offset.resolve(),
|
|
123
|
+
}) as this
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
order(): number {
|
|
127
|
+
return this.orderIndex ?? 0
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
isModified(): boolean {
|
|
131
|
+
return (
|
|
132
|
+
super.isModified() ||
|
|
133
|
+
this.content.isModified() ||
|
|
134
|
+
this.offset.isModified
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { PdfNameToken } from '../tokens/name-token'
|
|
2
|
+
import { PdfObject } from './pdf-object'
|
|
3
|
+
|
|
4
|
+
export class PdfName<T extends string = string> extends PdfObject {
|
|
5
|
+
value: T
|
|
6
|
+
|
|
7
|
+
constructor(value: T) {
|
|
8
|
+
super()
|
|
9
|
+
this.value = value
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
protected tokenize() {
|
|
13
|
+
return [new PdfNameToken(this.value)]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
clone(): this {
|
|
17
|
+
return new PdfName(this.value) as this
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { PdfObject } from './pdf-object'
|
|
2
|
+
import { PdfNullToken } from '../tokens/null-token'
|
|
3
|
+
import { PdfToken } from '../tokens/token'
|
|
4
|
+
|
|
5
|
+
export class PdfNull extends PdfObject {
|
|
6
|
+
static readonly NULL: PdfNull = new PdfNull()
|
|
7
|
+
|
|
8
|
+
protected tokenize() {
|
|
9
|
+
return [new PdfNullToken()]
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
clone(): this {
|
|
13
|
+
return new PdfNull() as this
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { Ref } from '../ref'
|
|
2
|
+
import { PdfNumberToken } from '../tokens/number-token'
|
|
3
|
+
import { PdfObject } from './pdf-object'
|
|
4
|
+
|
|
5
|
+
export class PdfNumber extends PdfObject {
|
|
6
|
+
#value: Ref<number>
|
|
7
|
+
padTo: number
|
|
8
|
+
decimalPlaces: number
|
|
9
|
+
isByteOffset: boolean = false
|
|
10
|
+
|
|
11
|
+
constructor(
|
|
12
|
+
options:
|
|
13
|
+
| {
|
|
14
|
+
value: number | Ref<number>
|
|
15
|
+
padTo?: number
|
|
16
|
+
decimalPlaces?: number
|
|
17
|
+
}
|
|
18
|
+
| number
|
|
19
|
+
| Ref<number>
|
|
20
|
+
| PdfNumber = 0,
|
|
21
|
+
) {
|
|
22
|
+
super()
|
|
23
|
+
if (options instanceof Ref) {
|
|
24
|
+
this.#value = options
|
|
25
|
+
this.padTo = 0
|
|
26
|
+
this.decimalPlaces = 0
|
|
27
|
+
} else if (options instanceof PdfNumber) {
|
|
28
|
+
this.#value = options.ref
|
|
29
|
+
this.padTo = options.padTo
|
|
30
|
+
this.decimalPlaces = options.decimalPlaces
|
|
31
|
+
this.preTokens = options.preTokens
|
|
32
|
+
this.postTokens = options.postTokens
|
|
33
|
+
} else if (typeof options === 'number') {
|
|
34
|
+
this.#value = new Ref(options)
|
|
35
|
+
this.padTo = 0
|
|
36
|
+
this.decimalPlaces = 0
|
|
37
|
+
} else {
|
|
38
|
+
this.#value =
|
|
39
|
+
typeof options.value === 'number'
|
|
40
|
+
? new Ref(options.value)
|
|
41
|
+
: options.value
|
|
42
|
+
this.padTo = options.padTo ?? 0
|
|
43
|
+
this.decimalPlaces = options.decimalPlaces ?? 0
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (
|
|
47
|
+
this.value === Number.POSITIVE_INFINITY ||
|
|
48
|
+
this.value === Number.NEGATIVE_INFINITY
|
|
49
|
+
) {
|
|
50
|
+
throw new Error('PDF numbers cannot be infinite')
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
get ref() {
|
|
55
|
+
return this.#value
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
get value() {
|
|
59
|
+
return this.#value.resolve()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
set value(value: number) {
|
|
63
|
+
this.#value.update(value)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
onChange(callback: (value: number) => void): void {
|
|
67
|
+
this.#value.onUpdate(callback)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
toToken(): PdfNumberToken {
|
|
71
|
+
return new PdfNumberToken({
|
|
72
|
+
value: this.#value,
|
|
73
|
+
padTo: this.padTo,
|
|
74
|
+
decimalPlaces: this.decimalPlaces,
|
|
75
|
+
isByteToken: this.isByteOffset,
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
protected tokenize() {
|
|
80
|
+
return [this.toToken()]
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
clone(): this {
|
|
84
|
+
return new PdfNumber({
|
|
85
|
+
value: this.value,
|
|
86
|
+
padTo: this.padTo,
|
|
87
|
+
decimalPlaces: this.decimalPlaces,
|
|
88
|
+
}) as this
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
isModified(): boolean {
|
|
92
|
+
return super.isModified() || this.#value.isModified
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export class PdfByteOffsetNumber extends PdfNumber {
|
|
97
|
+
isByteOffset: boolean = true
|
|
98
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { PdfToken } from '../tokens/token'
|
|
2
|
+
import { PdfObjectReferenceToken } from '../tokens/object-reference-token'
|
|
3
|
+
import { PdfObject } from './pdf-object'
|
|
4
|
+
|
|
5
|
+
export class PdfObjectReference extends PdfObject {
|
|
6
|
+
objectNumber: number
|
|
7
|
+
generationNumber: number
|
|
8
|
+
|
|
9
|
+
constructor(objectNumber: number, generationNumber: number) {
|
|
10
|
+
super()
|
|
11
|
+
this.objectNumber = objectNumber
|
|
12
|
+
this.generationNumber = generationNumber
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
protected tokenize(): PdfToken[] {
|
|
16
|
+
return [
|
|
17
|
+
new PdfObjectReferenceToken(
|
|
18
|
+
this.objectNumber,
|
|
19
|
+
this.generationNumber,
|
|
20
|
+
),
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
clone(): this {
|
|
25
|
+
return new PdfObjectReference(
|
|
26
|
+
this.objectNumber,
|
|
27
|
+
this.generationNumber,
|
|
28
|
+
) as this
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { ByteArray } from '../../types.js'
|
|
2
|
+
import { concatUint8Arrays } from '../../utils/concatUint8Arrays.js'
|
|
3
|
+
import { PdfToken } from '../tokens/token.js'
|
|
4
|
+
import { PdfWhitespaceToken } from '../tokens/whitespace-token.js'
|
|
5
|
+
|
|
6
|
+
export abstract class PdfObject {
|
|
7
|
+
/** Optional tokens to prepend or append during serialization */
|
|
8
|
+
preTokens?: PdfToken[]
|
|
9
|
+
/** Optional tokens to prepend or append during serialization */
|
|
10
|
+
postTokens?: PdfToken[]
|
|
11
|
+
/** Indicates whether the object has been modified. By default, assume it has been modified because it's a new object */
|
|
12
|
+
protected modified: boolean = true
|
|
13
|
+
/** Tokenizes the object into an array of PdfTokens */
|
|
14
|
+
protected abstract tokenize(): PdfToken[]
|
|
15
|
+
|
|
16
|
+
/** The type of this PDF object */
|
|
17
|
+
get objectType(): string {
|
|
18
|
+
return this.constructor.name
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Indicates whether the object has been modified. Override this method if the modified state is determined differently */
|
|
22
|
+
isModified(): boolean {
|
|
23
|
+
return this.modified
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Sets the modified state of the object. Override this method if the modified state is determined differently */
|
|
27
|
+
setModified(modified: boolean = true): void {
|
|
28
|
+
this.modified = modified
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Converts the object to an array of PdfTokens, including any pre or post tokens */
|
|
32
|
+
toTokens(): PdfToken[] {
|
|
33
|
+
return [
|
|
34
|
+
...(this.preTokens ?? []),
|
|
35
|
+
...this.tokenize(),
|
|
36
|
+
...(this.postTokens ?? []),
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Converts the object to a ByteArray, optionally padding to a specified length */
|
|
41
|
+
toBytes(padTo?: number): ByteArray {
|
|
42
|
+
const tokens = this.toTokens()
|
|
43
|
+
|
|
44
|
+
const byteArray = concatUint8Arrays(
|
|
45
|
+
...tokens.map((token) => token.toBytes()),
|
|
46
|
+
)
|
|
47
|
+
if (padTo) {
|
|
48
|
+
const paddedArray = new Uint8Array(padTo)
|
|
49
|
+
paddedArray.set(byteArray)
|
|
50
|
+
return paddedArray
|
|
51
|
+
}
|
|
52
|
+
return byteArray
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Converts the object to a string representation */
|
|
56
|
+
toString(): string {
|
|
57
|
+
let str = ''
|
|
58
|
+
for (const byte of this.toBytes()) {
|
|
59
|
+
str += String.fromCharCode(byte)
|
|
60
|
+
}
|
|
61
|
+
return str
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Attempts to cast the object to a specific PdfObject subclass */
|
|
65
|
+
as<T extends PdfObject>(ctor: new (...args: any[]) => T): T {
|
|
66
|
+
if (this instanceof ctor) {
|
|
67
|
+
return this as T
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
throw new Error(
|
|
71
|
+
`Cannot cast object of type ${this.objectType} to ${ctor.name}`,
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Creates a deep clone of the object */
|
|
76
|
+
abstract clone(): this
|
|
77
|
+
|
|
78
|
+
/** Compares this object to another for equality based on their token representations */
|
|
79
|
+
equals(other?: PdfObject): boolean {
|
|
80
|
+
if (!other) {
|
|
81
|
+
return false
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const tokensA = this.toTokens().filter(
|
|
85
|
+
(x) => !(x instanceof PdfWhitespaceToken),
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
const tokensB = other
|
|
89
|
+
.toTokens()
|
|
90
|
+
.filter((x) => !(x instanceof PdfWhitespaceToken))
|
|
91
|
+
|
|
92
|
+
if (tokensA.length !== tokensB.length) {
|
|
93
|
+
return false
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
for (let i = 0; i < tokensA.length; i++) {
|
|
97
|
+
const tokenA = tokensA[i]
|
|
98
|
+
const tokenB = tokensB[i]
|
|
99
|
+
|
|
100
|
+
if (!tokenA.equals(tokenB)) {
|
|
101
|
+
return false
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return true
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Ref } from '../ref'
|
|
2
|
+
import { PdfStartXRefToken } from '../tokens/start-xref-token'
|
|
3
|
+
import { PdfWhitespaceToken } from '../tokens/whitespace-token'
|
|
4
|
+
import { PdfNumber } from './pdf-number'
|
|
5
|
+
import { PdfObject } from './pdf-object'
|
|
6
|
+
|
|
7
|
+
export class PdfStartXRef extends PdfObject {
|
|
8
|
+
offset: PdfNumber
|
|
9
|
+
|
|
10
|
+
constructor(offset: number | PdfNumber | Ref<number> = -1) {
|
|
11
|
+
// default to -1 for unknown offset
|
|
12
|
+
super()
|
|
13
|
+
this.offset =
|
|
14
|
+
offset instanceof PdfNumber
|
|
15
|
+
? offset
|
|
16
|
+
: new PdfNumber({ value: offset })
|
|
17
|
+
this.offset.isByteOffset = true
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
protected tokenize() {
|
|
21
|
+
const whiteSpaceTokens = this.offset.preTokens
|
|
22
|
+
? []
|
|
23
|
+
: [PdfWhitespaceToken.NEWLINE]
|
|
24
|
+
|
|
25
|
+
return [
|
|
26
|
+
new PdfStartXRefToken(),
|
|
27
|
+
...whiteSpaceTokens,
|
|
28
|
+
...this.offset.toTokens(),
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
clone(): this {
|
|
33
|
+
return new PdfStartXRef(this.offset.clone()) as this
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
isModified(): boolean {
|
|
37
|
+
return super.isModified() || this.offset.isModified()
|
|
38
|
+
}
|
|
39
|
+
}
|