summaryrefslogtreecommitdiff
path: root/ext/node/ops/zlib/brotli.rs
diff options
context:
space:
mode:
authorud2 <sjx233@qq.com>2024-06-20 23:14:24 +0800
committerGitHub <noreply@github.com>2024-06-20 20:44:24 +0530
commit88e3f465d3a95db277ac7e685a0ed239958f8e6e (patch)
tree55d2b17abe8f31e8e47c6936f91e5743b20e55c3 /ext/node/ops/zlib/brotli.rs
parent6ab143335a402965943eb42114c29d0ba02c9a8e (diff)
refactor(ext): remove use of `brotli::ffi` (#24214)
Diffstat (limited to 'ext/node/ops/zlib/brotli.rs')
-rw-r--r--ext/node/ops/zlib/brotli.rs303
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)
}