Use pure rust lz4_flex

HC support from PSeitz/lz4_flex#191
This commit is contained in:
LoveSy
2026-03-03 10:30:12 +08:00
parent e8a58776f1
commit ded94550a5
11 changed files with 39 additions and 689 deletions

3
.gitmodules vendored
View File

@@ -1,9 +1,6 @@
[submodule "selinux"]
path = native/src/external/selinux
url = https://github.com/topjohnwu/selinux.git
[submodule "lz4"]
path = native/src/external/lz4
url = https://github.com/lz4/lz4.git
[submodule "libcxx"]
path = native/src/external/libcxx
url = https://github.com/topjohnwu/libcxx.git

View File

@@ -79,7 +79,6 @@ include $(CLEAR_VARS)
LOCAL_MODULE := magiskboot
LOCAL_STATIC_LIBRARIES := \
libbase \
liblz4 \
libboot-rs
LOCAL_SRC_FILES := \

24
native/src/Cargo.lock generated
View File

@@ -636,19 +636,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]]
name = "lz4"
version = "1.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a20b523e860d03443e98350ceaac5e71c6ba89aea7d960769ec3ce37f4de5af4"
name = "lz4_flex"
version = "0.11.5"
source = "git+https://github.com/PSeitz/lz4_flex.git?rev=e3e5138cff0cad6ca87d09b9d03b1f6017bbc370#e3e5138cff0cad6ca87d09b9d03b1f6017bbc370"
dependencies = [
"lz4-sys",
]
[[package]]
name = "lz4-sys"
version = "1.11.1+lz4-1.10.0"
dependencies = [
"libc",
"twox-hash",
]
[[package]]
@@ -692,7 +684,7 @@ dependencies = [
"digest 0.11.0",
"fdt",
"flate2",
"lz4",
"lz4_flex",
"lzma-rust2",
"num-traits",
"p256",
@@ -1221,6 +1213,12 @@ dependencies = [
"syn",
]
[[package]]
name = "twox-hash"
version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c"
[[package]]
name = "typenum"
version = "1.19.0"

View File

@@ -34,7 +34,7 @@ quick-protobuf = "0.8.1"
flate2 = { version = "1.1.9", default-features = false }
bzip2 = "0.6.1"
zopfli = "0.8.3"
lz4 = "1.28.1"
lz4_flex = { git = "https://github.com/PSeitz/lz4_flex.git", rev = "e3e5138cff0cad6ca87d09b9d03b1f6017bbc370", default-features = false, features = ["hc", "std", "frame"] }
lzma-rust2 = { version = "0.16.2", default-features = false }
nix = "0.30.1"
bitflags = "2.11.0"
@@ -53,7 +53,6 @@ der = "0.8.0"
[patch.crates-io]
pb-rs = { git = "https://github.com/topjohnwu/quick-protobuf.git" }
quick-protobuf = { git = "https://github.com/topjohnwu/quick-protobuf.git" }
lz4-sys = { path = "external/lz4-sys" }
[workspace.lints.clippy]
unwrap_used = "deny"

View File

@@ -34,6 +34,6 @@ bytemuck = { workspace = true, features = ["derive", "min_const_generics"] }
num-traits = { workspace = true }
flate2 = { workspace = true, features = ["zlib-rs"] }
bzip2 = { workspace = true }
lz4 = { workspace = true }
lz4_flex = { workspace = true, features = ["hc", "std", "frame"]}
lzma-rust2 = { workspace = true, features = ["xz", "std", "encoder", "optimization"] }
zopfli = { workspace = true, features = ["gzip"] }

View File

@@ -7,11 +7,9 @@ use bzip2::write::BzEncoder;
use flate2::Compression as GzCompression;
use flate2::read::MultiGzDecoder;
use flate2::write::GzEncoder;
use lz4::block::CompressionMode;
use lz4::liblz4::BlockChecksum;
use lz4::{
BlockMode, BlockSize, ContentChecksum, Decoder as LZ4FrameDecoder, Encoder as LZ4FrameEncoder,
EncoderBuilder as LZ4FrameEncoderBuilder,
use lz4_flex::frame::{
BlockSize as LZ4BlockSize, FrameDecoder as LZ4FrameDecoder, FrameEncoder as LZ4FrameEncoder,
FrameInfo as LZ4FrameInfo,
};
use lzma_rust2::{CheckType, LzmaOptions, LzmaReader, LzmaWriter, XzOptions, XzReader, XzWriter};
use std::cmp::min;
@@ -51,9 +49,7 @@ impl<W: Write> WriteFinish<W> for BufWriter<ZopFliEncoder<W>> {
impl<W: Write> WriteFinish<W> for LZ4FrameEncoder<W> {
fn finish(self: Box<Self>) -> std::io::Result<W> {
let (w, r) = Self::finish(*self);
r?;
Ok(w)
Ok(Self::finish(*self)?)
}
}
@@ -65,40 +61,31 @@ impl<W: Write> WriteFinish<W> for LZ4FrameEncoder<W> {
// LZ4BlockEncoder
const LZ4_BLOCK_SIZE: usize = 0x800000;
const LZ4HC_CLEVEL_MAX: i32 = 12;
const LZ4HC_CLEVEL_MAX: u8 = 12;
const LZ4_MAGIC: u32 = 0x184c2102;
struct LZ4BlockEncoder<W: Write> {
write: W,
chunker: Chunker,
out_buf: Box<[u8]>,
total: u32,
is_lg: bool,
}
impl<W: Write> LZ4BlockEncoder<W> {
fn new(write: W, is_lg: bool) -> Self {
let out_sz = lz4::block::compress_bound(LZ4_BLOCK_SIZE).unwrap_or(LZ4_BLOCK_SIZE);
LZ4BlockEncoder {
write,
chunker: Chunker::new(LZ4_BLOCK_SIZE),
// SAFETY: all bytes will be initialized before it is used
out_buf: unsafe { Box::new_uninit_slice(out_sz).assume_init() },
total: 0,
is_lg,
}
}
fn encode_block(write: &mut W, out_buf: &mut [u8], chunk: &[u8]) -> std::io::Result<()> {
let compressed_size = lz4::block::compress_to_buffer(
chunk,
Some(CompressionMode::HIGHCOMPRESSION(LZ4HC_CLEVEL_MAX)),
false,
out_buf,
)?;
let block_size = compressed_size as u32;
fn encode_block(write: &mut W, chunk: &[u8]) -> std::io::Result<()> {
let compressed = lz4_flex::block::compress_hc_to_vec(chunk, LZ4HC_CLEVEL_MAX);
let block_size = compressed.len() as u32;
write.write_pod(&block_size)?;
write.write_all(&out_buf[..compressed_size])
write.write_all(&compressed)
}
}
@@ -123,7 +110,7 @@ impl<W: Write> Write for LZ4BlockEncoder<W> {
let (b, chunk) = self.chunker.add_data(buf);
buf = b;
if let Some(chunk) = chunk {
Self::encode_block(&mut self.write, &mut self.out_buf, chunk)?;
Self::encode_block(&mut self.write, chunk)?;
}
}
Ok(())
@@ -134,7 +121,7 @@ impl<W: Write> WriteFinish<W> for LZ4BlockEncoder<W> {
fn finish(mut self: Box<Self>) -> std::io::Result<W> {
let chunk = self.chunker.get_available();
if !chunk.is_empty() {
Self::encode_block(&mut self.write, &mut self.out_buf, chunk)?;
Self::encode_block(&mut self.write, chunk)?;
}
if self.is_lg {
self.write.write_pod(&self.total)?;
@@ -155,10 +142,12 @@ struct LZ4BlockDecoder<R: Read> {
impl<R: Read> LZ4BlockDecoder<R> {
fn new(read: R) -> Self {
let compressed_sz = lz4::block::compress_bound(LZ4_BLOCK_SIZE).unwrap_or(LZ4_BLOCK_SIZE);
Self {
read,
in_buf: unsafe { Box::new_uninit_slice(compressed_sz).assume_init() },
in_buf: unsafe {
Box::new_uninit_slice(lz4_flex::block::get_maximum_output_size(LZ4_BLOCK_SIZE))
.assume_init()
},
out_buf: unsafe { Box::new_uninit_slice(LZ4_BLOCK_SIZE).assume_init() },
out_len: 0,
out_pos: 0,
@@ -200,11 +189,8 @@ impl<R: Read> Read for LZ4BlockDecoder<R> {
}
}
self.out_len = lz4::block::decompress_to_buffer(
compressed_block,
Some(LZ4_BLOCK_SIZE as i32),
&mut self.out_buf,
)?;
self.out_len = lz4_flex::block::decompress_into(compressed_block, &mut self.out_buf)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
self.out_pos = 0;
}
let copy_len = min(buf.len(), self.out_len - self.out_pos);
@@ -232,17 +218,14 @@ pub fn get_encoder<'a, W: Write + 'a>(
None,
)?),
FileFormat::BZIP2 => Box::new(BzEncoder::new(w, BzCompression::best())),
FileFormat::LZ4 => {
let encoder = LZ4FrameEncoderBuilder::new()
.block_size(BlockSize::Max4MB)
.block_mode(BlockMode::Independent)
.checksum(ContentChecksum::ChecksumEnabled)
.block_checksum(BlockChecksum::BlockChecksumEnabled)
.level(9)
.auto_flush(true)
.build(w)?;
Box::new(encoder)
}
FileFormat::LZ4 => Box::new(LZ4FrameEncoder::with_compression_level(
LZ4FrameInfo::new()
.block_size(LZ4BlockSize::Max4MB)
.block_checksums(true)
.content_checksum(true),
w,
LZ4HC_CLEVEL_MAX,
)),
FileFormat::LZ4_LEGACY => Box::new(LZ4BlockEncoder::new(w, false)),
FileFormat::LZ4_LG => Box::new(LZ4BlockEncoder::new(w, true)),
FileFormat::ZOPFLI => {
@@ -267,7 +250,7 @@ pub fn get_decoder<'a, R: Read + 'a>(
FileFormat::XZ => Box::new(XzReader::new(r, true)),
FileFormat::LZMA => Box::new(LzmaReader::new_mem_limit(r, u32::MAX, None)?),
FileFormat::BZIP2 => Box::new(BzDecoder::new(r)),
FileFormat::LZ4 => Box::new(LZ4FrameDecoder::new(r)?),
FileFormat::LZ4 => Box::new(LZ4FrameDecoder::new(r)),
FileFormat::LZ4_LG | FileFormat::LZ4_LEGACY => Box::new(LZ4BlockDecoder::new(r)),
FileFormat::ZOPFLI | FileFormat::GZIP => Box::new(MultiGzDecoder::new(r)),
_ => unreachable!(),

View File

@@ -11,18 +11,6 @@ LOCAL_SRC_FILES := \
xz-embedded/xz_dec_stream.c
include $(BUILD_STATIC_LIBRARY)
# liblz4.a
include $(CLEAR_VARS)
LOCAL_MODULE := liblz4
LOCAL_C_INCLUDES := $(LOCAL_PATH)/lz4/lib
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
LOCAL_SRC_FILES := \
lz4/lib/lz4.c \
lz4/lib/lz4frame.c \
lz4/lib/lz4hc.c \
lz4/lib/xxhash.c
include $(BUILD_STATIC_LIBRARY)
SE_PATH := $(LOCAL_PATH)/selinux
# libsepol.a

Submodule native/src/external/lz4 deleted from d44371841a

View File

@@ -1,10 +0,0 @@
[package]
name = "lz4-sys"
license = "MIT"
version = "1.11.1+lz4-1.10.0"
authors = [ "Jens Heyens <jens.heyens@ewetel.net>", "Artem V. Navrotskiy <bozaro@buzzsoft.ru>", "Patrick Marks <pmarks@gmail.com>"]
description = "Rust LZ4 sys package."
repository = "https://github.com/10xGenomics/lz4-rs"
[dependencies]
libc = "0.2"

View File

@@ -1,480 +0,0 @@
#![allow(unexpected_cfgs)]
#![no_std]
extern crate libc;
#[cfg(not(all(
target_arch = "wasm32",
not(any(target_env = "wasi", target_os = "wasi"))
)))]
pub use libc::{c_char, c_int, c_uint, c_ulonglong, c_void, size_t};
#[cfg(all(
target_arch = "wasm32",
not(any(target_env = "wasi", target_os = "wasi"))
))]
extern crate alloc;
#[cfg(all(
target_arch = "wasm32",
not(any(target_env = "wasi", target_os = "wasi"))
))]
mod wasm_shim;
#[cfg(all(
target_arch = "wasm32",
not(any(target_env = "wasi", target_os = "wasi"))
))]
extern crate std;
#[cfg(all(
target_arch = "wasm32",
not(any(target_env = "wasi", target_os = "wasi"))
))]
pub use std::os::raw::{c_char, c_int, c_uint, c_ulonglong, c_void};
#[cfg(all(
target_arch = "wasm32",
not(any(target_env = "wasi", target_os = "wasi"))
))]
#[allow(non_camel_case_types)]
pub type size_t = usize;
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct LZ4FCompressionContext(pub *mut c_void);
unsafe impl Send for LZ4FCompressionContext {}
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct LZ4FDecompressionContext(pub *mut c_void);
unsafe impl Send for LZ4FDecompressionContext {}
pub type LZ4FErrorCode = size_t;
#[derive(Clone, Debug)]
#[repr(u32)]
pub enum BlockSize {
Default = 0, // Default - 64KB
Max64KB = 4,
Max256KB = 5,
Max1MB = 6,
Max4MB = 7,
}
impl BlockSize {
pub fn get_size(&self) -> usize {
match self {
&BlockSize::Default | &BlockSize::Max64KB => 64 * 1024,
&BlockSize::Max256KB => 256 * 1024,
&BlockSize::Max1MB => 1 * 1024 * 1024,
&BlockSize::Max4MB => 4 * 1024 * 1024,
}
}
}
#[derive(Clone, Debug)]
#[repr(u32)]
pub enum BlockMode {
Linked = 0,
Independent,
}
#[derive(Clone, Debug)]
#[repr(u32)]
pub enum ContentChecksum {
NoChecksum = 0,
ChecksumEnabled,
}
#[derive(Clone, Debug)]
#[repr(u32)]
pub enum FrameType {
Frame = 0,
SkippableFrame,
}
#[derive(Clone, Debug)]
#[repr(u32)]
pub enum BlockChecksum {
NoBlockChecksum = 0,
BlockChecksumEnabled,
}
#[derive(Debug)]
#[repr(C)]
pub struct LZ4FFrameInfo {
pub block_size_id: BlockSize,
pub block_mode: BlockMode,
pub content_checksum_flag: ContentChecksum,
pub frame_type: FrameType,
pub content_size: c_ulonglong,
pub dict_id: c_uint,
pub block_checksum_flag: BlockChecksum,
}
#[derive(Debug)]
#[repr(C)]
pub struct LZ4FPreferences {
pub frame_info: LZ4FFrameInfo,
pub compression_level: c_uint, // 0 == default (fast mode); values above 16 count as 16
pub auto_flush: c_uint, // 1 == always flush : reduce need for tmp buffer
pub favor_dec_speed: c_uint, // 1 == favor decompression speed over ratio, requires level 10+
pub reserved: [c_uint; 3],
}
#[derive(Debug)]
#[repr(C)]
pub struct LZ4FCompressOptions {
pub stable_src: c_uint, /* 1 == src content will remain available on future calls
* to LZ4F_compress(); avoid saving src content within tmp
* buffer as future dictionary */
pub reserved: [c_uint; 3],
}
#[derive(Debug)]
#[repr(C)]
pub struct LZ4FDecompressOptions {
pub stable_dst: c_uint, /* guarantee that decompressed data will still be there on next
* function calls (avoid storage into tmp buffers) */
pub reserved: [c_uint; 3],
}
#[derive(Debug)]
#[repr(C)]
pub struct LZ4StreamEncode(c_void);
#[derive(Debug)]
#[repr(C)]
pub struct LZ4StreamDecode(c_void);
pub const LZ4F_VERSION: c_uint = 100;
extern "C" {
// int LZ4_compress_default(const char* source, char* dest, int sourceSize, int maxDestSize);
#[allow(non_snake_case)]
pub fn LZ4_compress_default(
source: *const c_char,
dest: *mut c_char,
sourceSize: c_int,
maxDestSize: c_int,
) -> c_int;
// int LZ4_compress_fast (const char* source, char* dest, int sourceSize, int maxDestSize, int acceleration);
#[allow(non_snake_case)]
pub fn LZ4_compress_fast(
source: *const c_char,
dest: *mut c_char,
sourceSize: c_int,
maxDestSize: c_int,
acceleration: c_int,
) -> c_int;
// int LZ4_compress_HC (const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel);
#[allow(non_snake_case)]
pub fn LZ4_compress_HC(
src: *const c_char,
dst: *mut c_char,
srcSize: c_int,
dstCapacity: c_int,
compressionLevel: c_int,
) -> c_int;
// int LZ4_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize);
#[allow(non_snake_case)]
pub fn LZ4_decompress_safe(
source: *const c_char,
dest: *mut c_char,
compressedSize: c_int,
maxDecompressedSize: c_int,
) -> c_int;
// unsigned LZ4F_isError(LZ4F_errorCode_t code);
pub fn LZ4F_isError(code: size_t) -> c_uint;
// const char* LZ4F_getErrorName(LZ4F_errorCode_t code);
pub fn LZ4F_getErrorName(code: size_t) -> *const c_char;
// LZ4F_createCompressionContext() :
// The first thing to do is to create a compressionContext object, which will be used in all
// compression operations.
// This is achieved using LZ4F_createCompressionContext(), which takes as argument a version
// and an LZ4F_preferences_t structure.
// The version provided MUST be LZ4F_VERSION. It is intended to track potential version
// differences between different binaries.
// The function will provide a pointer to a fully allocated LZ4F_compressionContext_t object.
// If the result LZ4F_errorCode_t is not zero, there was an error during context creation.
// Object can release its memory using LZ4F_freeCompressionContext();
//
// LZ4F_errorCode_t LZ4F_createCompressionContext(
// LZ4F_compressionContext_t* LZ4F_compressionContextPtr,
// unsigned version);
pub fn LZ4F_createCompressionContext(
ctx: &mut LZ4FCompressionContext,
version: c_uint,
) -> LZ4FErrorCode;
// LZ4F_errorCode_t LZ4F_freeCompressionContext(
// LZ4F_compressionContext_t LZ4F_compressionContext);
pub fn LZ4F_freeCompressionContext(ctx: LZ4FCompressionContext) -> LZ4FErrorCode;
// LZ4F_compressBegin() :
// will write the frame header into dstBuffer.
// dstBuffer must be large enough to accommodate a header (dstMaxSize). Maximum header
// size is 19 bytes.
// The LZ4F_preferences_t structure is optional : you can provide NULL as argument, all
// preferences will then be set to default.
// The result of the function is the number of bytes written into dstBuffer for the header
// or an error code (can be tested using LZ4F_isError())
//
// size_t LZ4F_compressBegin(LZ4F_compressionContext_t compressionContext,
// void* dstBuffer,
// size_t dstMaxSize,
// const LZ4F_preferences_t* preferencesPtr);
pub fn LZ4F_compressBegin(
ctx: LZ4FCompressionContext,
dstBuffer: *mut u8,
dstMaxSize: size_t,
preferencesPtr: *const LZ4FPreferences,
) -> LZ4FErrorCode;
// LZ4F_compressBound() :
// Provides the minimum size of Dst buffer given srcSize to handle worst case situations.
// preferencesPtr is optional : you can provide NULL as argument, all preferences will then
// be set to default.
// Note that different preferences will produce in different results.
//
// size_t LZ4F_compressBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr);
pub fn LZ4F_compressBound(
srcSize: size_t,
preferencesPtr: *const LZ4FPreferences,
) -> LZ4FErrorCode;
// LZ4F_compressUpdate()
// LZ4F_compressUpdate() can be called repetitively to compress as much data as necessary.
// The most important rule is that dstBuffer MUST be large enough (dstMaxSize) to ensure
// compression completion even in worst case.
// If this condition is not respected, LZ4F_compress() will fail (result is an errorCode)
// You can get the minimum value of dstMaxSize by using LZ4F_compressBound()
// The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument.
// The result of the function is the number of bytes written into dstBuffer : it can be zero,
// meaning input data was just buffered.
// The function outputs an error code if it fails (can be tested using LZ4F_isError())
//
// size_t LZ4F_compressUpdate(LZ4F_compressionContext_t compressionContext,
// void* dstBuffer,
// size_t dstMaxSize,
// const void* srcBuffer,
// size_t srcSize,
// const LZ4F_compressOptions_t* compressOptionsPtr);
pub fn LZ4F_compressUpdate(
ctx: LZ4FCompressionContext,
dstBuffer: *mut u8,
dstMaxSize: size_t,
srcBuffer: *const u8,
srcSize: size_t,
compressOptionsPtr: *const LZ4FCompressOptions,
) -> size_t;
// LZ4F_flush()
// Should you need to create compressed data immediately, without waiting for a block
// to be be filled, you can call LZ4_flush(), which will immediately compress any remaining
// data buffered within compressionContext.
// The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument.
// The result of the function is the number of bytes written into dstBuffer
// (it can be zero, this means there was no data left within compressionContext)
// The function outputs an error code if it fails (can be tested using LZ4F_isError())
//
// size_t LZ4F_flush(LZ4F_compressionContext_t compressionContext,
// void* dstBuffer,
// size_t dstMaxSize,
// const LZ4F_compressOptions_t* compressOptionsPtr);
pub fn LZ4F_flush(
ctx: LZ4FCompressionContext,
dstBuffer: *mut u8,
dstMaxSize: size_t,
compressOptionsPtr: *const LZ4FCompressOptions,
) -> LZ4FErrorCode;
// LZ4F_compressEnd()
// When you want to properly finish the compressed frame, just call LZ4F_compressEnd().
// It will flush whatever data remained within compressionContext (like LZ4_flush())
// but also properly finalize the frame, with an endMark and a checksum.
// The result of the function is the number of bytes written into dstBuffer
// (necessarily >= 4 (endMark size))
// The function outputs an error code if it fails (can be tested using LZ4F_isError())
// The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument.
// compressionContext can then be used again, starting with LZ4F_compressBegin().
//
// size_t LZ4F_compressEnd(LZ4F_compressionContext_t compressionContext,
// void* dstBuffer,
// size_t dstMaxSize,
// const LZ4F_compressOptions_t* compressOptionsPtr);
pub fn LZ4F_compressEnd(
ctx: LZ4FCompressionContext,
dstBuffer: *mut u8,
dstMaxSize: size_t,
compressOptionsPtr: *const LZ4FCompressOptions,
) -> LZ4FErrorCode;
// LZ4F_createDecompressionContext() :
// The first thing to do is to create a decompressionContext object, which will be used
// in all decompression operations.
// This is achieved using LZ4F_createDecompressionContext().
// The version provided MUST be LZ4F_VERSION. It is intended to track potential version
// differences between different binaries.
// The function will provide a pointer to a fully allocated and initialized
// LZ4F_decompressionContext_t object.
// If the result LZ4F_errorCode_t is not OK_NoError, there was an error during
// context creation.
// Object can release its memory using LZ4F_freeDecompressionContext();
//
// LZ4F_errorCode_t LZ4F_createDecompressionContext(LZ4F_decompressionContext_t* ctxPtr,
// unsigned version);
pub fn LZ4F_createDecompressionContext(
ctx: &mut LZ4FDecompressionContext,
version: c_uint,
) -> LZ4FErrorCode;
// LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_decompressionContext_t ctx);
pub fn LZ4F_freeDecompressionContext(ctx: LZ4FDecompressionContext) -> LZ4FErrorCode;
// LZ4F_getFrameInfo()
// This function decodes frame header information, such as blockSize.
// It is optional : you could start by calling directly LZ4F_decompress() instead.
// The objective is to extract header information without starting decompression, typically
// for allocation purposes.
// LZ4F_getFrameInfo() can also be used *after* starting decompression, on a
// valid LZ4F_decompressionContext_t.
// The number of bytes read from srcBuffer will be provided within *srcSizePtr
// (necessarily <= original value).
// You are expected to resume decompression from where it stopped (srcBuffer + *srcSizePtr)
// The function result is an hint of how many srcSize bytes LZ4F_decompress() expects for
// next call, or an error code which can be tested using LZ4F_isError().
//
// size_t LZ4F_getFrameInfo(LZ4F_decompressionContext_t ctx,
// LZ4F_frameInfo_t* frameInfoPtr,
// const void* srcBuffer, size_t* srcSizePtr);
pub fn LZ4F_getFrameInfo(
ctx: LZ4FDecompressionContext,
frameInfoPtr: &mut LZ4FFrameInfo,
srcBuffer: *const u8,
srcSizePtr: &mut size_t,
) -> LZ4FErrorCode;
// LZ4F_decompress()
// Call this function repetitively to regenerate data compressed within srcBuffer.
// The function will attempt to decode *srcSizePtr bytes from srcBuffer, into dstBuffer of
// maximum size *dstSizePtr.
//
// The number of bytes regenerated into dstBuffer will be provided within *dstSizePtr
// (necessarily <= original value).
//
// The number of bytes read from srcBuffer will be provided within *srcSizePtr
// (necessarily <= original value).
// If number of bytes read is < number of bytes provided, then decompression operation
// is not completed. It typically happens when dstBuffer is not large enough to contain
// all decoded data.
// LZ4F_decompress() must be called again, starting from where it stopped
// (srcBuffer + *srcSizePtr)
// The function will check this condition, and refuse to continue if it is not respected.
//
// dstBuffer is supposed to be flushed between each call to the function, since its content
// will be overwritten.
// dst arguments can be changed at will with each consecutive call to the function.
//
// The function result is an hint of how many srcSize bytes LZ4F_decompress() expects for
// next call.
// Schematically, it's the size of the current (or remaining) compressed block + header of
// next block.
// Respecting the hint provides some boost to performance, since it does skip intermediate
// buffers.
// This is just a hint, you can always provide any srcSize you want.
// When a frame is fully decoded, the function result will be 0. (no more data expected)
// If decompression failed, function result is an error code, which can be tested
// using LZ4F_isError().
//
// size_t LZ4F_decompress(LZ4F_decompressionContext_t ctx,
// void* dstBuffer, size_t* dstSizePtr,
// const void* srcBuffer, size_t* srcSizePtr,
// const LZ4F_decompressOptions_t* optionsPtr);
pub fn LZ4F_decompress(
ctx: LZ4FDecompressionContext,
dstBuffer: *mut u8,
dstSizePtr: &mut size_t,
srcBuffer: *const u8,
srcSizePtr: &mut size_t,
optionsPtr: *const LZ4FDecompressOptions,
) -> LZ4FErrorCode;
// int LZ4_versionNumber(void)
pub fn LZ4_versionNumber() -> c_int;
// int LZ4_compressBound(int isize)
pub fn LZ4_compressBound(size: c_int) -> c_int;
// LZ4_stream_t* LZ4_createStream(void)
pub fn LZ4_createStream() -> *mut LZ4StreamEncode;
// int LZ4_compress_continue(LZ4_stream_t* LZ4_streamPtr,
// const char* source,
// char* dest,
// int inputSize)
pub fn LZ4_compress_continue(
LZ4_stream: *mut LZ4StreamEncode,
source: *const u8,
dest: *mut u8,
input_size: c_int,
) -> c_int;
// int LZ4_freeStream(LZ4_stream_t* LZ4_streamPtr)
pub fn LZ4_freeStream(LZ4_stream: *mut LZ4StreamEncode) -> c_int;
// int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode,
// const char* dictionary,
// int dictSize)
pub fn LZ4_setStreamDecode(
LZ4_stream: *mut LZ4StreamDecode,
dictionary: *const u8,
dict_size: c_int,
) -> c_int;
// LZ4_streamDecode_t* LZ4_createStreamDecode(void)
pub fn LZ4_createStreamDecode() -> *mut LZ4StreamDecode;
// int LZ4_decompress_safe_continue(LZ4_streamDecode_t* LZ4_streamDecode,
// const char* source,
// char* dest,
// int compressedSize,
// int maxDecompressedSize)
pub fn LZ4_decompress_safe_continue(
LZ4_stream: *mut LZ4StreamDecode,
source: *const u8,
dest: *mut u8,
compressed_size: c_int,
max_decompressed_size: c_int,
) -> c_int;
// int LZ4_freeStreamDecode(LZ4_streamDecode_t* LZ4_stream)
pub fn LZ4_freeStreamDecode(LZ4_stream: *mut LZ4StreamDecode) -> c_int;
// LZ4F_resetDecompressionContext()
// In case of an error, the context is left in "undefined" state.
// In which case, it's necessary to reset it, before re-using it.
// This method can also be used to abruptly stop any unfinished decompression,
// and start a new one using same context resources.
pub fn LZ4F_resetDecompressionContext(ctx: LZ4FDecompressionContext);
}
#[test]
fn test_version_number() {
unsafe {
LZ4_versionNumber();
}
}
#[test]
fn test_frame_info_size() {
assert_eq!(core::mem::size_of::<LZ4FFrameInfo>(), 32);
}

