Skip to content

Commit a5b6fff

Browse files
committed
Initial commit for Rust powered modules
1 parent 3bc67de commit a5b6fff

File tree

12 files changed

+610
-245
lines changed

12 files changed

+610
-245
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,6 @@ __pycache__/
99
tests/docs/api
1010
tests/docs/build
1111
.tox/
12+
*/*/_native.src/target
13+
*/*/_native.*.so
14+
*/*/_native.*.dll

dissect/util/_native.src/Cargo.lock

Lines changed: 234 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "_native"
3+
version = "0.0.0-git"
4+
edition = "2021"
5+
6+
[lib]
7+
name = "_native"
8+
crate-type = ["cdylib"]
9+
10+
[dependencies]
11+
pyo3 = "0.22"
12+
lz4_flex = "0.11"
13+
lzokay-native = "0.1"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
use pyo3::prelude::*;
2+
3+
mod lz4;
4+
mod lzo;
5+
6+
pub fn create_submodule(m: &Bound<'_, PyModule>) -> PyResult<()> {
7+
let submodule = PyModule::new_bound(m.py(), "compression")?;
8+
lz4::create_submodule(&submodule)?;
9+
lzo::create_submodule(&submodule)?;
10+
m.add_submodule(&submodule)
11+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
use pyo3::exceptions::PyValueError;
2+
use pyo3::prelude::*;
3+
use pyo3::types::{PyByteArray, PyBytes};
4+
5+
const MAX_DISCOVER_OUTPUT_SIZE: usize = 1024 * 1024 * 1024;
6+
7+
#[pyfunction]
8+
#[pyo3(signature = (src, uncompressed_size=-1, return_bytearray=false))]
9+
fn decompress(
10+
py: Python<'_>,
11+
src: Vec<u8>,
12+
uncompressed_size: isize,
13+
return_bytearray: bool,
14+
) -> PyResult<PyObject> {
15+
let result = if uncompressed_size < 0 {
16+
// If the uncompressed size is not provided, we need to discover it first
17+
let mut output_size = lz4_flex::block::get_maximum_output_size(src.len());
18+
loop {
19+
// If the output size is too large, we should not attempt to decompress further
20+
if output_size > MAX_DISCOVER_OUTPUT_SIZE {
21+
return Err(PyErr::new::<PyValueError, _>(
22+
"output size is too large".to_string(),
23+
));
24+
}
25+
26+
match lz4_flex::block::decompress(&src, output_size) {
27+
Ok(result) => {
28+
break result;
29+
}
30+
Err(lz4_flex::block::DecompressError::OutputTooSmall {
31+
expected,
32+
actual: _,
33+
}) => {
34+
output_size = expected;
35+
}
36+
Err(e) => {
37+
return Err(PyErr::new::<PyValueError, _>(e.to_string()));
38+
}
39+
}
40+
}
41+
} else {
42+
lz4_flex::block::decompress(&src, uncompressed_size as usize)
43+
.map_err(|e| PyErr::new::<PyValueError, _>(e.to_string()))?
44+
};
45+
46+
let pyresult = PyBytes::new_bound(py, &result);
47+
if return_bytearray {
48+
Ok(PyByteArray::from_bound(&pyresult)?.into())
49+
} else {
50+
Ok(pyresult.into())
51+
}
52+
}
53+
54+
pub fn create_submodule(m: &Bound<'_, PyModule>) -> PyResult<()> {
55+
let submodule = PyModule::new_bound(m.py(), "lz4")?;
56+
submodule.add_function(wrap_pyfunction!(decompress, m)?)?;
57+
m.add_submodule(&submodule)
58+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
use pyo3::exceptions::PyValueError;
2+
use pyo3::prelude::*;
3+
use pyo3::types::PyBytes;
4+
5+
#[pyfunction]
6+
#[pyo3(signature = (src, header=true, buflen=-1))]
7+
fn decompress(
8+
py: Python<'_>,
9+
src: Vec<u8>,
10+
header: bool,
11+
buflen: isize,
12+
) -> PyResult<Bound<'_, PyBytes>> {
13+
let (src, out_len) = if header {
14+
if src.len() < 8 || src[0] < 0xf0 || src[0] > 0xf1 {
15+
return Err(PyErr::new::<PyValueError, _>(
16+
"Invalid header value".to_string(),
17+
));
18+
}
19+
let len = u32::from_le_bytes([src[1], src[2], src[3], src[4]]) as usize;
20+
(src[5..].to_vec(), len)
21+
} else if buflen < 0 {
22+
return Err(PyErr::new::<PyValueError, _>(
23+
"Buffer length must be provided".to_string(),
24+
));
25+
} else {
26+
(src, buflen as usize)
27+
};
28+
29+
let mut cursor = std::io::Cursor::new(src);
30+
lzokay_native::decompress(&mut cursor, Some(out_len))
31+
.map_err(|e| PyErr::new::<PyValueError, _>(e.to_string()))
32+
.map(|result| PyBytes::new_bound(py, &result))
33+
}
34+
35+
pub fn create_submodule(m: &Bound<'_, PyModule>) -> PyResult<()> {
36+
let submodule = PyModule::new_bound(m.py(), "lzo")?;
37+
submodule.add_function(wrap_pyfunction!(decompress, m)?)?;
38+
m.add_submodule(&submodule)
39+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
use pyo3::prelude::*;
2+
3+
mod compression;
4+
5+
6+
#[pymodule]
7+
fn _native(m: &Bound<'_, PyModule>) -> PyResult<()> {
8+
compression::create_submodule(m)?;
9+
Ok(())
10+
}

0 commit comments

Comments
 (0)