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.
Files changed (206) hide show
  1. package/.commitlintrc.cjs +25 -0
  2. package/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
  3. package/.github/ISSUE_TEMPLATE/feature_request.md +19 -0
  4. package/.github/workflows/docs.yaml +93 -0
  5. package/.github/workflows/prepare-release.yaml +79 -0
  6. package/.github/workflows/release.yaml +80 -0
  7. package/.github/workflows/test.yaml +35 -0
  8. package/.husky/commit-msg +1 -0
  9. package/.husky/pre-commit +1 -0
  10. package/.prettierignore +4 -0
  11. package/.prettierrc +4 -0
  12. package/CONTRIBUTING.md +109 -0
  13. package/EXAMPLES.md +1515 -0
  14. package/LICENSE +21 -0
  15. package/README.md +285 -0
  16. package/examples/001-create-pdf.ts +112 -0
  17. package/examples/002-create-encrypted-pdf.ts +121 -0
  18. package/examples/003-sign-pdf.ts +347 -0
  19. package/examples/004-incremental-update.ts +206 -0
  20. package/examples/005-modify-acroform.ts +374 -0
  21. package/examples/006-tokeniser-example.ts +131 -0
  22. package/examples/007-decoder-example.ts +197 -0
  23. package/package.json +72 -0
  24. package/packages/pdf-lite/README.md +3 -0
  25. package/packages/pdf-lite/package.json +68 -0
  26. package/packages/pdf-lite/scripts/create-encryption-tests.sh +41 -0
  27. package/packages/pdf-lite/scripts/gen-signing-keys.sh +290 -0
  28. package/packages/pdf-lite/scripts/generate-all-signing-keys.sh +70 -0
  29. package/packages/pdf-lite/src/core/decoder.ts +454 -0
  30. package/packages/pdf-lite/src/core/generators.ts +128 -0
  31. package/packages/pdf-lite/src/core/incremental-parser.ts +221 -0
  32. package/packages/pdf-lite/src/core/index.ts +2 -0
  33. package/packages/pdf-lite/src/core/objects/pdf-array.ts +54 -0
  34. package/packages/pdf-lite/src/core/objects/pdf-boolean.ts +19 -0
  35. package/packages/pdf-lite/src/core/objects/pdf-comment.ts +50 -0
  36. package/packages/pdf-lite/src/core/objects/pdf-date.ts +74 -0
  37. package/packages/pdf-lite/src/core/objects/pdf-dictionary.ts +171 -0
  38. package/packages/pdf-lite/src/core/objects/pdf-hexadecimal.ts +54 -0
  39. package/packages/pdf-lite/src/core/objects/pdf-indirect-object.ts +137 -0
  40. package/packages/pdf-lite/src/core/objects/pdf-name.ts +19 -0
  41. package/packages/pdf-lite/src/core/objects/pdf-null.ts +15 -0
  42. package/packages/pdf-lite/src/core/objects/pdf-number.ts +98 -0
  43. package/packages/pdf-lite/src/core/objects/pdf-object-reference.ts +30 -0
  44. package/packages/pdf-lite/src/core/objects/pdf-object.ts +107 -0
  45. package/packages/pdf-lite/src/core/objects/pdf-start-xref.ts +39 -0
  46. package/packages/pdf-lite/src/core/objects/pdf-stream.ts +687 -0
  47. package/packages/pdf-lite/src/core/objects/pdf-string.ts +38 -0
  48. package/packages/pdf-lite/src/core/objects/pdf-trailer.ts +57 -0
  49. package/packages/pdf-lite/src/core/objects/pdf-xref-table.ts +264 -0
  50. package/packages/pdf-lite/src/core/parser.ts +22 -0
  51. package/packages/pdf-lite/src/core/ref.ts +102 -0
  52. package/packages/pdf-lite/src/core/serializer.ts +68 -0
  53. package/packages/pdf-lite/src/core/streams/object-stream.ts +20 -0
  54. package/packages/pdf-lite/src/core/tokeniser.ts +687 -0
  55. package/packages/pdf-lite/src/core/tokens/boolean-token.ts +20 -0
  56. package/packages/pdf-lite/src/core/tokens/byte-offset-token.ts +20 -0
  57. package/packages/pdf-lite/src/core/tokens/comment-token.ts +32 -0
  58. package/packages/pdf-lite/src/core/tokens/end-array-token.ts +10 -0
  59. package/packages/pdf-lite/src/core/tokens/end-dictionary-token.ts +10 -0
  60. package/packages/pdf-lite/src/core/tokens/end-object-token.ts +10 -0
  61. package/packages/pdf-lite/src/core/tokens/end-stream-token.ts +11 -0
  62. package/packages/pdf-lite/src/core/tokens/hexadecimal-token.ts +22 -0
  63. package/packages/pdf-lite/src/core/tokens/name-token.ts +19 -0
  64. package/packages/pdf-lite/src/core/tokens/null-token.ts +9 -0
  65. package/packages/pdf-lite/src/core/tokens/number-token.ts +164 -0
  66. package/packages/pdf-lite/src/core/tokens/object-reference-token.ts +24 -0
  67. package/packages/pdf-lite/src/core/tokens/start-array-token.ts +10 -0
  68. package/packages/pdf-lite/src/core/tokens/start-dictionary-token.ts +10 -0
  69. package/packages/pdf-lite/src/core/tokens/start-object-token.ts +28 -0
  70. package/packages/pdf-lite/src/core/tokens/start-stream-token.ts +52 -0
  71. package/packages/pdf-lite/src/core/tokens/start-xref-token.ts +10 -0
  72. package/packages/pdf-lite/src/core/tokens/stream-chunk-token.ts +8 -0
  73. package/packages/pdf-lite/src/core/tokens/string-token.ts +17 -0
  74. package/packages/pdf-lite/src/core/tokens/token.ts +43 -0
  75. package/packages/pdf-lite/src/core/tokens/trailer-token.ts +12 -0
  76. package/packages/pdf-lite/src/core/tokens/whitespace-token.ts +43 -0
  77. package/packages/pdf-lite/src/core/tokens/xref-table-entry-token.ts +65 -0
  78. package/packages/pdf-lite/src/core/tokens/xref-table-section-start-token.ts +31 -0
  79. package/packages/pdf-lite/src/core/tokens/xref-table-start-token.ts +13 -0
  80. package/packages/pdf-lite/src/crypto/ciphers/aes128.ts +63 -0
  81. package/packages/pdf-lite/src/crypto/ciphers/aes256.ts +50 -0
  82. package/packages/pdf-lite/src/crypto/ciphers/rc4.ts +82 -0
  83. package/packages/pdf-lite/src/crypto/constants.ts +10 -0
  84. package/packages/pdf-lite/src/crypto/key-derivation/key-derivation-aes256.ts +213 -0
  85. package/packages/pdf-lite/src/crypto/key-derivation/key-derivation.ts +122 -0
  86. package/packages/pdf-lite/src/crypto/key-gen/key-gen-aes256.ts +79 -0
  87. package/packages/pdf-lite/src/crypto/key-gen/key-gen-rc4-128.ts +190 -0
  88. package/packages/pdf-lite/src/crypto/key-gen/key-gen-rc4-40.ts +129 -0
  89. package/packages/pdf-lite/src/crypto/types.ts +6 -0
  90. package/packages/pdf-lite/src/crypto/utils.ts +81 -0
  91. package/packages/pdf-lite/src/filters/ascii85.ts +128 -0
  92. package/packages/pdf-lite/src/filters/asciihex.ts +55 -0
  93. package/packages/pdf-lite/src/filters/flate.ts +39 -0
  94. package/packages/pdf-lite/src/filters/lzw.ts +144 -0
  95. package/packages/pdf-lite/src/filters/pass-through.ts +37 -0
  96. package/packages/pdf-lite/src/filters/runlength.ts +92 -0
  97. package/packages/pdf-lite/src/filters/types.ts +21 -0
  98. package/packages/pdf-lite/src/index.ts +4 -0
  99. package/packages/pdf-lite/src/pdf/errors.ts +5 -0
  100. package/packages/pdf-lite/src/pdf/index.ts +4 -0
  101. package/packages/pdf-lite/src/pdf/pdf-document.ts +924 -0
  102. package/packages/pdf-lite/src/pdf/pdf-reader.ts +57 -0
  103. package/packages/pdf-lite/src/pdf/pdf-revision.ts +234 -0
  104. package/packages/pdf-lite/src/pdf/pdf-xref-lookup.ts +527 -0
  105. package/packages/pdf-lite/src/security/crypt-filters/aesv2.ts +58 -0
  106. package/packages/pdf-lite/src/security/crypt-filters/aesv3.ts +56 -0
  107. package/packages/pdf-lite/src/security/crypt-filters/base.ts +140 -0
  108. package/packages/pdf-lite/src/security/crypt-filters/identity.ts +40 -0
  109. package/packages/pdf-lite/src/security/crypt-filters/v2.ts +59 -0
  110. package/packages/pdf-lite/src/security/handlers/base.ts +625 -0
  111. package/packages/pdf-lite/src/security/handlers/pubSec.ts +413 -0
  112. package/packages/pdf-lite/src/security/handlers/utils.ts +304 -0
  113. package/packages/pdf-lite/src/security/handlers/v1.ts +225 -0
  114. package/packages/pdf-lite/src/security/handlers/v2.ts +128 -0
  115. package/packages/pdf-lite/src/security/handlers/v4.ts +379 -0
  116. package/packages/pdf-lite/src/security/handlers/v5.ts +298 -0
  117. package/packages/pdf-lite/src/security/types.ts +158 -0
  118. package/packages/pdf-lite/src/signing/document-security-store.ts +224 -0
  119. package/packages/pdf-lite/src/signing/index.ts +3 -0
  120. package/packages/pdf-lite/src/signing/signatures/adbe-pkcs7-detached.ts +154 -0
  121. package/packages/pdf-lite/src/signing/signatures/adbe-pkcs7-sha1.ts +161 -0
  122. package/packages/pdf-lite/src/signing/signatures/adbe-x509-rsa-sha1.ts +106 -0
  123. package/packages/pdf-lite/src/signing/signatures/base.ts +229 -0
  124. package/packages/pdf-lite/src/signing/signatures/etsi-cades-detached.ts +229 -0
  125. package/packages/pdf-lite/src/signing/signatures/etsi-rfc3161.ts +92 -0
  126. package/packages/pdf-lite/src/signing/signatures/index.ts +6 -0
  127. package/packages/pdf-lite/src/signing/signer.ts +120 -0
  128. package/packages/pdf-lite/src/signing/types.ts +86 -0
  129. package/packages/pdf-lite/src/signing/utils.ts +71 -0
  130. package/packages/pdf-lite/src/types.ts +44 -0
  131. package/packages/pdf-lite/src/utils/IterableReadableStream.ts +30 -0
  132. package/packages/pdf-lite/src/utils/algos.ts +446 -0
  133. package/packages/pdf-lite/src/utils/assert.ts +42 -0
  134. package/packages/pdf-lite/src/utils/bytesToHex.ts +18 -0
  135. package/packages/pdf-lite/src/utils/bytesToHexBytes.ts +27 -0
  136. package/packages/pdf-lite/src/utils/bytesToString.ts +17 -0
  137. package/packages/pdf-lite/src/utils/concatUint8Arrays.ts +26 -0
  138. package/packages/pdf-lite/src/utils/escapeString.ts +49 -0
  139. package/packages/pdf-lite/src/utils/hexBytesToBytes.ts +22 -0
  140. package/packages/pdf-lite/src/utils/hexBytesToString.ts +21 -0
  141. package/packages/pdf-lite/src/utils/hexToBytes.ts +18 -0
  142. package/packages/pdf-lite/src/utils/padBytes.ts +25 -0
  143. package/packages/pdf-lite/src/utils/predictors.ts +332 -0
  144. package/packages/pdf-lite/src/utils/replaceInBuffer.ts +56 -0
  145. package/packages/pdf-lite/src/utils/stringToBytes.ts +22 -0
  146. package/packages/pdf-lite/src/utils/stringToHexBytes.ts +23 -0
  147. package/packages/pdf-lite/src/utils/unescapeString.ts +123 -0
  148. package/packages/pdf-lite/test/acceptance/__snapshots__/versions.node.test.ts.snap +60766 -0
  149. package/packages/pdf-lite/test/acceptance/fixtures/1.3/basic.pdf +0 -0
  150. package/packages/pdf-lite/test/acceptance/fixtures/1.4/basic-aes-128.pdf +0 -0
  151. package/packages/pdf-lite/test/acceptance/fixtures/1.4/basic-aes-256.pdf +0 -0
  152. package/packages/pdf-lite/test/acceptance/fixtures/1.4/basic-rc4-128.pdf +0 -0
  153. package/packages/pdf-lite/test/acceptance/fixtures/1.4/basic-rc4-40.pdf +0 -0
  154. package/packages/pdf-lite/test/acceptance/fixtures/1.4/basic.pdf +0 -0
  155. package/packages/pdf-lite/test/acceptance/fixtures/1.5/basic.pdf +0 -0
  156. package/packages/pdf-lite/test/acceptance/fixtures/1.6/basic.pdf +0 -0
  157. package/packages/pdf-lite/test/acceptance/fixtures/1.7/basic.pdf +0 -0
  158. package/packages/pdf-lite/test/acceptance/fixtures/2.0/basic-aes-128.pdf +43 -0
  159. package/packages/pdf-lite/test/acceptance/fixtures/2.0/basic-aes-256.pdf +43 -0
  160. package/packages/pdf-lite/test/acceptance/fixtures/2.0/basic-rc4-128.pdf +43 -0
  161. package/packages/pdf-lite/test/acceptance/fixtures/2.0/basic-rc4-40.pdf +44 -0
  162. package/packages/pdf-lite/test/acceptance/fixtures/2.0/basic.pdf +79 -0
  163. package/packages/pdf-lite/test/acceptance/versions.node.test.ts +41 -0
  164. package/packages/pdf-lite/test/unit/__snapshots__/decoder.node.test.ts.snap +86947 -0
  165. package/packages/pdf-lite/test/unit/__snapshots__/tokeniser.node.test.ts.snap +131829 -0
  166. package/packages/pdf-lite/test/unit/ciphers.test.ts +61 -0
  167. package/packages/pdf-lite/test/unit/decoder.node.test.ts +21 -0
  168. package/packages/pdf-lite/test/unit/decoder.test.ts +567 -0
  169. package/packages/pdf-lite/test/unit/filters.test.ts +67 -0
  170. package/packages/pdf-lite/test/unit/fixtures/basic.pdf +0 -0
  171. package/packages/pdf-lite/test/unit/fixtures/encrypted_v1/basic-aes-128.pdf +0 -0
  172. package/packages/pdf-lite/test/unit/fixtures/encrypted_v1/basic-aes-256.pdf +0 -0
  173. package/packages/pdf-lite/test/unit/fixtures/encrypted_v1/basic-rc4-128.pdf +0 -0
  174. package/packages/pdf-lite/test/unit/fixtures/encrypted_v1/basic-rc4-40.pdf +43 -0
  175. package/packages/pdf-lite/test/unit/fixtures/protectedAdobeLivecycle.pdf +0 -0
  176. package/packages/pdf-lite/test/unit/fixtures/rsa-2048/index.ts +187 -0
  177. package/packages/pdf-lite/test/unit/fixtures/template.pdf +0 -0
  178. package/packages/pdf-lite/test/unit/incremental-update.test.ts +0 -0
  179. package/packages/pdf-lite/test/unit/objects.test.ts +0 -0
  180. package/packages/pdf-lite/test/unit/pdf-document-signing.test.ts +0 -0
  181. package/packages/pdf-lite/test/unit/pdf-revision.test.ts +195 -0
  182. package/packages/pdf-lite/test/unit/pdf.browser.test.ts +0 -0
  183. package/packages/pdf-lite/test/unit/predictors.test.ts +226 -0
  184. package/packages/pdf-lite/test/unit/ref.test.ts +158 -0
  185. package/packages/pdf-lite/test/unit/security-handlers.test.ts +645 -0
  186. package/packages/pdf-lite/test/unit/serializer.test.ts +81 -0
  187. package/packages/pdf-lite/test/unit/signature-objects.test.ts +814 -0
  188. package/packages/pdf-lite/test/unit/string-escaping.test.ts +84 -0
  189. package/packages/pdf-lite/test/unit/tokeniser.node.test.ts +38 -0
  190. package/packages/pdf-lite/test/unit/tokeniser.test.ts +1213 -0
  191. package/packages/pdf-lite/test/unit/utils.test.ts +248 -0
  192. package/packages/pdf-lite/test/unit/xref-lookup.test.ts +72 -0
  193. package/packages/pdf-lite/tsconfig.json +4 -0
  194. package/packages/pdf-lite/tsconfig.prod.json +8 -0
  195. package/packages/pdf-lite/typedoc.json +14 -0
  196. package/packages/pdf-lite/vitest.config.ts +43 -0
  197. package/pnpm-workspace.yaml +2 -0
  198. package/renovate.json +34 -0
  199. package/scripts/build-examples.ts +30 -0
  200. package/scripts/bump-version.sh +56 -0
  201. package/scripts/gen-html-docs.sh +21 -0
  202. package/scripts/gen-md-docs.sh +15 -0
  203. package/scripts/prepare-release.sh +33 -0
  204. package/tsconfig.json +22 -0
  205. package/tsconfig.prod.json +12 -0
  206. package/typedoc.json +34 -0
