Skip to content

Commit 6c9a44d

Browse files
committed
Add decompressing streaming impl
1 parent 762b1ed commit 6c9a44d

File tree

2 files changed

+100
-1
lines changed

2 files changed

+100
-1
lines changed

src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
pub mod stream;
2+
13
use brotli;
24
use wasm_bindgen::prelude::*;
35
use serde::{Serialize, Deserialize};
@@ -6,7 +8,7 @@ use serde::{Serialize, Deserialize};
68
#[global_allocator]
79
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
810

9-
fn set_panic_hook() {
11+
pub fn set_panic_hook() {
1012
#[cfg(feature="console_error_panic_hook")]
1113
console_error_panic_hook::set_once();
1214
}

src/stream.rs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
use crate::set_panic_hook;
2+
use brotli::enc::StandardAlloc; // Re-exported from alloc_stdlib::StandardAlloc
3+
use brotli::{BrotliDecompressStream, BrotliResult, BrotliState};
4+
use wasm_bindgen::prelude::*;
5+
6+
#[wasm_bindgen]
7+
#[repr(i32)]
8+
pub enum BrotliStreamResult {
9+
/// The stream is just initialized and no input is provided currently.
10+
/// `BrotliResult` uses `ResultFailure = 0`, but as we will convert `ResultFailure` to a negative actual error code,
11+
/// 0 is reused as no input currently.
12+
Init = 0,
13+
ResultSuccess = 1,
14+
NeedsMoreInput = 2,
15+
NeedsMoreOutput = 3,
16+
}
17+
18+
#[wasm_bindgen]
19+
pub struct CompressStream {}
20+
21+
#[wasm_bindgen]
22+
impl CompressStream {}
23+
24+
#[wasm_bindgen]
25+
pub struct DecompressStream {
26+
state: BrotliState<StandardAlloc, StandardAlloc, StandardAlloc>,
27+
result: i32,
28+
total_out: usize,
29+
}
30+
31+
#[wasm_bindgen]
32+
impl DecompressStream {
33+
#[allow(clippy::new_without_default)]
34+
#[wasm_bindgen(constructor)]
35+
pub fn new() -> Self {
36+
set_panic_hook();
37+
let alloc = StandardAlloc::default();
38+
Self {
39+
state: BrotliState::new(alloc, alloc, alloc),
40+
result: BrotliStreamResult::Init as i32,
41+
total_out: 0,
42+
}
43+
}
44+
45+
pub fn decompress(
46+
&mut self,
47+
input: Box<[u8]>,
48+
output_size: usize,
49+
) -> Result<Box<[u8]>, JsValue> {
50+
let mut output = vec![0; output_size];
51+
let mut available_in = input.len();
52+
let mut input_offset = 0;
53+
let mut available_out = output_size;
54+
let mut output_offset = 0;
55+
match BrotliDecompressStream(
56+
&mut available_in,
57+
&mut input_offset,
58+
&input,
59+
&mut available_out,
60+
&mut output_offset,
61+
&mut output,
62+
&mut self.total_out,
63+
&mut self.state,
64+
) {
65+
BrotliResult::ResultFailure => {
66+
// It should be a negative error code
67+
self.result = self.state.error_code as i32;
68+
Err(JsValue::from_str(&format!(
69+
"Brotli streaming decompress failed: Error code {}",
70+
self.result
71+
)))
72+
}
73+
BrotliResult::NeedsMoreOutput => {
74+
self.result = BrotliStreamResult::NeedsMoreOutput as i32;
75+
Ok(output.into_boxed_slice())
76+
}
77+
BrotliResult::ResultSuccess => {
78+
output.truncate(output_offset);
79+
self.result = BrotliStreamResult::ResultSuccess as i32;
80+
Ok(output.into_boxed_slice())
81+
}
82+
BrotliResult::NeedsMoreInput => {
83+
output.truncate(output_offset);
84+
self.result = BrotliStreamResult::NeedsMoreInput as i32;
85+
Ok(output.into_boxed_slice())
86+
}
87+
}
88+
}
89+
90+
pub fn total_out(&self) -> usize {
91+
self.total_out
92+
}
93+
94+
pub fn result(&self) -> i32 {
95+
self.result
96+
}
97+
}

0 commit comments

Comments
 (0)