1use crate::utils::module::{export_default, ModuleInfo};
4use rquickjs::{
5 function::Func,
6 module::{Declarations, Exports, ModuleDef},
7 Ctx, Result,
8};
9
10mod brotli;
11mod codec;
12mod zstd;
13
14use std::io::Read;
15
16use crate::utils::object::ObjectExt;
17use rquickjs::{prelude::Opt, Exception, Value};
18
19pub(crate) fn max_output_length<'js>(options: &Opt<Value<'js>>) -> Result<Option<usize>> {
22 match options.0.as_ref() {
23 Some(options) => options.get_optional::<_, usize>("maxOutputLength"),
24 None => Ok(None),
25 }
26}
27
28pub(crate) fn read_to_end_limited<R: Read>(
34 ctx: &Ctx<'_>,
35 reader: R,
36 limit: Option<usize>,
37 capacity: usize,
38) -> Result<Vec<u8>> {
39 let Some(limit) = limit else {
40 let mut dst = Vec::with_capacity(capacity);
41 let mut reader = reader;
42 reader.read_to_end(&mut dst)?;
43 return Ok(dst);
44 };
45
46 let cutoff = limit.saturating_add(1);
47 let mut dst = Vec::with_capacity(capacity.min(cutoff));
48 reader.take(cutoff as u64).read_to_end(&mut dst)?;
49
50 if dst.len() > limit {
51 return Err(Exception::throw_range(
52 ctx,
53 &[
54 "Cannot create a Buffer larger than ",
55 &limit.to_string(),
56 " bytes",
57 ]
58 .concat(),
59 ));
60 }
61
62 Ok(dst)
63}
64
65use self::brotli::{br_comp, br_comp_sync, br_decomp, br_decomp_sync};
66use self::codec::{
67 deflate, deflate_raw, deflate_raw_sync, deflate_sync, gunzip, gunzip_sync, gzip, gzip_sync,
68 inflate, inflate_raw, inflate_raw_sync, inflate_sync,
69};
70use self::zstd::{zstd_comp, zstd_comp_sync, zstd_decomp, zstd_decomp_sync};
71
72#[macro_export]
73macro_rules! define_sync_function {
74 ($fn_name:ident, $converter:expr, $command:expr) => {
75 pub(crate) fn $fn_name<'js>(
76 ctx: Ctx<'js>,
77 value: ObjectBytes<'js>,
78 options: Opt<Value<'js>>,
79 ) -> Result<Value<'js>> {
80 $converter(ctx.clone(), value, options, $command)
81 }
82 };
83}
84
85#[macro_export]
86macro_rules! define_cb_function {
87 ($fn_name:ident, $converter:expr, $command:expr) => {
88 pub(crate) fn $fn_name<'js>(
89 ctx: Ctx<'js>,
90 value: ObjectBytes<'js>,
91 args: Rest<Value<'js>>,
92 ) -> Result<()> {
93 let mut args_iter = args.0.into_iter().rev();
94 let cb: Function = args_iter
95 .next()
96 .and_then(|v| v.into_function())
97 .or_throw_msg(&ctx, "Callback parameter is not a function")?;
98 let options = match args_iter.next() {
99 Some(v) => Opt(Some(v)),
100 None => Opt(None),
101 };
102
103 ctx.clone().spawn_exit(async move {
104 match $converter(ctx.clone(), value, options, $command) {
105 Ok(obj) => {
106 () = cb.call((Null.into_js(&ctx), obj))?;
107 Ok::<_, Error>(())
108 },
109 Err(err) => {
110 let err = if matches!(err, Error::Exception) {
113 ctx.catch()
114 } else {
115 Exception::from_message(ctx.clone(), &err.to_string())?.into_value()
116 };
117 () = cb.call((err,))?;
118 Ok(())
119 },
120 }
121 })?;
122 Ok(())
123 }
124 };
125}
126pub struct ZlibModule;
127
128impl ModuleDef for ZlibModule {
129 fn declare(declare: &Declarations) -> Result<()> {
130 declare.declare("deflate")?;
131 declare.declare("deflateSync")?;
132
133 declare.declare("deflateRaw")?;
134 declare.declare("deflateRawSync")?;
135
136 declare.declare("gzip")?;
137 declare.declare("gzipSync")?;
138
139 declare.declare("inflate")?;
140 declare.declare("inflateSync")?;
141
142 declare.declare("inflateRaw")?;
143 declare.declare("inflateRawSync")?;
144
145 declare.declare("gunzip")?;
146 declare.declare("gunzipSync")?;
147
148 declare.declare("brotliCompress")?;
149 declare.declare("brotliCompressSync")?;
150
151 declare.declare("brotliDecompress")?;
152 declare.declare("brotliDecompressSync")?;
153
154 declare.declare("zstdCompress")?;
155 declare.declare("zstdCompressSync")?;
156
157 declare.declare("zstdDecompress")?;
158 declare.declare("zstdDecompressSync")?;
159
160 declare.declare("default")?;
161 Ok(())
162 }
163
164 fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {
165 export_default(ctx, exports, |default| {
166 default.set("deflate", Func::from(deflate))?;
167 default.set("deflateSync", Func::from(deflate_sync))?;
168
169 default.set("deflateRaw", Func::from(deflate_raw))?;
170 default.set("deflateRawSync", Func::from(deflate_raw_sync))?;
171
172 default.set("gzip", Func::from(gzip))?;
173 default.set("gzipSync", Func::from(gzip_sync))?;
174
175 default.set("inflate", Func::from(inflate))?;
176 default.set("inflateSync", Func::from(inflate_sync))?;
177
178 default.set("inflateRaw", Func::from(inflate_raw))?;
179 default.set("inflateRawSync", Func::from(inflate_raw_sync))?;
180
181 default.set("gunzip", Func::from(gunzip))?;
182 default.set("gunzipSync", Func::from(gunzip_sync))?;
183
184 default.set("brotliCompress", Func::from(br_comp))?;
185 default.set("brotliCompressSync", Func::from(br_comp_sync))?;
186
187 default.set("brotliDecompress", Func::from(br_decomp))?;
188 default.set("brotliDecompressSync", Func::from(br_decomp_sync))?;
189
190 default.set("zstdCompress", Func::from(zstd_comp))?;
191 default.set("zstdCompressSync", Func::from(zstd_comp_sync))?;
192
193 default.set("zstdDecompress", Func::from(zstd_decomp))?;
194 default.set("zstdDecompressSync", Func::from(zstd_decomp_sync))?;
195
196 Ok(())
197 })
198 }
199}
200
201impl From<ZlibModule> for ModuleInfo<ZlibModule> {
202 fn from(val: ZlibModule) -> Self {
203 ModuleInfo {
204 name: "zlib",
205 module: val,
206 }
207 }
208}