@@ -0,0 +1,57 @@
1
+ import { PdfObject } from '../core/objects/pdf-object'
2
+ import { PdfObjectStream } from '../core/streams/object-stream'
3
+ import { ByteArray } from '../types'
4
+ import { PdfDocument } from './pdf-document'
5
+
6
+ /**
7
+ * A reader for parsing PDF data into PdfDocument instances.
8
+ * Processes streams of PDF objects and constructs documents from them.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * // Read PDF from file bytes
13
+ * const document = await PdfReader.fromBytes(fileBytes)
14
+ * ```
15
+ */
16
+ export class PdfReader {
17
+ /** The stream of PDF objects to read from */
18
+ protected objectStream: AsyncIterable<PdfObject> | Iterable<PdfObject>
19
+
20
+ /**
21
+ * Creates a new PdfReader instance.
22
+ *
23
+ * @param objectStream - An async or sync iterable of PDF objects
24
+ */
25
+ constructor(objectStream: AsyncIterable<PdfObject> | Iterable<PdfObject>) {
26
+ this.objectStream = objectStream
27
+ }
28
+
29
+ /**
30
+ * Reads all objects from the stream and constructs a PdfDocument.
31
+ *
32
+ * @returns A promise that resolves to the parsed PdfDocument
33
+ */
34
+ async read(): Promise<PdfDocument> {
35
+ const objects: PdfObject[] = []
36
+
37
+ for await (const obj of this.objectStream) {
38
+ objects.push(obj)
39
+ }
40
+
41
+ return PdfDocument.fromObjects(objects)
42
+ }
43
+
44
+ /**
45
+ * Creates a PdfDocument directly from a byte stream.
46
+ * Convenience method that creates a reader internally.
47
+ *
48
+ * @param input - Async or sync iterable of byte arrays
49
+ * @returns A promise that resolves to the parsed PdfDocument
50
+ */
51
+ static async fromBytes(
52
+ input: AsyncIterable<ByteArray> | Iterable<ByteArray>,
53
+ ): Promise<PdfDocument> {
54
+ const reader = new PdfReader(new PdfObjectStream(input))
55
+ return reader.read()
56
+ }
57
+ }
@@ -0,0 +1,234 @@
1
+ import { PdfDictionary } from '../core/objects/pdf-dictionary'
2
+ import { PdfIndirectObject } from '../core/objects/pdf-indirect-object'
3
+ import { PdfObject } from '../core/objects/pdf-object'
4
+ import { PdfTrailerEntries } from '../core/objects/pdf-trailer'
5
+ import { PdfToken } from '../core/tokens/token'
6
+ import { PdfWhitespaceToken } from '../core/tokens/whitespace-token'
7
+ import { PdfXrefLookup } from './pdf-xref-lookup'
8
+
9
+ /**
10
+ * Represents a single revision of a PDF document.
11
+ * PDF documents can have multiple revisions for incremental updates,
12
+ * where each revision contains its own set of objects and cross-reference table.
13
+ */
14
+ export class PdfRevision extends PdfObject {
15
+ /** Objects contained in this revision */
16
+ objects: PdfObject[] = []
17
+ /** Cross-reference lookup table for this revision */
18
+ xref: PdfXrefLookup
19
+ /** Whether this revision is locked (cannot be modified) */
20
+ locked: boolean = false
21
+
22
+ /**
23
+ * Creates a new PDF revision.
24
+ *
25
+ * @param options - Configuration options for the revision
26
+ * @param options.objects - Initial objects for this revision
27
+ * @param options.prev - Previous revision or xref lookup to link to
28
+ * @param options.locked - Whether the revision should be locked initially
29
+ */
30
+ constructor(options?: {
31
+ objects?: PdfObject[]
32
+ prev?: PdfXrefLookup | PdfRevision
33
+ locked?: boolean
34
+ }) {
35
+ super()
36
+ this.modified = false
37
+ this.objects = options?.objects ?? []
38
+
39
+ this.xref = PdfXrefLookup.fromObjects(this.objects)
40
+
41
+ if (options?.prev) this.setPrev(options.prev)
42
+ if (!this.contains(this.xref.object))
43
+ this.addObject(...this.xref.toTrailerSection())
44
+ this.locked = options?.locked ?? false
45
+ }
46
+
47
+ /**
48
+ * Links this revision to a previous revision's cross-reference table.
49
+ *
50
+ * @param xref - The previous revision's xref lookup or revision
51
+ */
52
+ setPrev(xref: PdfXrefLookup | PdfRevision) {
53
+ xref = xref instanceof PdfRevision ? xref.xref : xref
54
+ this.xref.setPrev(xref)
55
+ }
56
+
57
+ /**
58
+ * Checks if an object reference exists in this revision.
59
+ *
60
+ * @param object - The object to check for
61
+ * @returns True if the exact object instance exists in this revision
62
+ */
63
+ contains(object: PdfObject): boolean {
64
+ return this.objects.includes(object)
65
+ }
66
+
67
+ /**
68
+ * Checks if an equivalent object exists in this revision (by value equality).
69
+ *
70
+ * @param object - The object to check for
71
+ * @returns True if an equal object exists in this revision
72
+ */
73
+ exists(object: PdfObject): boolean {
74
+ for (const obj of this.objects) {
75
+ if (obj.equals(object)) {
76
+ return true
77
+ }
78
+ }
79
+ return false
80
+ }
81
+
82
+ /**
83
+ * Adds objects to the beginning of the revision's object list.
84
+ *
85
+ * @param objects - Objects to add at the beginning
86
+ */
87
+ unshift(...objects: PdfObject[]): void {
88
+ for (const obj of objects.reverse()) {
89
+ this.objects.unshift(obj)
90
+ if (obj instanceof PdfIndirectObject) this.xref.addObject(obj)
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Adds objects to the revision.
96
+ *
97
+ * @param objects - Objects to add to the revision
98
+ */
99
+ addObject(...objects: PdfObject[]): void {
100
+ for (const obj of objects) {
101
+ this.addObjectAt(obj)
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Adds an object at a specific position in the revision.
107
+ *
108
+ * @param object - The object to add
109
+ * @param index - Position to insert at (number) or object to insert before
110
+ * @throws Error if the revision is locked or index is out of bounds
111
+ */
112
+ addObjectAt(object: PdfObject, index?: number | PdfObject): void {
113
+ if (this.locked) {
114
+ throw new Error('Cannot add object to locked PDF revision')
115
+ }
116
+
117
+ if (index === undefined) {
118
+ index =
119
+ object instanceof PdfIndirectObject
120
+ ? this.xref.object
121
+ : this.objects.length
122
+ }
123
+
124
+ if (typeof index !== 'number') {
125
+ index = this.objects.indexOf(index)
126
+
127
+ if (index === -1) {
128
+ index = this.objects.length
129
+ }
130
+ }
131
+
132
+ if (index < 0 || index > this.objects.length) {
133
+ throw new Error('Index out of bounds')
134
+ }
135
+
136
+ this.objects.splice(index, 0, object)
137
+ this.sortObjects()
138
+
139
+ if (object instanceof PdfIndirectObject) {
140
+ this.xref.addObject(object)
141
+ }
142
+
143
+ this.update()
144
+ }
145
+
146
+ /**
147
+ * Removes objects from the revision.
148
+ *
149
+ * @param objects - Objects to remove from the revision
150
+ * @throws Error if the revision is locked
151
+ */
152
+ deleteObject(...objects: PdfObject[]): void {
153
+ if (this.locked) {
154
+ throw new Error('Cannot delete object from locked PDF revision')
155
+ }
156
+
157
+ for (const object of objects) {
158
+ const index = this.objects.indexOf(object)
159
+ if (index === -1) {
160
+ return
161
+ }
162
+
163
+ this.modified = true
164
+ this.objects.splice(index, 1)
165
+
166
+ if (object instanceof PdfIndirectObject) {
167
+ this.xref.removeObject(object)
168
+ }
169
+ }
170
+ }
171
+
172
+ isModified(): boolean {
173
+ return (
174
+ super.isModified() ||
175
+ this.xref.trailerDict.isModified() ||
176
+ this.objects.some((obj) => obj.isModified())
177
+ )
178
+ }
179
+
180
+ /**
181
+ * Updates the revision by sorting objects and updating the xref table.
182
+ */
183
+ update(): void {
184
+ if (this.locked) {
185
+ return
186
+ }
187
+ this.sortObjects()
188
+ this.xref.update()
189
+ this.modified = false
190
+ }
191
+
192
+ /**
193
+ * Sorts objects by their insertion order.
194
+ * Indirect objects are placed before other objects.
195
+ */
196
+ sortObjects(): void {
197
+ this.objects.sort((a, b) => {
198
+ if (
199
+ a instanceof PdfIndirectObject &&
200
+ b instanceof PdfIndirectObject
201
+ ) {
202
+ return a.order() - b.order()
203
+ } else {
204
+ return 0
205
+ }
206
+ })
207
+ }
208
+
209
+ /**
210
+ * Gets the trailer dictionary for this revision.
211
+ *
212
+ * @returns The trailer dictionary containing document metadata references
213
+ */
214
+ get trailerDict(): PdfDictionary<PdfTrailerEntries> {
215
+ return this.xref.trailerDict
216
+ }
217
+
218
+ /**
219
+ * Creates a deep copy of this revision.
220
+ *
221
+ * @returns A cloned PdfRevision instance
222
+ */
223
+ clone(): this {
224
+ const clonedObjects = this.objects.map((obj) => obj.clone())
225
+ return new PdfRevision({ objects: clonedObjects }) as this
226
+ }
227
+
228
+ protected tokenize(): PdfToken[] {
229
+ return this.objects.flatMap((obj) => [
230
+ ...obj.toTokens(),
231
+ PdfWhitespaceToken.NEWLINE,
232
+ ])
233
+ }
234
+ }