diff options
Diffstat (limited to 'ext/node/ops/zlib/brotli.rs')
-rw-r--r-- | ext/node/ops/zlib/brotli.rs | 303 |
1 files changed, 134 insertions, 169 deletions
diff --git a/ext/node/ops/zlib/brotli.rs b/ext/node/ops/zlib/brotli.rs index dc3a40441..3e3905fc3 100644 --- a/ext/node/ops/zlib/brotli.rs +++ b/ext/node/ops/zlib/brotli.rs @@ -1,9 +1,13 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +use brotli::enc::backward_references::BrotliEncoderMode; +use brotli::enc::encode::BrotliEncoderCompress; +use brotli::enc::encode::BrotliEncoderOperation; use brotli::enc::encode::BrotliEncoderParameter; -use brotli::ffi::compressor::*; -use brotli::ffi::decompressor::ffi::interface::BrotliDecoderResult; -use brotli::ffi::decompressor::ffi::BrotliDecoderState; -use brotli::ffi::decompressor::*; +use brotli::enc::encode::BrotliEncoderStateStruct; +use brotli::writer::StandardAlloc; +use brotli::BrotliDecompressStream; +use brotli::BrotliResult; +use brotli::BrotliState; use brotli::Decompressor; use deno_core::error::type_error; use deno_core::error::AnyError; @@ -12,14 +16,20 @@ use deno_core::JsBuffer; use deno_core::OpState; use deno_core::Resource; use deno_core::ToJsBuffer; +use std::cell::RefCell; use std::io::Read; fn encoder_mode(mode: u32) -> Result<BrotliEncoderMode, AnyError> { - if mode > 6 { - return Err(type_error("Invalid encoder mode")); - } - // SAFETY: mode is a valid discriminant for BrotliEncoderMode - unsafe { Ok(std::mem::transmute::<u32, BrotliEncoderMode>(mode)) } + Ok(match mode { + 0 => BrotliEncoderMode::BROTLI_MODE_GENERIC, + 1 => BrotliEncoderMode::BROTLI_MODE_TEXT, + 2 => BrotliEncoderMode::BROTLI_MODE_FONT, + 3 => BrotliEncoderMode::BROTLI_FORCE_LSB_PRIOR, + 4 => BrotliEncoderMode::BROTLI_FORCE_MSB_PRIOR, + 5 => BrotliEncoderMode::BROTLI_FORCE_UTF8_PRIOR, + 6 => BrotliEncoderMode::BROTLI_FORCE_SIGNED_PRIOR, + _ => return Err(type_error("Invalid encoder mode")), + }) } #[op2(fast)] @@ -31,24 +41,22 @@ pub fn op_brotli_compress( #[smi] lgwin: i32, #[smi] mode: u32, ) -> Result<usize, AnyError> { - let in_buffer = buffer.as_ptr(); - let in_size = buffer.len(); - let out_buffer = out.as_mut_ptr(); + let mode = encoder_mode(mode)?; let mut out_size = out.len(); - // SAFETY: in_size and in_buffer, out_size and out_buffer are valid for this call. - if unsafe { - BrotliEncoderCompress( - quality, - lgwin, - encoder_mode(mode)?, - in_size, - in_buffer, - &mut out_size as *mut usize, - out_buffer, - ) - } != 1 - { + let result = BrotliEncoderCompress( + StandardAlloc::default(), + &mut StandardAlloc::default(), + quality, + lgwin, + mode, + buffer.len(), + buffer, + &mut out_size, + out, + &mut |_, _, _, _| (), + ); + if result != 1 { return Err(type_error("Failed to compress")); } @@ -80,28 +88,25 @@ pub async fn op_brotli_compress_async( #[smi] lgwin: i32, #[smi] mode: u32, ) -> Result<ToJsBuffer, AnyError> { + let mode = encoder_mode(mode)?; tokio::task::spawn_blocking(move || { - let in_buffer = input.as_ptr(); - let in_size = input.len(); - - let mut out = vec![0u8; max_compressed_size(in_size)]; - let out_buffer = out.as_mut_ptr(); + let input = &*input; + let mut out = vec![0u8; max_compressed_size(input.len())]; let mut out_size = out.len(); - // SAFETY: in_size and in_buffer, out_size and out_buffer - // are valid for this call. - if unsafe { - BrotliEncoderCompress( - quality, - lgwin, - encoder_mode(mode)?, - in_size, - in_buffer, - &mut out_size as *mut usize, - out_buffer, - ) - } != 1 - { + let result = BrotliEncoderCompress( + StandardAlloc::default(), + &mut StandardAlloc::default(), + quality, + lgwin, + mode, + input.len(), + input, + &mut out_size, + &mut out, + &mut |_, _, _, _| (), + ); + if result != 1 { return Err(type_error("Failed to compress")); } @@ -112,38 +117,26 @@ pub async fn op_brotli_compress_async( } struct BrotliCompressCtx { - inst: *mut BrotliEncoderState, + inst: RefCell<BrotliEncoderStateStruct<StandardAlloc>>, } impl Resource for BrotliCompressCtx {} -impl Drop for BrotliCompressCtx { - fn drop(&mut self) { - // SAFETY: `self.inst` is the current brotli encoder instance. - // It is not used after the following call. - unsafe { BrotliEncoderDestroyInstance(self.inst) }; - } -} - #[op2] #[smi] pub fn op_create_brotli_compress( state: &mut OpState, #[serde] params: Vec<(u8, i32)>, ) -> u32 { - let inst = - // SAFETY: Creates a brotli encoder instance for default allocators. - unsafe { BrotliEncoderCreateInstance(None, None, std::ptr::null_mut()) }; + let mut inst = BrotliEncoderStateStruct::new(StandardAlloc::default()); for (key, value) in params { - // SAFETY: `key` can range from 0-255. - // Any valid u32 can be used for the `value`. - unsafe { - BrotliEncoderSetParameter(inst, encoder_param(key), value as u32); - } + inst.set_parameter(encoder_param(key), value as u32); } - state.resource_table.add(BrotliCompressCtx { inst }) + state.resource_table.add(BrotliCompressCtx { + inst: RefCell::new(inst), + }) } fn encoder_param(param: u8) -> BrotliEncoderParameter { @@ -160,30 +153,25 @@ pub fn op_brotli_compress_stream( #[buffer] output: &mut [u8], ) -> Result<usize, AnyError> { let ctx = state.resource_table.get::<BrotliCompressCtx>(rid)?; - - // SAFETY: TODO(littledivy) - unsafe { - let mut available_in = input.len(); - let mut next_in = input.as_ptr(); - let mut available_out = output.len(); - let mut next_out = output.as_mut_ptr(); - - if BrotliEncoderCompressStream( - ctx.inst, - BrotliEncoderOperation::BROTLI_OPERATION_PROCESS, - &mut available_in, - &mut next_in, - &mut available_out, - &mut next_out, - std::ptr::null_mut(), - ) != 1 - { - return Err(type_error("Failed to compress")); - } - - // On progress, next_out is advanced and available_out is reduced. - Ok(output.len() - available_out) + let mut inst = ctx.inst.borrow_mut(); + let mut output_offset = 0; + + let result = inst.compress_stream( + BrotliEncoderOperation::BROTLI_OPERATION_PROCESS, + &mut input.len(), + input, + &mut 0, + &mut output.len(), + output, + &mut output_offset, + &mut None, + &mut |_, _, _, _| (), + ); + if !result { + return Err(type_error("Failed to compress")); } + + Ok(output_offset) } #[op2(fast)] @@ -194,29 +182,25 @@ pub fn op_brotli_compress_stream_end( #[buffer] output: &mut [u8], ) -> Result<usize, AnyError> { let ctx = state.resource_table.get::<BrotliCompressCtx>(rid)?; - - // SAFETY: TODO(littledivy) - unsafe { - let mut available_out = output.len(); - let mut next_out = output.as_mut_ptr(); - let mut total_out = 0; - - if BrotliEncoderCompressStream( - ctx.inst, - BrotliEncoderOperation::BROTLI_OPERATION_FINISH, - &mut 0, - std::ptr::null_mut(), - &mut available_out, - &mut next_out, - &mut total_out, - ) != 1 - { - return Err(type_error("Failed to compress")); - } - - // On finish, next_out is advanced and available_out is reduced. - Ok(output.len() - available_out) + let mut inst = ctx.inst.borrow_mut(); + let mut output_offset = 0; + + let result = inst.compress_stream( + BrotliEncoderOperation::BROTLI_OPERATION_FINISH, + &mut 0, + &[], + &mut 0, + &mut output.len(), + output, + &mut output_offset, + &mut None, + &mut |_, _, _, _| (), + ); + if !result { + return Err(type_error("Failed to compress")); } + + Ok(output_offset) } fn brotli_decompress(buffer: &[u8]) -> Result<ToJsBuffer, AnyError> { @@ -243,25 +227,22 @@ pub async fn op_brotli_decompress_async( } struct BrotliDecompressCtx { - inst: *mut BrotliDecoderState, + inst: RefCell<BrotliState<StandardAlloc, StandardAlloc, StandardAlloc>>, } impl Resource for BrotliDecompressCtx {} -impl Drop for BrotliDecompressCtx { - fn drop(&mut self) { - // SAFETY: TODO(littledivy) - unsafe { CBrotliDecoderDestroyInstance(self.inst) }; - } -} - #[op2(fast)] #[smi] pub fn op_create_brotli_decompress(state: &mut OpState) -> u32 { - let inst = - // SAFETY: TODO(littledivy) - unsafe { CBrotliDecoderCreateInstance(None, None, std::ptr::null_mut()) }; - state.resource_table.add(BrotliDecompressCtx { inst }) + let inst = BrotliState::new( + StandardAlloc::default(), + StandardAlloc::default(), + StandardAlloc::default(), + ); + state.resource_table.add(BrotliDecompressCtx { + inst: RefCell::new(inst), + }) } #[op2(fast)] @@ -273,32 +254,24 @@ pub fn op_brotli_decompress_stream( #[buffer] output: &mut [u8], ) -> Result<usize, AnyError> { let ctx = state.resource_table.get::<BrotliDecompressCtx>(rid)?; - - // SAFETY: TODO(littledivy) - unsafe { - let mut available_in = input.len(); - let mut next_in = input.as_ptr(); - let mut available_out = output.len(); - let mut next_out = output.as_mut_ptr(); - - if matches!( - CBrotliDecoderDecompressStream( - ctx.inst, - &mut available_in, - &mut next_in, - &mut available_out, - &mut next_out, - std::ptr::null_mut(), - ), - BrotliDecoderResult::BROTLI_DECODER_RESULT_ERROR - ) { - let ec = CBrotliDecoderGetErrorCode(ctx.inst) as i32; - return Err(type_error(format!("Failed to decompress, error {ec}"))); - } - - // On progress, next_out is advanced and available_out is reduced. - Ok(output.len() - available_out) + let mut inst = ctx.inst.borrow_mut(); + let mut output_offset = 0; + + let result = BrotliDecompressStream( + &mut input.len(), + &mut 0, + input, + &mut output.len(), + &mut output_offset, + output, + &mut 0, + &mut inst, + ); + if matches!(result, BrotliResult::ResultFailure) { + return Err(type_error("Failed to decompress")); } + + Ok(output_offset) } #[op2(fast)] @@ -309,30 +282,22 @@ pub fn op_brotli_decompress_stream_end( #[buffer] output: &mut [u8], ) -> Result<usize, AnyError> { let ctx = state.resource_table.get::<BrotliDecompressCtx>(rid)?; - - // SAFETY: TODO(littledivy) - unsafe { - let mut available_out = output.len(); - let mut next_out = output.as_mut_ptr(); - let mut available_in = 0; - let mut next_in = []; - let mut total_out = 0; - - if matches!( - CBrotliDecoderDecompressStream( - ctx.inst, - &mut available_in, - next_in.as_mut_ptr(), - &mut available_out, - &mut next_out, - &mut total_out, - ), - BrotliDecoderResult::BROTLI_DECODER_RESULT_ERROR - ) { - return Err(type_error("Failed to decompress")); - } - - // On finish, next_out is advanced and available_out is reduced. - Ok(output.len() - available_out) + let mut inst = ctx.inst.borrow_mut(); + let mut output_offset = 0; + + let result = BrotliDecompressStream( + &mut 0, + &mut 0, + &[], + &mut output.len(), + &mut output_offset, + output, + &mut 0, + &mut inst, + ); + if matches!(result, BrotliResult::ResultFailure) { + return Err(type_error("Failed to decompress")); } + + Ok(output_offset) } |