View File

@@ -1,123 +0,0 @@
//! A shim for the libc functions used in lz4-rs that are not available when building for wasm
//! targets. Adapted from the shim present in the [zstd](https://github.com/gyscos/zstd-rs) crate.
//! zstd-rs license here:
//! The MIT License (MIT)
//! Copyright (c) 2016 Alexandre Bury
//!
//! Permission is hereby granted, free of charge, to any person obtaining a copy of this software
//! and associated documentation files (the "Software"), to deal in the Software without
//! restriction, including without limitation the rights to use, copy, modify, merge, publish,
//! distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
//! Software is furnished to do so, subject to the following conditions:
//!
//! The above copyright notice and this permission notice shall be included in all copies or
//! substantial portions of the Software.
//!
//! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
//! BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//! NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
//! DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//! OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
use alloc::alloc::{alloc, alloc_zeroed, dealloc, Layout};
use core::ffi::{c_int, c_void};
const USIZE_ALIGN: usize = core::mem::align_of::<usize>();
const USIZE_SIZE: usize = core::mem::size_of::<usize>();
#[no_mangle]
pub extern "C" fn rust_lz4_wasm_shim_malloc(size: usize) -> *mut c_void {
wasm_shim_alloc::<false>(size)
}
#[no_mangle]
pub extern "C" fn rust_lz4_wasm_shim_memcmp(
str1: *const c_void,
str2: *const c_void,
n: usize,
) -> i32 {
// Safety: function contracts requires str1 and str2 at least `n`-long.
unsafe {
let str1: &[u8] = core::slice::from_raw_parts(str1 as *const u8, n);
let str2: &[u8] = core::slice::from_raw_parts(str2 as *const u8, n);
match str1.cmp(str2) {
core::cmp::Ordering::Less => -1,
core::cmp::Ordering::Equal => 0,
core::cmp::Ordering::Greater => 1,
}
}
}
#[no_mangle]
pub extern "C" fn rust_lz4_wasm_shim_calloc(nmemb: usize, size: usize) -> *mut c_void {
// note: calloc expects the allocation to be zeroed
wasm_shim_alloc::<true>(nmemb * size)
}
#[inline]
fn wasm_shim_alloc<const ZEROED: bool>(size: usize) -> *mut c_void {
// in order to recover the size upon free, we store the size below the allocation
// special alignment is never requested via the malloc API,
// so it's not stored, and usize-alignment is used
// memory layout: [size] [allocation]
let full_alloc_size = size + USIZE_SIZE;
unsafe {
let layout = Layout::from_size_align_unchecked(full_alloc_size, USIZE_ALIGN);
let ptr = if ZEROED {
alloc_zeroed(layout)
} else {
alloc(layout)
};
// SAFETY: ptr is usize-aligned and we've allocated sufficient memory
ptr.cast::<usize>().write(full_alloc_size);
ptr.add(USIZE_SIZE).cast()
}
}
#[no_mangle]
pub unsafe extern "C" fn rust_lz4_wasm_shim_free(ptr: *mut c_void) {
// the layout for the allocation needs to be recovered for dealloc
// - the size must be recovered from directly below the allocation
// - the alignment will always by USIZE_ALIGN
let alloc_ptr = ptr.sub(USIZE_SIZE);
// SAFETY: the allocation routines must uphold having a valid usize below the provided pointer
let full_alloc_size = alloc_ptr.cast::<usize>().read();
let layout = Layout::from_size_align_unchecked(full_alloc_size, USIZE_ALIGN);
dealloc(alloc_ptr.cast(), layout);
}
#[no_mangle]
pub unsafe extern "C" fn rust_lz4_wasm_shim_memcpy(
dest: *mut c_void,
src: *const c_void,
n: usize,
) -> *mut c_void {
core::ptr::copy_nonoverlapping(src as *const u8, dest as *mut u8, n);
dest
}
#[no_mangle]
pub unsafe extern "C" fn rust_lz4_wasm_shim_memmove(
dest: *mut c_void,
src: *const c_void,
n: usize,
) -> *mut c_void {
core::ptr::copy(src as *const u8, dest as *mut u8, n);
dest
}
#[no_mangle]
pub unsafe extern "C" fn rust_lz4_wasm_shim_memset(
dest: *mut c_void,
c: c_int,
n: usize,
) -> *mut c_void {
core::ptr::write_bytes(dest as *mut u8, c as u8, n);
dest
}