* Copy a stream reference, handling circular references and encryption.
(key: string, srcStream: PdfStream)
| 246 | * Copy a stream reference, handling circular references and encryption. |
| 247 | */ |
| 248 | private copyStreamRef(key: string, srcStream: PdfStream): PdfRef { |
| 249 | const sourceWasEncrypted = this.source.isEncrypted; |
| 250 | |
| 251 | // Clone the stream's dictionary |
| 252 | const clonedDict = srcStream.clone(); |
| 253 | |
| 254 | // Get stream data based on encryption state |
| 255 | let streamData: Uint8Array; |
| 256 | |
| 257 | if (!sourceWasEncrypted) { |
| 258 | // Source wasn't encrypted - copy raw encoded bytes directly |
| 259 | streamData = srcStream.data; |
| 260 | } else { |
| 261 | // Source was encrypted - decode and re-encode |
| 262 | // Wrap in try/catch since decoding may fail for corrupt streams |
| 263 | try { |
| 264 | const decodedData = srcStream.getDecodedData(); |
| 265 | const filterEntry = srcStream.get("Filter"); |
| 266 | |
| 267 | if (filterEntry) { |
| 268 | try { |
| 269 | const filterSpecs = this.buildFilterSpecs(srcStream); |
| 270 | |
| 271 | streamData = FilterPipeline.encode(decodedData, filterSpecs); |
| 272 | |
| 273 | clonedDict.set("Length", PdfNumber.of(streamData.length)); |
| 274 | } catch (error) { |
| 275 | console.warn(`Could not re-encode stream ${key}, will use uncompressed data`); |
| 276 | console.warn(error); |
| 277 | |
| 278 | // If re-encoding fails, store uncompressed |
| 279 | clonedDict.delete("Filter"); |
| 280 | clonedDict.delete("DecodeParms"); |
| 281 | |
| 282 | streamData = decodedData; |
| 283 | |
| 284 | clonedDict.set("Length", PdfNumber.of(streamData.length)); |
| 285 | } |
| 286 | } else { |
| 287 | streamData = decodedData; |
| 288 | clonedDict.set("Length", PdfNumber.of(streamData.length)); |
| 289 | } |
| 290 | } catch (error) { |
| 291 | console.warn(`Could not decode stream ${key}, will use raw data`); |
| 292 | console.warn(error); |
| 293 | |
| 294 | // If decoding fails entirely, try to copy raw bytes as fallback |
| 295 | // Clear filters since we can't guarantee the data is properly encoded |
| 296 | clonedDict.delete("Filter"); |
| 297 | clonedDict.delete("DecodeParms"); |
| 298 | |
| 299 | streamData = srcStream.data; |
| 300 | |
| 301 | clonedDict.set("Length", PdfNumber.of(streamData.length)); |
| 302 | } |
| 303 | } |
| 304 | |
| 305 | // Create the stream with data |
no test coverage detected