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,687 @@
|
|
|
1
|
+
import { PdfToken } from '../tokens/token'
|
|
2
|
+
import { PdfEndStreamToken } from '../tokens/end-stream-token'
|
|
3
|
+
import { PdfStartStreamToken } from '../tokens/start-stream-token'
|
|
4
|
+
import { PdfStreamChunkToken } from '../tokens/stream-chunk-token'
|
|
5
|
+
import { PdfWhitespaceToken } from '../tokens/whitespace-token'
|
|
6
|
+
import { PdfDictionary } from './pdf-dictionary'
|
|
7
|
+
import { PdfObject } from './pdf-object'
|
|
8
|
+
import { PdfName } from './pdf-name'
|
|
9
|
+
import { PdfArray } from './pdf-array'
|
|
10
|
+
import { flate } from '../../filters/flate'
|
|
11
|
+
import { asciiHex } from '../../filters/asciihex'
|
|
12
|
+
import { ascii85 } from '../../filters/ascii85'
|
|
13
|
+
import { lzw } from '../../filters/lzw'
|
|
14
|
+
import { runLength } from '../../filters/runlength'
|
|
15
|
+
import { passthroughFilter } from '../../filters/pass-through'
|
|
16
|
+
import { ByteArray } from '../../types'
|
|
17
|
+
import { PdfNumber } from './pdf-number'
|
|
18
|
+
import { Predictor } from '../../utils/predictors'
|
|
19
|
+
import { bytesToPdfObjects } from '../generators'
|
|
20
|
+
import { PdfIndirectObject } from './pdf-indirect-object'
|
|
21
|
+
import { PdfXRefTableEntry } from './pdf-xref-table'
|
|
22
|
+
import { stringToBytes } from '../../utils/stringToBytes'
|
|
23
|
+
import { PdfFilter, PdfStreamFilterType } from '../../filters/types'
|
|
24
|
+
|
|
25
|
+
export class PdfStream<
|
|
26
|
+
T extends PdfDictionary = PdfDictionary,
|
|
27
|
+
> extends PdfObject {
|
|
28
|
+
header: T
|
|
29
|
+
original: ByteArray
|
|
30
|
+
preStreamDataTokens?: PdfToken[]
|
|
31
|
+
postStreamDataTokens?: PdfToken[]
|
|
32
|
+
|
|
33
|
+
constructor(
|
|
34
|
+
options:
|
|
35
|
+
| { header: T; original: ByteArray | string; isModified?: boolean }
|
|
36
|
+
| ByteArray
|
|
37
|
+
| string,
|
|
38
|
+
) {
|
|
39
|
+
super()
|
|
40
|
+
|
|
41
|
+
if (typeof options === 'string' || options instanceof Uint8Array) {
|
|
42
|
+
options = { header: new PdfDictionary() as T, original: options }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
this.header = options.header
|
|
46
|
+
this.modified = options.isModified ?? true
|
|
47
|
+
this.original =
|
|
48
|
+
typeof options.original === 'string'
|
|
49
|
+
? stringToBytes(options.original)
|
|
50
|
+
: options.original
|
|
51
|
+
if (!this.header.get('Length')) {
|
|
52
|
+
this.header.set('Length', new PdfNumber(this.original.length))
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
get raw(): ByteArray {
|
|
57
|
+
const length = this.header.get('Length')?.as(PdfNumber)?.value
|
|
58
|
+
if (length === undefined) return this.original
|
|
59
|
+
|
|
60
|
+
return this.original.slice(0, length)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
set raw(data: ByteArray) {
|
|
64
|
+
this.setModified()
|
|
65
|
+
this.original = data
|
|
66
|
+
this.header.set('Length', new PdfNumber(data.length))
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
get originalAsString(): string {
|
|
70
|
+
return new TextDecoder().decode(this.original)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
get rawAsString(): string {
|
|
74
|
+
return new TextDecoder().decode(this.raw)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
getFilters(): PdfStreamFilterType[] {
|
|
78
|
+
const filters = this.header.get('Filter') as
|
|
79
|
+
| PdfArray<PdfName<PdfStreamFilterType>>
|
|
80
|
+
| PdfName<PdfStreamFilterType>
|
|
81
|
+
| undefined
|
|
82
|
+
if (!filters) {
|
|
83
|
+
return []
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (filters instanceof PdfName) {
|
|
87
|
+
return [filters.value]
|
|
88
|
+
} else if (filters instanceof PdfArray) {
|
|
89
|
+
return filters.items.map((item) => item.value)
|
|
90
|
+
} else {
|
|
91
|
+
throw new Error('Invalid Filter entry in PDF stream')
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
addFilter(filterName: PdfStreamFilterType) {
|
|
96
|
+
const filters = this.header.get('Filter')
|
|
97
|
+
|
|
98
|
+
if (!filters) {
|
|
99
|
+
this.header.set('Filter', new PdfName(filterName))
|
|
100
|
+
} else if (filters instanceof PdfName) {
|
|
101
|
+
this.header.set(
|
|
102
|
+
'Filter',
|
|
103
|
+
new PdfArray([new PdfName(filterName), filters]),
|
|
104
|
+
)
|
|
105
|
+
} else if (filters instanceof PdfArray) {
|
|
106
|
+
filters.items.unshift(new PdfName(filterName))
|
|
107
|
+
} else {
|
|
108
|
+
throw new Error('Invalid Filter entry in PDF stream')
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const filter = PdfStream.getFilter(filterName)
|
|
112
|
+
this.raw = filter.encode(this.raw)
|
|
113
|
+
return this
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
setPredictor(predictorParams: {
|
|
117
|
+
Predictor?: number
|
|
118
|
+
Columns?: number
|
|
119
|
+
Colors?: number
|
|
120
|
+
BitsPerComponent?: number
|
|
121
|
+
}) {
|
|
122
|
+
let decodeParms = this.header.get('DecodeParms')?.as(PdfDictionary)
|
|
123
|
+
|
|
124
|
+
if (!decodeParms) {
|
|
125
|
+
decodeParms = new PdfDictionary()
|
|
126
|
+
this.header.set('DecodeParms', decodeParms)
|
|
127
|
+
} else if (decodeParms instanceof PdfDictionary) {
|
|
128
|
+
// already a dictionary
|
|
129
|
+
} else {
|
|
130
|
+
throw new Error('Invalid DecodeParms entry in PDF stream')
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
for (const [key, value] of Object.entries(predictorParams)) {
|
|
134
|
+
decodeParms.set(key, new PdfNumber(value))
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
this.raw = Predictor.encode(this.raw, predictorParams)
|
|
138
|
+
|
|
139
|
+
return this
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
removeFilter(filterName: PdfStreamFilterType) {
|
|
143
|
+
let filters = this.header.get('Filter')
|
|
144
|
+
if (!filters) {
|
|
145
|
+
return this
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const decoded = this.decode()
|
|
149
|
+
|
|
150
|
+
if (filters instanceof PdfName) {
|
|
151
|
+
if (filters.value === filterName) {
|
|
152
|
+
this.header.delete('Filter')
|
|
153
|
+
}
|
|
154
|
+
} else if (filters instanceof PdfArray) {
|
|
155
|
+
filters.items = filters.items.filter(
|
|
156
|
+
(item) => item.value !== filterName,
|
|
157
|
+
)
|
|
158
|
+
if (filters.items.length === 0) {
|
|
159
|
+
this.header.delete('Filter')
|
|
160
|
+
} else if (filters.items.length === 1) {
|
|
161
|
+
this.header.set('Filter', filters.items[0])
|
|
162
|
+
}
|
|
163
|
+
} else {
|
|
164
|
+
throw new Error('Invalid Filter entry in PDF stream')
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const finalFilters = this.getFilters()
|
|
168
|
+
const encoded = PdfStream.applyFilters(decoded, finalFilters)
|
|
169
|
+
this.raw = encoded
|
|
170
|
+
return this
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
removePredictor() {
|
|
174
|
+
const decoded = this.decode()
|
|
175
|
+
this.header.delete('DecodeParms')
|
|
176
|
+
this.raw = decoded
|
|
177
|
+
return this
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
removeAllFilters() {
|
|
181
|
+
const decoded = this.decode()
|
|
182
|
+
this.raw = decoded
|
|
183
|
+
this.header.delete('Filter')
|
|
184
|
+
return this
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
decode(): ByteArray {
|
|
188
|
+
let data: ByteArray = this.raw
|
|
189
|
+
const filters = this.getFilters()
|
|
190
|
+
|
|
191
|
+
for (const filterName of filters) {
|
|
192
|
+
const filter = PdfStream.getFilter(filterName)
|
|
193
|
+
data = filter.decode(data)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const predictorParams = Predictor.getDecodeParms(
|
|
197
|
+
this.header.get('DecodeParms')?.as(PdfDictionary),
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
if (predictorParams) {
|
|
201
|
+
data = Predictor.decode(data, predictorParams)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return data
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
parseAs<T extends PdfStream>(
|
|
208
|
+
Class: new (options: {
|
|
209
|
+
header: PdfDictionary
|
|
210
|
+
original: ByteArray
|
|
211
|
+
isModified?: boolean
|
|
212
|
+
}) => T,
|
|
213
|
+
): T {
|
|
214
|
+
const instance = new Class({
|
|
215
|
+
header: this.header,
|
|
216
|
+
original: this.original,
|
|
217
|
+
isModified: this.isModified(),
|
|
218
|
+
})
|
|
219
|
+
instance.preTokens = this.preTokens
|
|
220
|
+
instance.postTokens = this.postTokens
|
|
221
|
+
instance.preStreamDataTokens = this.preStreamDataTokens
|
|
222
|
+
instance.postStreamDataTokens = this.postStreamDataTokens
|
|
223
|
+
|
|
224
|
+
return instance
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
protected tokenize() {
|
|
228
|
+
return [
|
|
229
|
+
...this.header.toTokens(),
|
|
230
|
+
PdfStartStreamToken.withTrailingWhitespace(
|
|
231
|
+
this.preStreamDataTokens,
|
|
232
|
+
),
|
|
233
|
+
new PdfStreamChunkToken(this.original),
|
|
234
|
+
new PdfEndStreamToken(),
|
|
235
|
+
]
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
isType(name: string): boolean {
|
|
239
|
+
const type = this.header.get('Type')
|
|
240
|
+
return type instanceof PdfName && type.value === name
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
static getFilter(name: PdfStreamFilterType): PdfFilter {
|
|
244
|
+
const allFilters = PdfStream.getAllFilters()
|
|
245
|
+
if (!allFilters[name]) {
|
|
246
|
+
throw new Error(`Unsupported filter: ${name}`)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return allFilters[name]
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
static getAllFilters() {
|
|
253
|
+
return {
|
|
254
|
+
FlateDecode: flate(),
|
|
255
|
+
Fl: flate(),
|
|
256
|
+
ASCIIHexDecode: asciiHex(),
|
|
257
|
+
ASCII85Decode: ascii85(),
|
|
258
|
+
LZWDecode: lzw(),
|
|
259
|
+
RunLengthDecode: runLength(),
|
|
260
|
+
CCITTFaxDecode: passthroughFilter(),
|
|
261
|
+
DCTDecode: passthroughFilter(),
|
|
262
|
+
JPXDecode: passthroughFilter(),
|
|
263
|
+
Crypt: passthroughFilter(),
|
|
264
|
+
} as const satisfies {
|
|
265
|
+
[key in PdfStreamFilterType]: PdfFilter
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
static applyFilters(
|
|
270
|
+
data: ByteArray,
|
|
271
|
+
filters: PdfStreamFilterType[],
|
|
272
|
+
): ByteArray {
|
|
273
|
+
let result = data
|
|
274
|
+
for (const filterName of filters) {
|
|
275
|
+
const filter = PdfStream.getFilter(filterName)
|
|
276
|
+
if (!filter) {
|
|
277
|
+
throw new Error(`Unsupported filter: ${filterName}`)
|
|
278
|
+
}
|
|
279
|
+
result = filter.encode(result)
|
|
280
|
+
}
|
|
281
|
+
return result
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
clone(): this {
|
|
285
|
+
return new PdfStream({
|
|
286
|
+
header: this.header.clone(),
|
|
287
|
+
original: new Uint8Array(this.original),
|
|
288
|
+
}) as this
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export class PdfObjStream extends PdfStream {
|
|
293
|
+
constructor(options: {
|
|
294
|
+
header: PdfDictionary
|
|
295
|
+
original: ByteArray | string
|
|
296
|
+
isModified?: boolean
|
|
297
|
+
}) {
|
|
298
|
+
super(options)
|
|
299
|
+
|
|
300
|
+
if (!this.isType('ObjStm')) {
|
|
301
|
+
throw new Error('PDF Object Stream must be of type ObjStm')
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
static fromObjects(objects: Iterable<PdfIndirectObject>): PdfObjStream {
|
|
306
|
+
let header = ''
|
|
307
|
+
let objectData = ''
|
|
308
|
+
|
|
309
|
+
let offset = 0
|
|
310
|
+
|
|
311
|
+
for (const obj of objects) {
|
|
312
|
+
header += `${obj.objectNumber} ${offset} `
|
|
313
|
+
const objString = obj.content.toString()
|
|
314
|
+
objectData += objString + '\n'
|
|
315
|
+
offset += objString.length + 1
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const headerDict = new PdfDictionary()
|
|
319
|
+
headerDict.set('Type', new PdfName('ObjStm'))
|
|
320
|
+
headerDict.set('N', new PdfNumber(header.length))
|
|
321
|
+
headerDict.set('First', new PdfNumber(offset))
|
|
322
|
+
|
|
323
|
+
objectData = `${header.trim()}\n${objectData.trim()}`
|
|
324
|
+
|
|
325
|
+
return new PdfObjStream({
|
|
326
|
+
header: headerDict,
|
|
327
|
+
original: objectData,
|
|
328
|
+
})
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
*getObjectStream(): Generator<PdfIndirectObject> {
|
|
332
|
+
const decodedData = this.decode()
|
|
333
|
+
const reader = bytesToPdfObjects([decodedData])
|
|
334
|
+
const numbers: PdfNumber[] = []
|
|
335
|
+
let i = 0
|
|
336
|
+
|
|
337
|
+
while (true) {
|
|
338
|
+
const { value: obj, done } = reader.next()
|
|
339
|
+
if (done) break
|
|
340
|
+
|
|
341
|
+
if (obj instanceof PdfDictionary) {
|
|
342
|
+
const objectNumber = numbers[i * 2].value
|
|
343
|
+
const generationNumber = 0
|
|
344
|
+
|
|
345
|
+
yield new PdfIndirectObject({
|
|
346
|
+
objectNumber,
|
|
347
|
+
generationNumber,
|
|
348
|
+
content: obj,
|
|
349
|
+
})
|
|
350
|
+
|
|
351
|
+
i++
|
|
352
|
+
} else if (obj instanceof PdfNumber) {
|
|
353
|
+
numbers.push(obj)
|
|
354
|
+
} else {
|
|
355
|
+
throw new Error('Invalid object in PDF Object Stream')
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
getObject(options: {
|
|
361
|
+
objectNumber: number
|
|
362
|
+
}): PdfIndirectObject | undefined {
|
|
363
|
+
for (const obj of this.getObjectStream()) {
|
|
364
|
+
if (obj.objectNumber === options.objectNumber) {
|
|
365
|
+
return obj
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return undefined
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
getObjects(): PdfIndirectObject[] {
|
|
372
|
+
return Array.from(this.getObjectStream())
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
clone(): this {
|
|
376
|
+
return new PdfObjStream({
|
|
377
|
+
header: this.header.clone(),
|
|
378
|
+
original: new Uint8Array(this.original),
|
|
379
|
+
}) as this
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
export class PdfXRefStreamCompressedEntry {
|
|
384
|
+
objectNumber: PdfNumber
|
|
385
|
+
objectStreamNumber: PdfNumber
|
|
386
|
+
index: PdfNumber
|
|
387
|
+
|
|
388
|
+
constructor(options: {
|
|
389
|
+
objectNumber: number | PdfNumber
|
|
390
|
+
objectStreamNumber: number | PdfNumber
|
|
391
|
+
index: number | PdfNumber
|
|
392
|
+
}) {
|
|
393
|
+
this.objectNumber =
|
|
394
|
+
options.objectNumber instanceof PdfNumber
|
|
395
|
+
? options.objectNumber
|
|
396
|
+
: new PdfNumber(options.objectNumber)
|
|
397
|
+
this.objectStreamNumber =
|
|
398
|
+
options.objectStreamNumber instanceof PdfNumber
|
|
399
|
+
? options.objectStreamNumber
|
|
400
|
+
: new PdfNumber(options.objectStreamNumber)
|
|
401
|
+
this.index =
|
|
402
|
+
options.index instanceof PdfNumber
|
|
403
|
+
? options.index
|
|
404
|
+
: new PdfNumber(options.index)
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
export type PdfXRefStreamStandardEntry = PdfXRefTableEntry
|
|
409
|
+
export const PdfXRefStreamStandardEntry = PdfXRefTableEntry
|
|
410
|
+
|
|
411
|
+
export type PdfXRefStreamEntry =
|
|
412
|
+
| PdfXRefStreamStandardEntry
|
|
413
|
+
| PdfXRefStreamCompressedEntry
|
|
414
|
+
|
|
415
|
+
export class PdfXRefStream extends PdfStream {
|
|
416
|
+
constructor(options?: {
|
|
417
|
+
header?: PdfDictionary
|
|
418
|
+
original?: ByteArray | string
|
|
419
|
+
isModified?: boolean
|
|
420
|
+
}) {
|
|
421
|
+
super({
|
|
422
|
+
header: options?.header ?? PdfXRefStream.createNewHeader(),
|
|
423
|
+
original: options?.original ?? new Uint8Array(),
|
|
424
|
+
isModified: options?.isModified,
|
|
425
|
+
})
|
|
426
|
+
|
|
427
|
+
if (!this.isType('XRef')) {
|
|
428
|
+
throw new Error('PDF XRef Stream must be of type XRef')
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
static createNewHeader(): PdfDictionary {
|
|
433
|
+
const headerDict = new PdfDictionary()
|
|
434
|
+
headerDict.set('Type', new PdfName('XRef'))
|
|
435
|
+
headerDict.set(
|
|
436
|
+
'W',
|
|
437
|
+
new PdfArray([
|
|
438
|
+
new PdfNumber(1),
|
|
439
|
+
new PdfNumber(4),
|
|
440
|
+
new PdfNumber(2),
|
|
441
|
+
]),
|
|
442
|
+
)
|
|
443
|
+
headerDict.set('Size', new PdfNumber(0))
|
|
444
|
+
|
|
445
|
+
return headerDict
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
static fromEntries(
|
|
449
|
+
entries: PdfXRefStreamEntry[],
|
|
450
|
+
headerDict: PdfDictionary = new PdfDictionary(),
|
|
451
|
+
): PdfXRefStream {
|
|
452
|
+
headerDict.delete('DecodeParms')
|
|
453
|
+
headerDict.delete('Filter')
|
|
454
|
+
headerDict.set('Type', new PdfName('XRef'))
|
|
455
|
+
entries.sort((a, b) => a.objectNumber.value - b.objectNumber.value)
|
|
456
|
+
|
|
457
|
+
const W = this.calculateW(entries)
|
|
458
|
+
headerDict.set('W', new PdfArray(W.map((w) => new PdfNumber(w))))
|
|
459
|
+
|
|
460
|
+
// Build Index array - pairs of [start, count] for each contiguous range
|
|
461
|
+
const indexArray: number[] = []
|
|
462
|
+
if (entries.length > 0) {
|
|
463
|
+
let rangeStart = entries[0].objectNumber.value
|
|
464
|
+
let rangeCount = 1
|
|
465
|
+
|
|
466
|
+
for (let i = 1; i < entries.length; i++) {
|
|
467
|
+
const currentNum = entries[i].objectNumber.value
|
|
468
|
+
const prevNum = entries[i - 1].objectNumber.value
|
|
469
|
+
|
|
470
|
+
if (currentNum === prevNum + 1) {
|
|
471
|
+
// Contiguous - extend current range
|
|
472
|
+
rangeCount++
|
|
473
|
+
} else {
|
|
474
|
+
// Gap found - save current range and start new one
|
|
475
|
+
indexArray.push(rangeStart, rangeCount)
|
|
476
|
+
rangeStart = currentNum
|
|
477
|
+
rangeCount = 1
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// Add final range
|
|
482
|
+
indexArray.push(rangeStart, rangeCount)
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
headerDict.set(
|
|
486
|
+
'Index',
|
|
487
|
+
new PdfArray(indexArray.map((num) => new PdfNumber(num))),
|
|
488
|
+
)
|
|
489
|
+
|
|
490
|
+
const size =
|
|
491
|
+
entries.length === 0
|
|
492
|
+
? 0
|
|
493
|
+
: Math.max(
|
|
494
|
+
...entries.map((entry) => entry.objectNumber.value),
|
|
495
|
+
) + 1
|
|
496
|
+
headerDict.set('Size', new PdfNumber(size))
|
|
497
|
+
|
|
498
|
+
// Encode entries to bytes
|
|
499
|
+
const entrySize = W.reduce((a, b) => a + b, 0)
|
|
500
|
+
const streamBytes = new Uint8Array(entries.length * entrySize)
|
|
501
|
+
let offset = 0
|
|
502
|
+
|
|
503
|
+
for (const entry of entries) {
|
|
504
|
+
const typeByte =
|
|
505
|
+
entry instanceof PdfXRefTableEntry ? (entry.inUse ? 1 : 0) : 2
|
|
506
|
+
|
|
507
|
+
let field1 = typeByte
|
|
508
|
+
let field2 = 0
|
|
509
|
+
let field3 = 0
|
|
510
|
+
|
|
511
|
+
if (entry instanceof PdfXRefTableEntry) {
|
|
512
|
+
field2 = entry.byteOffset.value
|
|
513
|
+
field3 = entry.generationNumber.value
|
|
514
|
+
} else if (entry instanceof PdfXRefStreamCompressedEntry) {
|
|
515
|
+
field2 = entry.objectStreamNumber.value
|
|
516
|
+
field3 = entry.index.value
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
for (let i = 0; i < W[0]; i++) {
|
|
520
|
+
streamBytes[offset++] = (field1 >> (8 * (W[0] - 1 - i))) & 0xff
|
|
521
|
+
}
|
|
522
|
+
for (let i = 0; i < W[1]; i++) {
|
|
523
|
+
streamBytes[offset++] = (field2 >> (8 * (W[1] - 1 - i))) & 0xff
|
|
524
|
+
}
|
|
525
|
+
for (let i = 0; i < W[2]; i++) {
|
|
526
|
+
streamBytes[offset++] = (field3 >> (8 * (W[2] - 1 - i))) & 0xff
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
const rawData = new Uint8Array(streamBytes)
|
|
531
|
+
headerDict.set('Length', new PdfNumber(rawData.length))
|
|
532
|
+
|
|
533
|
+
return new PdfXRefStream({
|
|
534
|
+
header: headerDict,
|
|
535
|
+
original: rawData,
|
|
536
|
+
})
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
addEntry(entry: PdfXRefStreamEntry) {
|
|
540
|
+
const entries = this.getEntries()
|
|
541
|
+
entries.push(entry)
|
|
542
|
+
|
|
543
|
+
const newXRefStream = PdfXRefStream.fromEntries(entries)
|
|
544
|
+
|
|
545
|
+
this.header = newXRefStream.header
|
|
546
|
+
this.raw = newXRefStream.raw
|
|
547
|
+
|
|
548
|
+
return this
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
private static calculateW(entries: PdfXRefStreamEntry[]): number[] {
|
|
552
|
+
let maxGeneration = 0
|
|
553
|
+
|
|
554
|
+
const maxOffset = Math.max(
|
|
555
|
+
...entries.map((entry) => {
|
|
556
|
+
let value = 0
|
|
557
|
+
|
|
558
|
+
if (entry instanceof PdfXRefTableEntry) {
|
|
559
|
+
value = entry.byteOffset.value
|
|
560
|
+
maxGeneration = Math.max(
|
|
561
|
+
maxGeneration,
|
|
562
|
+
entry.generationNumber.value,
|
|
563
|
+
)
|
|
564
|
+
} else if (entry instanceof PdfXRefStreamCompressedEntry) {
|
|
565
|
+
value = entry.objectStreamNumber.value
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
return value
|
|
569
|
+
}),
|
|
570
|
+
)
|
|
571
|
+
|
|
572
|
+
const W1 = 1 // Type byte
|
|
573
|
+
const W2 =
|
|
574
|
+
maxOffset === -1 ? 0 : Math.ceil(Math.log2(maxOffset + 1) / 8) || 1 // Offset or next free
|
|
575
|
+
const W3 = Math.ceil(Math.log2(maxGeneration + 1) / 8) || 1 // Generation number or index
|
|
576
|
+
|
|
577
|
+
return [W1, W2, W3]
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
get prev(): PdfNumber | undefined {
|
|
581
|
+
const prev = this.header.get('Prev')
|
|
582
|
+
return prev instanceof PdfNumber ? prev : undefined
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
*getEntryStream(): Generator<PdfXRefStreamEntry> {
|
|
586
|
+
const data = this.decode()
|
|
587
|
+
|
|
588
|
+
const header = this.header
|
|
589
|
+
const W = header
|
|
590
|
+
.get('W')
|
|
591
|
+
?.as(PdfArray<PdfNumber>)
|
|
592
|
+
?.items?.map((v: any) => v.value)
|
|
593
|
+
|
|
594
|
+
if (!W) throw new Error('Missing W entry in XRef stream')
|
|
595
|
+
|
|
596
|
+
if (W.length !== 3) {
|
|
597
|
+
throw new Error(
|
|
598
|
+
'Invalid W entry in XRef stream. Expected array of 3 numbers.',
|
|
599
|
+
)
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
const entrySize = W[0] + W[1] + W[2]
|
|
603
|
+
|
|
604
|
+
const Index = header
|
|
605
|
+
.get('Index')
|
|
606
|
+
?.as(PdfArray<PdfNumber>)
|
|
607
|
+
?.items?.map((v) => v.value)
|
|
608
|
+
|
|
609
|
+
const Size = header.get('Size')!.as(PdfNumber).value
|
|
610
|
+
|
|
611
|
+
const objectRanges: [number, number][] = Index
|
|
612
|
+
? Array.from({ length: Index.length / 2 }, (_, i) => [
|
|
613
|
+
Index[i * 2],
|
|
614
|
+
Index[i * 2 + 1],
|
|
615
|
+
])
|
|
616
|
+
: [[0, Size]]
|
|
617
|
+
|
|
618
|
+
const expectedLength =
|
|
619
|
+
objectRanges.reduce((sum, [, count]) => sum + count, 0) * entrySize
|
|
620
|
+
if (data.length < expectedLength) {
|
|
621
|
+
throw new Error(
|
|
622
|
+
`XRef stream too short: expected ${expectedLength} bytes, got ${data.length}`,
|
|
623
|
+
)
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
let offset = 0
|
|
627
|
+
|
|
628
|
+
for (const [startObj, count] of objectRanges) {
|
|
629
|
+
for (let i = 0; i < count; i++) {
|
|
630
|
+
const objectNumber = startObj + i
|
|
631
|
+
|
|
632
|
+
const type = this.readInt(data, offset, W[0])
|
|
633
|
+
offset += W[0]
|
|
634
|
+
const field2 = this.readInt(data, offset, W[1])
|
|
635
|
+
offset += W[1]
|
|
636
|
+
const field3 = this.readInt(data, offset, W[2])
|
|
637
|
+
offset += W[2]
|
|
638
|
+
|
|
639
|
+
let entry: PdfXRefStreamEntry
|
|
640
|
+
if (type === 0) {
|
|
641
|
+
entry = new PdfXRefTableEntry({
|
|
642
|
+
objectNumber,
|
|
643
|
+
generationNumber: field3,
|
|
644
|
+
byteOffset: field2,
|
|
645
|
+
inUse: false,
|
|
646
|
+
})
|
|
647
|
+
} else if (type === 1) {
|
|
648
|
+
entry = new PdfXRefTableEntry({
|
|
649
|
+
objectNumber,
|
|
650
|
+
generationNumber: field3,
|
|
651
|
+
byteOffset: field2,
|
|
652
|
+
inUse: true,
|
|
653
|
+
})
|
|
654
|
+
} else if (type === 2) {
|
|
655
|
+
entry = new PdfXRefStreamCompressedEntry({
|
|
656
|
+
objectNumber,
|
|
657
|
+
objectStreamNumber: field2,
|
|
658
|
+
index: field3,
|
|
659
|
+
})
|
|
660
|
+
} else {
|
|
661
|
+
throw new Error(`Unknown xref entry type: ${type}`)
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
yield entry
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
getEntries(): PdfXRefStreamEntry[] {
|
|
670
|
+
return Array.from(this.getEntryStream())
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
private readInt(data: ByteArray, offset: number, length: number): number {
|
|
674
|
+
let value = 0
|
|
675
|
+
for (let i = 0; i < length; i++) {
|
|
676
|
+
value = (value << 8) | data[offset + i]
|
|
677
|
+
}
|
|
678
|
+
return value
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
clone(): this {
|
|
682
|
+
return new PdfXRefStream({
|
|
683
|
+
header: this.header.clone(),
|
|
684
|
+
original: new Uint8Array(this.original),
|
|
685
|
+
}) as this
|
|
686
|
+
}
|
|
687
|
+
}
|