mirror of
https://github.com/mozilla/pdf.js.git
synced 2026-04-10 15:24:03 +02:00
For now, `BrotliDecode` hasn't been specified but it should be in a close future. So when it's possible we use the native `DecompressionStream` API with "brotli" as argument. If that fails or if we've to decompress in a sync context, we fallback to `BrotliStream` which a pure js implementation (see README in external/brotli).
87 lines
2.3 KiB
JavaScript
87 lines
2.3 KiB
JavaScript
/* Copyright 2026 Mozilla Foundation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
import { BrotliDecode } from "../../external/brotli/decode.js";
|
|
import { DecodeStream } from "./decode_stream.js";
|
|
import { Stream } from "./stream.js";
|
|
|
|
class BrotliStream extends DecodeStream {
|
|
#isAsync = true;
|
|
|
|
constructor(stream, maybeLength) {
|
|
super(maybeLength);
|
|
|
|
this.stream = stream;
|
|
this.dict = stream.dict;
|
|
}
|
|
|
|
readBlock() {
|
|
// TODO: add some telemetry to measure how often we fallback here.
|
|
// Get all bytes from the input stream
|
|
const bytes = this.stream.getBytes();
|
|
const decodedData = BrotliDecode(
|
|
new Int8Array(bytes.buffer, bytes.byteOffset, bytes.length)
|
|
);
|
|
|
|
this.buffer = new Uint8Array(
|
|
decodedData.buffer,
|
|
decodedData.byteOffset,
|
|
decodedData.length
|
|
);
|
|
this.bufferLength = this.buffer.length;
|
|
this.eof = true;
|
|
}
|
|
|
|
async getImageData(length, _decoderOptions) {
|
|
const data = await this.asyncGetBytes();
|
|
if (!data) {
|
|
return this.getBytes(length);
|
|
}
|
|
if (data.length <= length) {
|
|
return data;
|
|
}
|
|
return data.subarray(0, length);
|
|
}
|
|
|
|
async asyncGetBytes() {
|
|
const { decompressed, compressed } =
|
|
await this.asyncGetBytesFromDecompressionStream("brotli");
|
|
if (decompressed) {
|
|
return decompressed;
|
|
}
|
|
// DecompressionStream failed (for example because there are some extra
|
|
// bytes after the end of the compressed data), so we fallback to our
|
|
// decoder.
|
|
// We already get the bytes from the underlying stream, so we just reuse
|
|
// them to avoid get them again.
|
|
|
|
this.#isAsync = false;
|
|
this.stream = new Stream(
|
|
compressed,
|
|
0,
|
|
compressed.length,
|
|
this.stream.dict
|
|
);
|
|
this.reset();
|
|
return null;
|
|
}
|
|
|
|
get isAsync() {
|
|
return this.#isAsync;
|
|
}
|
|
}
|
|
|
|
export { BrotliStream };
|