diff options
author | Bartek IwaĆczuk <biwanczuk@gmail.com> | 2023-04-24 12:22:21 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-24 12:22:21 +0200 |
commit | 1f0360c07382dbd86066d1aa8aa4bae34aff18c5 (patch) | |
tree | cc82d00aea829f0b3d3949f40df9696b099ee662 /ext/node/zlib | |
parent | 28e2c7204fe02304a8fc3339d7758eec0f64f723 (diff) |
refactor(ext/node): reorganize ops (#18799)
Move all op related code of "ext/node" to "ext/node/ops" module.
These files were unnecessarily scattered around the extension.
Diffstat (limited to 'ext/node/zlib')
-rw-r--r-- | ext/node/zlib/alloc.rs | 64 | ||||
-rw-r--r-- | ext/node/zlib/mod.rs | 450 | ||||
-rw-r--r-- | ext/node/zlib/mode.rs | 71 | ||||
-rw-r--r-- | ext/node/zlib/stream.rs | 136 |
4 files changed, 0 insertions, 721 deletions
diff --git a/ext/node/zlib/alloc.rs b/ext/node/zlib/alloc.rs deleted file mode 100644 index c7fecadd8..000000000 --- a/ext/node/zlib/alloc.rs +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. - -// Workaround for https://github.com/rust-lang/libz-sys/issues/55 -// See https://github.com/rust-lang/flate2-rs/blob/31fb07820345691352aaa64f367c1e482ad9cfdc/src/ffi/c.rs#L60 -use std::alloc::Layout; -use std::alloc::{self}; -use std::os::raw::c_void; -use std::ptr; - -const ALIGN: usize = std::mem::align_of::<usize>(); - -fn align_up(size: usize, align: usize) -> usize { - (size + align - 1) & !(align - 1) -} - -pub extern "C" fn zalloc( - _ptr: *mut c_void, - items: u32, - item_size: u32, -) -> *mut c_void { - // We need to multiply `items` and `item_size` to get the actual desired - // allocation size. Since `zfree` doesn't receive a size argument we - // also need to allocate space for a `usize` as a header so we can store - // how large the allocation is to deallocate later. - let size = match (items as usize) - .checked_mul(item_size as usize) - .map(|size| align_up(size, ALIGN)) - .and_then(|i| i.checked_add(std::mem::size_of::<usize>())) - { - Some(i) => i, - None => return ptr::null_mut(), - }; - - // Make sure the `size` isn't too big to fail `Layout`'s restrictions - let layout = match Layout::from_size_align(size, ALIGN) { - Ok(layout) => layout, - Err(_) => return ptr::null_mut(), - }; - - // SAFETY: `layout` has non-zero size, guaranteed to be a sentinel address - // or a null pointer. - unsafe { - // Allocate the data, and if successful store the size we allocated - // at the beginning and then return an offset pointer. - let ptr = alloc::alloc(layout) as *mut usize; - if ptr.is_null() { - return ptr as *mut c_void; - } - *ptr = size; - ptr.add(1) as *mut c_void - } -} - -pub extern "C" fn zfree(_ptr: *mut c_void, address: *mut c_void) { - // SAFETY: Move our address being free'd back one pointer, read the size we - // stored in `zalloc`, and then free it using the standard Rust - // allocator. - unsafe { - let ptr = (address as *mut usize).offset(-1); - let size = *ptr; - let layout = Layout::from_size_align_unchecked(size, ALIGN); - alloc::dealloc(ptr as *mut u8, layout) - } -} diff --git a/ext/node/zlib/mod.rs b/ext/node/zlib/mod.rs deleted file mode 100644 index c103b3009..000000000 --- a/ext/node/zlib/mod.rs +++ /dev/null @@ -1,450 +0,0 @@ -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. - -use deno_core::error::bad_resource_id; -use deno_core::error::type_error; -use deno_core::error::AnyError; -use deno_core::op; -use deno_core::OpState; -use libz_sys::*; -use std::borrow::Cow; -use std::cell::RefCell; -use std::future::Future; -use std::rc::Rc; - -mod alloc; -mod mode; -mod stream; - -use mode::Flush; -use mode::Mode; - -use self::stream::StreamWrapper; - -#[inline] -fn check(condition: bool, msg: &str) -> Result<(), AnyError> { - if condition { - Ok(()) - } else { - Err(type_error(msg.to_string())) - } -} - -#[inline] -fn zlib(state: &mut OpState, handle: u32) -> Result<Rc<Zlib>, AnyError> { - state - .resource_table - .get::<Zlib>(handle) - .map_err(|_| bad_resource_id()) -} - -#[derive(Default)] -struct ZlibInner { - dictionary: Option<Vec<u8>>, - err: i32, - flush: Flush, - init_done: bool, - level: i32, - mem_level: i32, - mode: Mode, - strategy: i32, - window_bits: i32, - write_in_progress: bool, - pending_close: bool, - gzib_id_bytes_read: u32, - strm: StreamWrapper, -} - -const GZIP_HEADER_ID1: u8 = 0x1f; -const GZIP_HEADER_ID2: u8 = 0x8b; - -impl ZlibInner { - #[allow(clippy::too_many_arguments)] - fn start_write( - &mut self, - input: &[u8], - in_off: u32, - in_len: u32, - out: &mut [u8], - out_off: u32, - out_len: u32, - flush: Flush, - ) -> Result<(), AnyError> { - check(self.init_done, "write before init")?; - check(!self.write_in_progress, "write already in progress")?; - check(!self.pending_close, "close already in progress")?; - - self.write_in_progress = true; - - let next_in = input - .get(in_off as usize..in_off as usize + in_len as usize) - .ok_or_else(|| type_error("invalid input range"))? - .as_ptr() as *mut _; - let next_out = out - .get_mut(out_off as usize..out_off as usize + out_len as usize) - .ok_or_else(|| type_error("invalid output range"))? - .as_mut_ptr(); - - self.strm.avail_in = in_len; - self.strm.next_in = next_in; - self.strm.avail_out = out_len; - self.strm.next_out = next_out; - - self.flush = flush; - Ok(()) - } - - fn do_write(&mut self, flush: Flush) -> Result<(), AnyError> { - self.flush = flush; - match self.mode { - Mode::Deflate | Mode::Gzip | Mode::DeflateRaw => { - self.err = self.strm.deflate(flush); - } - // Auto-detect mode. - Mode::Unzip if self.strm.avail_in > 0 => 'blck: { - let mut next_expected_header_byte = Some(0); - // SAFETY: `self.strm.next_in` is valid pointer to the input buffer. - // `self.strm.avail_in` is the length of the input buffer that is only set by - // `start_write`. - let strm = unsafe { - std::slice::from_raw_parts( - self.strm.next_in, - self.strm.avail_in as usize, - ) - }; - - if self.gzib_id_bytes_read == 0 { - if strm[0] == GZIP_HEADER_ID1 { - self.gzib_id_bytes_read = 1; - next_expected_header_byte = Some(1); - - // Not enough. - if self.strm.avail_in == 1 { - break 'blck; - } - } else { - self.mode = Mode::Inflate; - next_expected_header_byte = None; - } - } - - if self.gzib_id_bytes_read == 1 { - let byte = match next_expected_header_byte { - Some(i) => strm[i], - None => break 'blck, - }; - if byte == GZIP_HEADER_ID2 { - self.gzib_id_bytes_read = 2; - self.mode = Mode::Gunzip; - } else { - self.mode = Mode::Inflate; - } - } else if next_expected_header_byte.is_some() { - return Err(type_error( - "invalid number of gzip magic number bytes read", - )); - } - } - _ => {} - } - - match self.mode { - Mode::Inflate - | Mode::Gunzip - | Mode::InflateRaw - // We're still reading the header. - | Mode::Unzip => { - self.err = self.strm.inflate(self.flush); - // TODO(@littledivy): Use if let chain when it is stable. - // https://github.com/rust-lang/rust/issues/53667 - // - // Data was encoded with dictionary - if let (Z_NEED_DICT, Some(dictionary)) = (self.err, &self.dictionary) { - self.err = self.strm.inflate_set_dictionary(dictionary); - - if self.err == Z_OK { - self.err = self.strm.inflate(flush); - } else if self.err == Z_DATA_ERROR { - self.err = Z_NEED_DICT; - } - } - - while self.strm.avail_in > 0 - && self.mode == Mode::Gunzip - && self.err == Z_STREAM_END - // SAFETY: `strm` is a valid pointer to zlib strm. - // `strm.next_in` is initialized to the input buffer. - && unsafe { *self.strm.next_in } != 0x00 - { - self.err = self.strm.reset(self.mode); - self.err = self.strm.inflate(flush); - } - } - _ => {} - } - - let done = self.strm.avail_out != 0 && self.flush == Flush::Finish; - // We're are not done yet, but output buffer is full - if self.err == Z_BUF_ERROR && !done { - // Set to Z_OK to avoid reporting the error in JS. - self.err = Z_OK; - } - - self.write_in_progress = false; - Ok(()) - } - - fn init_stream(&mut self) -> Result<(), AnyError> { - match self.mode { - Mode::Gzip | Mode::Gunzip => self.window_bits += 16, - Mode::Unzip => self.window_bits += 32, - Mode::DeflateRaw | Mode::InflateRaw => self.window_bits *= -1, - _ => {} - } - - self.err = match self.mode { - Mode::Deflate | Mode::Gzip | Mode::DeflateRaw => self.strm.deflate_init( - self.level, - self.window_bits, - self.mem_level, - self.strategy, - ), - Mode::Inflate | Mode::Gunzip | Mode::InflateRaw | Mode::Unzip => { - self.strm.inflate_init(self.window_bits) - } - Mode::None => return Err(type_error("Unknown mode")), - }; - - self.write_in_progress = false; - self.init_done = true; - - Ok(()) - } - - fn close(&mut self) -> Result<bool, AnyError> { - if self.write_in_progress { - self.pending_close = true; - return Ok(false); - } - - self.pending_close = false; - check(self.init_done, "close before init")?; - - self.strm.end(self.mode); - self.mode = Mode::None; - Ok(true) - } - - fn reset_stream(&mut self) -> Result<(), AnyError> { - self.err = self.strm.reset(self.mode); - - Ok(()) - } -} - -struct Zlib { - inner: RefCell<ZlibInner>, -} - -impl deno_core::Resource for Zlib { - fn name(&self) -> Cow<str> { - "zlib".into() - } -} - -#[op] -pub fn op_zlib_new(state: &mut OpState, mode: i32) -> Result<u32, AnyError> { - let mode = Mode::try_from(mode)?; - - let inner = ZlibInner { - mode, - ..Default::default() - }; - - Ok(state.resource_table.add(Zlib { - inner: RefCell::new(inner), - })) -} - -#[op] -pub fn op_zlib_close(state: &mut OpState, handle: u32) -> Result<(), AnyError> { - let resource = zlib(state, handle)?; - let mut zlib = resource.inner.borrow_mut(); - - // If there is a pending write, defer the close until the write is done. - zlib.close()?; - - Ok(()) -} - -#[op] -pub fn op_zlib_write_async( - state: Rc<RefCell<OpState>>, - handle: u32, - flush: i32, - input: &[u8], - in_off: u32, - in_len: u32, - out: &mut [u8], - out_off: u32, - out_len: u32, -) -> Result< - impl Future<Output = Result<(i32, u32, u32), AnyError>> + 'static, - AnyError, -> { - let mut state_mut = state.borrow_mut(); - let resource = zlib(&mut state_mut, handle)?; - - let mut strm = resource.inner.borrow_mut(); - let flush = Flush::try_from(flush)?; - strm.start_write(input, in_off, in_len, out, out_off, out_len, flush)?; - - let state = state.clone(); - Ok(async move { - let mut state_mut = state.borrow_mut(); - let resource = zlib(&mut state_mut, handle)?; - let mut zlib = resource.inner.borrow_mut(); - - zlib.do_write(flush)?; - Ok((zlib.err, zlib.strm.avail_out, zlib.strm.avail_in)) - }) -} - -#[op] -pub fn op_zlib_write( - state: &mut OpState, - handle: u32, - flush: i32, - input: &[u8], - in_off: u32, - in_len: u32, - out: &mut [u8], - out_off: u32, - out_len: u32, - result: &mut [u32], -) -> Result<i32, AnyError> { - let resource = zlib(state, handle)?; - - let mut zlib = resource.inner.borrow_mut(); - let flush = Flush::try_from(flush)?; - zlib.start_write(input, in_off, in_len, out, out_off, out_len, flush)?; - zlib.do_write(flush)?; - - result[0] = zlib.strm.avail_out; - result[1] = zlib.strm.avail_in; - - Ok(zlib.err) -} - -#[op] -pub fn op_zlib_init( - state: &mut OpState, - handle: u32, - level: i32, - window_bits: i32, - mem_level: i32, - strategy: i32, - dictionary: Option<&[u8]>, -) -> Result<i32, AnyError> { - let resource = zlib(state, handle)?; - let mut zlib = resource.inner.borrow_mut(); - - check((8..=15).contains(&window_bits), "invalid windowBits")?; - check((-1..=9).contains(&level), "invalid level")?; - - check((1..=9).contains(&mem_level), "invalid memLevel")?; - - check( - strategy == Z_DEFAULT_STRATEGY - || strategy == Z_FILTERED - || strategy == Z_HUFFMAN_ONLY - || strategy == Z_RLE - || strategy == Z_FIXED, - "invalid strategy", - )?; - - zlib.level = level; - zlib.window_bits = window_bits; - zlib.mem_level = mem_level; - zlib.strategy = strategy; - - zlib.flush = Flush::None; - zlib.err = Z_OK; - - zlib.init_stream()?; - - zlib.dictionary = dictionary.map(|buf| buf.to_vec()); - - Ok(zlib.err) -} - -#[op] -pub fn op_zlib_reset( - state: &mut OpState, - handle: u32, -) -> Result<i32, AnyError> { - let resource = zlib(state, handle)?; - - let mut zlib = resource.inner.borrow_mut(); - zlib.reset_stream()?; - - Ok(zlib.err) -} - -#[op] -pub fn op_zlib_close_if_pending( - state: &mut OpState, - handle: u32, -) -> Result<(), AnyError> { - let resource = zlib(state, handle)?; - let pending_close = { - let mut zlib = resource.inner.borrow_mut(); - zlib.write_in_progress = false; - zlib.pending_close - }; - if pending_close { - drop(resource); - state.resource_table.close(handle)?; - } - - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn zlib_start_write() { - // buffer, length, should pass - type WriteVector = (&'static [u8], u32, u32, bool); - const WRITE_VECTORS: [WriteVector; 8] = [ - (b"Hello", 5, 0, true), - (b"H", 1, 0, true), - (b"", 0, 0, true), - // Overrun the buffer - (b"H", 5, 0, false), - (b"ello", 5, 0, false), - (b"Hello", 5, 1, false), - (b"H", 1, 1, false), - (b"", 0, 1, false), - ]; - - for (input, len, offset, expected) in WRITE_VECTORS.iter() { - let mut stream = ZlibInner { - mode: Mode::Inflate, - ..Default::default() - }; - - stream.init_stream().unwrap(); - assert_eq!(stream.err, Z_OK); - assert_eq!( - stream - .start_write(input, *offset, *len, &mut [], 0, 0, Flush::None) - .is_ok(), - *expected - ); - assert_eq!(stream.err, Z_OK); - stream.close().unwrap(); - } - } -} diff --git a/ext/node/zlib/mode.rs b/ext/node/zlib/mode.rs deleted file mode 100644 index ef89805ba..000000000 --- a/ext/node/zlib/mode.rs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. - -use libz_sys as sys; - -#[derive(Debug)] -pub enum Error { - BadArgument, -} - -impl std::fmt::Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Error::BadArgument => write!(f, "bad argument"), - } - } -} - -impl std::error::Error for Error {} - -macro_rules! repr_i32 { - ($(#[$meta:meta])* $vis:vis enum $name:ident { - $($(#[$vmeta:meta])* $vname:ident $(= $val:expr)?,)* - }) => { - $(#[$meta])* - $vis enum $name { - $($(#[$vmeta])* $vname $(= $val)?,)* - } - - impl core::convert::TryFrom<i32> for $name { - type Error = Error; - - fn try_from(v: i32) -> Result<Self, Self::Error> { - match v { - $(x if x == $name::$vname as i32 => Ok($name::$vname),)* - _ => Err(Error::BadArgument), - } - } - } - } - } - -repr_i32! { - #[repr(i32)] - #[derive(Clone, Copy, Debug, PartialEq, Default)] - pub enum Mode { - #[default] - None, - Deflate, - Inflate, - Gzip, - Gunzip, - DeflateRaw, - InflateRaw, - Unzip, - } -} - -repr_i32! { - #[repr(i32)] - #[derive(Clone, Copy, Debug, PartialEq, Default)] - pub enum Flush { - #[default] - None = sys::Z_NO_FLUSH, - Partial = sys::Z_PARTIAL_FLUSH, - Sync = sys::Z_SYNC_FLUSH, - Full = sys::Z_FULL_FLUSH, - Finish = sys::Z_FINISH, - Block = sys::Z_BLOCK, - Trees = sys::Z_TREES, - } -} diff --git a/ext/node/zlib/stream.rs b/ext/node/zlib/stream.rs deleted file mode 100644 index 90cd58ed3..000000000 --- a/ext/node/zlib/stream.rs +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. - -use super::mode::Flush; -use super::mode::Mode; -use libz_sys as sys; -use std::ffi::c_int; -use std::ops::Deref; -use std::ops::DerefMut; - -pub struct StreamWrapper { - pub strm: sys::z_stream, -} - -impl Default for StreamWrapper { - fn default() -> Self { - Self { - strm: sys::z_stream { - next_in: std::ptr::null_mut(), - avail_in: 0, - total_in: 0, - next_out: std::ptr::null_mut(), - avail_out: 0, - total_out: 0, - msg: std::ptr::null_mut(), - state: std::ptr::null_mut(), - zalloc: super::alloc::zalloc, - zfree: super::alloc::zfree, - opaque: 0 as sys::voidpf, - data_type: 0, - adler: 0, - reserved: 0, - }, - } - } -} - -impl Deref for StreamWrapper { - type Target = sys::z_stream; - - fn deref(&self) -> &Self::Target { - &self.strm - } -} - -impl DerefMut for StreamWrapper { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.strm - } -} - -impl StreamWrapper { - pub fn reset(&mut self, mode: Mode) -> c_int { - // SAFETY: `self.strm` is an initialized `z_stream`. - unsafe { - match mode { - Mode::Deflate | Mode::Gzip | Mode::DeflateRaw => { - sys::deflateReset(&mut self.strm) - } - Mode::Inflate | Mode::Gunzip | Mode::InflateRaw | Mode::Unzip => { - sys::inflateReset(&mut self.strm) - } - Mode::None => unreachable!(), - } - } - } - - pub fn end(&mut self, mode: Mode) { - // SAFETY: `self.strm` is an initialized `z_stream`. - unsafe { - match mode { - Mode::Deflate | Mode::Gzip | Mode::DeflateRaw => { - sys::deflateEnd(&mut self.strm); - } - Mode::Inflate | Mode::Gunzip | Mode::InflateRaw | Mode::Unzip => { - sys::inflateEnd(&mut self.strm); - } - Mode::None => {} - } - } - } - - pub fn deflate_init( - &mut self, - level: c_int, - window_bits: c_int, - mem_level: c_int, - strategy: c_int, - ) -> c_int { - // SAFETY: `self.strm` is an initialized `z_stream`. - unsafe { - sys::deflateInit2_( - &mut self.strm, - level, - sys::Z_DEFLATED, - window_bits, - mem_level, - strategy, - sys::zlibVersion(), - std::mem::size_of::<sys::z_stream>() as i32, - ) - } - } - - pub fn inflate_init(&mut self, window_bits: c_int) -> c_int { - // SAFETY: `self.strm` is an initialized `z_stream`. - unsafe { - sys::inflateInit2_( - &mut self.strm, - window_bits, - sys::zlibVersion(), - std::mem::size_of::<sys::z_stream>() as i32, - ) - } - } - - pub fn deflate(&mut self, flush: Flush) -> c_int { - // SAFETY: `self.strm` is an initialized `z_stream`. - unsafe { sys::deflate(&mut self.strm, flush as _) } - } - - pub fn inflate(&mut self, flush: Flush) -> c_int { - // SAFETY: `self.strm` is an initialized `z_stream`. - unsafe { sys::inflate(&mut self.strm, flush as _) } - } - - pub fn inflate_set_dictionary(&mut self, dictionary: &[u8]) -> c_int { - // SAFETY: `self.strm` is an initialized `z_stream`. - unsafe { - sys::inflateSetDictionary( - &mut self.strm, - dictionary.as_ptr() as *const _, - dictionary.len() as _, - ) - } - } -} |