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,20 @@
|
|
|
1
|
+
import { Ref } from '../ref'
|
|
2
|
+
import { PdfToken } from './token'
|
|
3
|
+
|
|
4
|
+
export class PdfByteOffsetToken extends PdfToken {
|
|
5
|
+
value: Ref<number>
|
|
6
|
+
|
|
7
|
+
constructor(value: Ref<number> = new Ref(0)) {
|
|
8
|
+
super(new Uint8Array())
|
|
9
|
+
|
|
10
|
+
this.value = value
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
resolve(): number {
|
|
14
|
+
return this.value.resolve()
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
update(offset: number | Ref<number>): void {
|
|
18
|
+
this.value.update(offset)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { stringToBytes } from '../../utils/stringToBytes'
|
|
2
|
+
import { concatUint8Arrays } from '../../utils/concatUint8Arrays'
|
|
3
|
+
import { PdfToken } from './token'
|
|
4
|
+
import { ByteArray } from '../../types'
|
|
5
|
+
import { bytesToString } from '../../utils/bytesToString'
|
|
6
|
+
|
|
7
|
+
export class PdfCommentToken extends PdfToken {
|
|
8
|
+
static EOF = new PdfCommentToken('%EOF')
|
|
9
|
+
comment: ByteArray
|
|
10
|
+
|
|
11
|
+
constructor(comment: ByteArray | string) {
|
|
12
|
+
super(PdfCommentToken.toBytes(comment))
|
|
13
|
+
this.comment =
|
|
14
|
+
typeof comment === 'string' ? stringToBytes(comment) : comment
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
get innerComment(): string {
|
|
18
|
+
return bytesToString(this.comment)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
private static toBytes(comment: ByteArray | string): ByteArray {
|
|
22
|
+
const tokenBytes =
|
|
23
|
+
typeof comment === 'string' ? stringToBytes(comment) : comment
|
|
24
|
+
return concatUint8Arrays(stringToBytes('%'), tokenBytes)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
static isEofCommentToken(token: PdfToken): boolean {
|
|
28
|
+
if (!(token instanceof PdfCommentToken)) return false
|
|
29
|
+
const tokenStr = token.innerComment.trim()
|
|
30
|
+
return tokenStr.toLowerCase() === '%eof'
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { stringToBytes } from '../../utils/stringToBytes'
|
|
2
|
+
import { PdfToken } from './token'
|
|
3
|
+
|
|
4
|
+
const END_DICTIONARY_BYTES = stringToBytes('>>')
|
|
5
|
+
|
|
6
|
+
export class PdfEndDictionaryToken extends PdfToken {
|
|
7
|
+
constructor() {
|
|
8
|
+
super(END_DICTIONARY_BYTES)
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ByteArray } from '../../types'
|
|
2
|
+
import { stringToBytes } from '../../utils/stringToBytes'
|
|
3
|
+
import { PdfToken } from './token'
|
|
4
|
+
|
|
5
|
+
const END_STREAM_BYTES = stringToBytes('endstream')
|
|
6
|
+
|
|
7
|
+
export class PdfEndStreamToken extends PdfToken {
|
|
8
|
+
constructor(bytes?: ByteArray) {
|
|
9
|
+
super(bytes ?? END_STREAM_BYTES)
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ByteArray } from '../../types'
|
|
2
|
+
import { stringToBytes } from '../../utils/stringToBytes'
|
|
3
|
+
import { PdfToken } from './token'
|
|
4
|
+
|
|
5
|
+
export class PdfHexadecimalToken extends PdfToken {
|
|
6
|
+
raw: ByteArray
|
|
7
|
+
|
|
8
|
+
constructor(hexadecimal: string | ByteArray) {
|
|
9
|
+
super(PdfHexadecimalToken.toBytes(hexadecimal))
|
|
10
|
+
|
|
11
|
+
this.raw =
|
|
12
|
+
typeof hexadecimal === 'string'
|
|
13
|
+
? stringToBytes(hexadecimal)
|
|
14
|
+
: hexadecimal
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
private static toBytes(hexadecimal: string | ByteArray): ByteArray {
|
|
18
|
+
const bytes = stringToBytes(hexadecimal)
|
|
19
|
+
|
|
20
|
+
return new Uint8Array([0x3c, ...bytes, 0x3e])
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ByteArray } from '../../types'
|
|
2
|
+
import { stringToBytes } from '../../utils/stringToBytes'
|
|
3
|
+
import { PdfToken } from './token'
|
|
4
|
+
|
|
5
|
+
export class PdfNameToken extends PdfToken {
|
|
6
|
+
name: string
|
|
7
|
+
|
|
8
|
+
constructor(name: string) {
|
|
9
|
+
if (typeof name !== 'string' || name.length === 0) {
|
|
10
|
+
throw new Error('PdfNameToken name must be a non-empty string')
|
|
11
|
+
}
|
|
12
|
+
super(PdfNameToken.toBytes(name))
|
|
13
|
+
this.name = name
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
private static toBytes(name: string): ByteArray {
|
|
17
|
+
return stringToBytes(`/${name}`)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { ByteArray } from '../../types'
|
|
2
|
+
import { stringToBytes } from '../../utils/stringToBytes'
|
|
3
|
+
import { Ref } from '../ref'
|
|
4
|
+
import { PdfToken } from './token'
|
|
5
|
+
|
|
6
|
+
export class PdfNumberToken extends PdfToken {
|
|
7
|
+
#value: Ref<number>
|
|
8
|
+
padTo: number
|
|
9
|
+
decimalPlaces: number
|
|
10
|
+
isByteToken: boolean = false
|
|
11
|
+
|
|
12
|
+
constructor(
|
|
13
|
+
options:
|
|
14
|
+
| {
|
|
15
|
+
value: number | ByteArray | PdfNumberToken | Ref<number>
|
|
16
|
+
padTo?: number
|
|
17
|
+
decimalPlaces?: number
|
|
18
|
+
isByteToken?: boolean
|
|
19
|
+
}
|
|
20
|
+
| number
|
|
21
|
+
| ByteArray,
|
|
22
|
+
padTo?: number,
|
|
23
|
+
decimalPlaces?: number,
|
|
24
|
+
) {
|
|
25
|
+
super()
|
|
26
|
+
|
|
27
|
+
if (
|
|
28
|
+
typeof options === 'number' ||
|
|
29
|
+
options instanceof Uint8Array ||
|
|
30
|
+
options instanceof Ref ||
|
|
31
|
+
options instanceof PdfNumberToken
|
|
32
|
+
) {
|
|
33
|
+
this.#value = PdfNumberToken.getValue(options)
|
|
34
|
+
this.padTo = padTo ?? 0
|
|
35
|
+
this.decimalPlaces = decimalPlaces ?? 0
|
|
36
|
+
this.isByteToken = false
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
this.#value = PdfNumberToken.getValue(options.value)
|
|
41
|
+
this.padTo = options.padTo ?? 0
|
|
42
|
+
|
|
43
|
+
this.decimalPlaces =
|
|
44
|
+
options.decimalPlaces ??
|
|
45
|
+
PdfNumberToken.getDecimalPlaces(options.value)
|
|
46
|
+
this.isByteToken = options.isByteToken ?? false
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
toBytes(): ByteArray {
|
|
50
|
+
return PdfNumberToken.toBytes(
|
|
51
|
+
this.#value,
|
|
52
|
+
this.padTo,
|
|
53
|
+
this.decimalPlaces,
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
get ref(): Ref<number> {
|
|
58
|
+
return this.#value
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
set ref(newRef: Ref<number>) {
|
|
62
|
+
this.#value = newRef
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
get value(): number {
|
|
66
|
+
return this.#value.resolve()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
set value(newValue: number) {
|
|
70
|
+
this.#value.update(newValue)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
static getValue(
|
|
74
|
+
bytes: ByteArray | PdfNumberToken | number | Ref<number>,
|
|
75
|
+
): Ref<number> {
|
|
76
|
+
if (bytes instanceof Ref) {
|
|
77
|
+
return bytes
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (bytes instanceof PdfNumberToken) {
|
|
81
|
+
return bytes.ref
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (typeof bytes === 'number') {
|
|
85
|
+
return new Ref(bytes)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const str = new TextDecoder().decode(bytes)
|
|
89
|
+
return new Ref(parseFloat(str))
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
static getPadding(
|
|
93
|
+
bytes: ByteArray | PdfNumberToken | number | Ref<number>,
|
|
94
|
+
): number {
|
|
95
|
+
if (bytes instanceof PdfNumberToken) {
|
|
96
|
+
return bytes.padTo
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (bytes instanceof Ref) {
|
|
100
|
+
bytes = PdfNumberToken.toBytes(bytes.resolve())
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (typeof bytes === 'number') {
|
|
104
|
+
bytes = PdfNumberToken.toBytes(bytes)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
let padding = 0
|
|
108
|
+
while (bytes.length && bytes[0] === 0x30) {
|
|
109
|
+
bytes = bytes.slice(1)
|
|
110
|
+
padding++
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return padding
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
static getDecimalPlaces(
|
|
117
|
+
bytes: ByteArray | PdfNumberToken | number | Ref<number>,
|
|
118
|
+
): number {
|
|
119
|
+
if (bytes instanceof PdfNumberToken) {
|
|
120
|
+
return bytes.decimalPlaces
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (bytes instanceof Ref) {
|
|
124
|
+
bytes = PdfNumberToken.toBytes(bytes.resolve())
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (typeof bytes === 'number') {
|
|
128
|
+
bytes = PdfNumberToken.toBytes(bytes)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const str = new TextDecoder().decode(bytes)
|
|
132
|
+
const match = str.match(/\.(\d+)/)
|
|
133
|
+
|
|
134
|
+
if (match) {
|
|
135
|
+
return match[1].length
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return 0
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
static toBytes(
|
|
142
|
+
value: number | PdfNumberToken | Ref<number> | ByteArray,
|
|
143
|
+
padTo?: number,
|
|
144
|
+
decimalPlaces?: number,
|
|
145
|
+
): ByteArray {
|
|
146
|
+
if (value instanceof Uint8Array) {
|
|
147
|
+
return value
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (value instanceof PdfNumberToken) {
|
|
151
|
+
return value.toBytes()
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const numberValue = value instanceof Ref ? value.resolve() : value
|
|
155
|
+
|
|
156
|
+
const valueString = decimalPlaces
|
|
157
|
+
? numberValue.toFixed(decimalPlaces)
|
|
158
|
+
: numberValue.toString()
|
|
159
|
+
|
|
160
|
+
const tokenString = valueString.padStart(padTo ?? 0, '0')
|
|
161
|
+
|
|
162
|
+
return stringToBytes(tokenString)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ByteArray } from '../../types'
|
|
2
|
+
import { stringToBytes } from '../../utils/stringToBytes'
|
|
3
|
+
import { PdfToken } from './token'
|
|
4
|
+
|
|
5
|
+
export class PdfObjectReferenceToken extends PdfToken {
|
|
6
|
+
objectNumber: number
|
|
7
|
+
generationNumber: number
|
|
8
|
+
|
|
9
|
+
constructor(objectNumber: number, generationNumber: number) {
|
|
10
|
+
super(PdfObjectReferenceToken.toBytes(objectNumber, generationNumber))
|
|
11
|
+
this.objectNumber = objectNumber
|
|
12
|
+
this.generationNumber = generationNumber
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
private static toBytes(
|
|
16
|
+
objectNumber: number,
|
|
17
|
+
generationNumber: number,
|
|
18
|
+
): ByteArray {
|
|
19
|
+
const objNumStr = objectNumber.toString()
|
|
20
|
+
const genNumStr = generationNumber.toString()
|
|
21
|
+
const refStr = `${objNumStr} ${genNumStr} R`
|
|
22
|
+
return stringToBytes(refStr)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { stringToBytes } from '../../utils/stringToBytes'
|
|
2
|
+
import { PdfToken } from './token'
|
|
3
|
+
|
|
4
|
+
const START_DICTIONARY_BYTES = stringToBytes('<<')
|
|
5
|
+
|
|
6
|
+
export class PdfStartDictionaryToken extends PdfToken {
|
|
7
|
+
constructor() {
|
|
8
|
+
super(START_DICTIONARY_BYTES)
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ByteArray } from '../../types'
|
|
2
|
+
import { stringToBytes } from '../../utils/stringToBytes'
|
|
3
|
+
import { PdfToken } from './token'
|
|
4
|
+
|
|
5
|
+
export class PdfStartObjectToken extends PdfToken {
|
|
6
|
+
objectNumber: number
|
|
7
|
+
generationNumber: number
|
|
8
|
+
byteOffset?: number
|
|
9
|
+
|
|
10
|
+
constructor(
|
|
11
|
+
objectNumber: number,
|
|
12
|
+
generationNumber: number,
|
|
13
|
+
byteOffset?: number,
|
|
14
|
+
) {
|
|
15
|
+
super(PdfStartObjectToken.toBytes(objectNumber, generationNumber))
|
|
16
|
+
this.objectNumber = objectNumber
|
|
17
|
+
this.generationNumber = generationNumber
|
|
18
|
+
this.byteOffset = byteOffset
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
private static toBytes(
|
|
22
|
+
objectNumber: number,
|
|
23
|
+
generationNumber: number,
|
|
24
|
+
): ByteArray {
|
|
25
|
+
const tokenString = `${objectNumber} ${generationNumber} obj`
|
|
26
|
+
return stringToBytes(tokenString)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { ByteArray } from '../../types'
|
|
2
|
+
import { stringToBytes } from '../../utils/stringToBytes'
|
|
3
|
+
import { PdfToken } from './token'
|
|
4
|
+
import { PdfWhitespaceToken } from './whitespace-token'
|
|
5
|
+
|
|
6
|
+
const START_STREAM_WITHOUT_WHITESPACE_BYTES = stringToBytes('stream')
|
|
7
|
+
const START_STREAM_BYTES = stringToBytes('stream\n')
|
|
8
|
+
|
|
9
|
+
export class PdfStartStreamToken extends PdfToken {
|
|
10
|
+
constructor(bytes?: ByteArray) {
|
|
11
|
+
super(bytes ?? START_STREAM_BYTES)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
getTrailingWhitespaceTokens(): PdfWhitespaceToken[] {
|
|
15
|
+
const tokens: PdfWhitespaceToken[] = []
|
|
16
|
+
const bytes = this.toBytes()
|
|
17
|
+
|
|
18
|
+
for (let i = bytes.length - 1; i >= 0; i--) {
|
|
19
|
+
const byte = bytes[i]
|
|
20
|
+
if (!PdfWhitespaceToken.isWhitespaceByte(byte)) {
|
|
21
|
+
continue
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
tokens.push(new PdfWhitespaceToken(byte))
|
|
25
|
+
}
|
|
26
|
+
return tokens.reverse()
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static withTrailingWhitespace(
|
|
30
|
+
whitespaceTokens: PdfToken[] | undefined,
|
|
31
|
+
): PdfStartStreamToken {
|
|
32
|
+
if (!whitespaceTokens || whitespaceTokens.length === 0) {
|
|
33
|
+
return new PdfStartStreamToken()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const totalLength =
|
|
37
|
+
START_STREAM_WITHOUT_WHITESPACE_BYTES.length +
|
|
38
|
+
whitespaceTokens.reduce((sum, token) => sum + token.byteLength, 0)
|
|
39
|
+
|
|
40
|
+
const bytes = new Uint8Array(totalLength)
|
|
41
|
+
bytes.set(START_STREAM_WITHOUT_WHITESPACE_BYTES, 0)
|
|
42
|
+
|
|
43
|
+
let offset = START_STREAM_WITHOUT_WHITESPACE_BYTES.length
|
|
44
|
+
for (const token of whitespaceTokens) {
|
|
45
|
+
const tokenBytes = token.toBytes()
|
|
46
|
+
bytes.set(tokenBytes, offset)
|
|
47
|
+
offset += tokenBytes.length
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return new PdfStartStreamToken(bytes)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ByteArray } from '../../types'
|
|
2
|
+
import { escapeString } from '../../utils/escapeString'
|
|
3
|
+
import { stringToBytes } from '../../utils/stringToBytes'
|
|
4
|
+
import { PdfToken } from './token'
|
|
5
|
+
|
|
6
|
+
export class PdfStringToken extends PdfToken {
|
|
7
|
+
value: ByteArray
|
|
8
|
+
|
|
9
|
+
constructor(value: string | ByteArray) {
|
|
10
|
+
super(PdfStringToken.toBytes(value))
|
|
11
|
+
this.value = typeof value === 'string' ? stringToBytes(value) : value
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
private static toBytes(value: string | ByteArray): ByteArray {
|
|
15
|
+
return new Uint8Array([0x28, ...escapeString(value), 0x29])
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ByteArray } from '../../types'
|
|
2
|
+
import { bytesToString } from '../../utils/bytesToString'
|
|
3
|
+
|
|
4
|
+
export abstract class PdfToken {
|
|
5
|
+
protected rawBytes: ByteArray
|
|
6
|
+
|
|
7
|
+
constructor(bytes?: ByteArray) {
|
|
8
|
+
this.rawBytes = bytes ?? new Uint8Array()
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
toBytes(): ByteArray {
|
|
12
|
+
return this.rawBytes
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
toString(): string {
|
|
16
|
+
return bytesToString(this.toBytes())
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
get type(): string {
|
|
20
|
+
return this.constructor.name
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
get byteLength(): number {
|
|
24
|
+
return this.toBytes().length
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
equals(other: PdfToken): boolean {
|
|
28
|
+
if (this.byteLength !== other.byteLength) {
|
|
29
|
+
return false
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const bytes = this.toBytes()
|
|
33
|
+
const otherBytes = other.toBytes()
|
|
34
|
+
|
|
35
|
+
for (let i = 0; i < this.byteLength; i++) {
|
|
36
|
+
if (bytes[i] !== otherBytes[i]) {
|
|
37
|
+
return false
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return true
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { stringToBytes } from '../../utils/stringToBytes'
|
|
2
|
+
import { PdfToken } from './token'
|
|
3
|
+
|
|
4
|
+
const TRAILER = stringToBytes('trailer')
|
|
5
|
+
|
|
6
|
+
export class PdfTrailerToken extends PdfToken {
|
|
7
|
+
byteOffset?: number
|
|
8
|
+
constructor(byteOffset?: number) {
|
|
9
|
+
super(TRAILER)
|
|
10
|
+
this.byteOffset = byteOffset
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ByteArray } from '../../types'
|
|
2
|
+
import { PdfToken } from './token'
|
|
3
|
+
|
|
4
|
+
export class PdfWhitespaceToken extends PdfToken {
|
|
5
|
+
public static NEWLINE = new PdfWhitespaceToken('\n')
|
|
6
|
+
public static SPACE = new PdfWhitespaceToken(' ')
|
|
7
|
+
public static TAB = new PdfWhitespaceToken('\t')
|
|
8
|
+
public static CARRIAGE_RETURN = new PdfWhitespaceToken('\r')
|
|
9
|
+
|
|
10
|
+
constructor(value: string | ByteArray | number) {
|
|
11
|
+
super(PdfWhitespaceToken.toBytes(value))
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
private static toBytes(value: string | ByteArray | number): ByteArray {
|
|
15
|
+
if (value instanceof Uint8Array) {
|
|
16
|
+
return value
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (typeof value === 'number') {
|
|
20
|
+
return new Uint8Array([value])
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
switch (value) {
|
|
24
|
+
case ' ':
|
|
25
|
+
return new Uint8Array([0x20]) // space character
|
|
26
|
+
case '\t':
|
|
27
|
+
return new Uint8Array([0x09]) // tab character
|
|
28
|
+
case '\n':
|
|
29
|
+
return new Uint8Array([0x0a]) // newline character
|
|
30
|
+
case '\r':
|
|
31
|
+
return new Uint8Array([0x0d]) // carriage return character
|
|
32
|
+
default:
|
|
33
|
+
throw new Error(`Invalid whitespace character: ${value}`)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
static isWhitespaceByte(byte: number | null | undefined): boolean {
|
|
38
|
+
if (byte === null || byte === undefined) {
|
|
39
|
+
return false
|
|
40
|
+
}
|
|
41
|
+
return byte === 0x20 || byte === 0x0a || byte === 0x0d || byte === 0x09
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { ByteArray } from '../../types'
|
|
2
|
+
import { stringToBytes } from '../../utils/stringToBytes'
|
|
3
|
+
import { Ref } from '../ref'
|
|
4
|
+
import { PdfNumberToken } from './number-token'
|
|
5
|
+
import { PdfToken } from './token.js'
|
|
6
|
+
|
|
7
|
+
export class PdfXRefTableEntryToken extends PdfToken {
|
|
8
|
+
objectNumber: PdfNumberToken
|
|
9
|
+
generationNumber: PdfNumberToken
|
|
10
|
+
offset: PdfNumberToken
|
|
11
|
+
inUse: boolean
|
|
12
|
+
|
|
13
|
+
constructor(
|
|
14
|
+
offset: number | Ref<number> | PdfNumberToken,
|
|
15
|
+
generationNumber: number | PdfNumberToken,
|
|
16
|
+
objectNumber: number | PdfNumberToken,
|
|
17
|
+
inUse: boolean,
|
|
18
|
+
) {
|
|
19
|
+
super()
|
|
20
|
+
this.objectNumber =
|
|
21
|
+
objectNumber instanceof PdfNumberToken
|
|
22
|
+
? objectNumber
|
|
23
|
+
: new PdfNumberToken({ value: objectNumber })
|
|
24
|
+
this.generationNumber =
|
|
25
|
+
generationNumber instanceof PdfNumberToken
|
|
26
|
+
? generationNumber
|
|
27
|
+
: new PdfNumberToken({ value: generationNumber })
|
|
28
|
+
this.offset =
|
|
29
|
+
offset instanceof PdfNumberToken
|
|
30
|
+
? offset
|
|
31
|
+
: new PdfNumberToken({ value: offset })
|
|
32
|
+
this.inUse = inUse
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
toBytes(): ByteArray {
|
|
36
|
+
return PdfXRefTableEntryToken.toBytes(
|
|
37
|
+
this.generationNumber,
|
|
38
|
+
this.offset,
|
|
39
|
+
this.inUse,
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private static toBytes(
|
|
44
|
+
generationNumber: number | PdfNumberToken,
|
|
45
|
+
offset: number | PdfNumberToken | Ref<number>,
|
|
46
|
+
inUse: boolean,
|
|
47
|
+
): ByteArray {
|
|
48
|
+
const offsetString =
|
|
49
|
+
offset instanceof PdfNumberToken
|
|
50
|
+
? offset.toString()
|
|
51
|
+
: new PdfNumberToken({ value: offset, padTo: 10 }).toString()
|
|
52
|
+
|
|
53
|
+
const generationNumberString =
|
|
54
|
+
generationNumber instanceof PdfNumberToken
|
|
55
|
+
? generationNumber.toString()
|
|
56
|
+
: new PdfNumberToken({
|
|
57
|
+
value: generationNumber,
|
|
58
|
+
padTo: 5,
|
|
59
|
+
}).toString()
|
|
60
|
+
|
|
61
|
+
return stringToBytes(
|
|
62
|
+
`${offsetString} ${generationNumberString} ${inUse ? 'n' : 'f'}`,
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
}
|