Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for the delta encoding filter #130

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ jobs:
shell: bash
- run: cargo test
- run: cargo test --features tokio
- run: cargo run --manifest-path systest/Cargo.toml
# TODO: should figure out how to run systest in debug mode without generating
# a failure deep inside ctest
- run: cargo run --release --manifest-path systest/Cargo.toml
if: matrix.static == 'yes'


Expand Down
20 changes: 20 additions & 0 deletions lzma-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub type lzma_check = __enum_ty;
pub type lzma_vli = u64;
pub type lzma_mode = __enum_ty;
pub type lzma_match_finder = __enum_ty;
pub type lzma_delta_type = __enum_ty;

pub const LZMA_OK: lzma_ret = 0;
pub const LZMA_STREAM_END: lzma_ret = 1;
Expand Down Expand Up @@ -90,6 +91,12 @@ pub const LZMA_FILTER_ARMTHUMB: lzma_vli = 0x08;
pub const LZMA_FILTER_SPARC: lzma_vli = 0x09;
pub const LZMA_FILTER_LZMA1: lzma_vli = 0x4000000000000001;
pub const LZMA_FILTER_LZMA2: lzma_vli = 0x21;
pub const LZMA_FILTER_DELTA: lzma_vli = 0x03;

pub const LZMA_DELTA_TYPE_BYTE: lzma_delta_type = 0x0;

pub const LZMA_DELTA_DIST_MIN: u32 = 1;
pub const LZMA_DELTA_DIST_MAX: u32 = 256;

#[repr(C)]
pub struct lzma_allocator {
Expand Down Expand Up @@ -186,6 +193,19 @@ pub struct lzma_options_lzma {
reserved_ptr2: *mut c_void,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct lzma_options_delta {
pub type_: lzma_delta_type,
pub dist: u32,
reserved_int1: u32,
reserved_int2: u32,
reserved_int3: u32,
reserved_int4: u32,
reserved_ptr1: *mut c_void,
reserved_ptr2: *mut c_void,
}

#[repr(C)]
pub struct lzma_stream_flags {
pub version: u32,
Expand Down
68 changes: 67 additions & 1 deletion src/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ pub struct LzmaOptions {
raw: lzma_sys::lzma_options_lzma,
}

/// Options that can be used to configure the delta filter.
pub struct DeltaOptions {
raw: lzma_sys::lzma_options_delta,
}

/// Builder to create a multi-threaded stream encoder.
pub struct MtStreamBuilder {
raw: lzma_sys::lzma_mt,
Expand All @@ -41,6 +46,7 @@ pub struct MtStreamBuilder {
pub struct Filters {
inner: Vec<lzma_sys::lzma_filter>,
lzma_opts: LinkedList<lzma_sys::lzma_options_lzma>,
delta_opts: LinkedList<lzma_sys::lzma_options_delta>,
}

/// The `action` argument for `process`,
Expand Down Expand Up @@ -571,6 +577,22 @@ impl LzmaOptions {
}
}

impl DeltaOptions {
/// Creates a set of options for the delta filter for a distance type of bytes.
pub fn new_byte(dist: u32) -> Result<DeltaOptions, Error> {
if dist < lzma_sys::LZMA_DELTA_DIST_MIN || dist > lzma_sys::LZMA_DELTA_DIST_MAX {
Err(Error::Options)
} else {
unsafe {
let mut options = DeltaOptions { raw: mem::zeroed() };
options.raw.type_ = lzma_sys::LZMA_DELTA_TYPE_BYTE;
options.raw.dist = dist;
Ok(options)
}
}
}
}

impl Check {
/// Test if this check is supported in this build of liblzma.
pub fn is_supported(&self) -> bool {
Expand All @@ -596,6 +618,7 @@ impl Filters {
options: 0 as *mut _,
}],
lzma_opts: LinkedList::new(),
delta_opts: LinkedList::new(),
}
}

Expand Down Expand Up @@ -632,7 +655,15 @@ impl Filters {
})
}

// TODO: delta filter
/// Add a filter for delta encoding.
pub fn delta(&mut self, opts: &DeltaOptions) -> &mut Filters {
self.delta_opts.push_back(opts.raw);
let ptr = self.delta_opts.back().unwrap() as *const _ as *mut _;
self.push(lzma_sys::lzma_filter {
id: lzma_sys::LZMA_FILTER_DELTA,
options: ptr,
})
}

/// Add a filter for x86 binaries.
pub fn x86(&mut self) -> &mut Filters {
Expand Down Expand Up @@ -856,3 +887,38 @@ impl Drop for Stream {
}
}
}

#[cfg(test)]
mod tests {
use super::super::write::{XzDecoder, XzEncoder};
use super::DeltaOptions;
use super::{Check, Filters, LzmaOptions, Stream};
use std::io::prelude::*;
use std::iter::repeat;

#[test]
fn delta_bounds() {
assert!(DeltaOptions::new_byte(lzma_sys::LZMA_DELTA_DIST_MIN - 1).is_err());
assert!(DeltaOptions::new_byte(lzma_sys::LZMA_DELTA_DIST_MAX + 1).is_err());
assert!(DeltaOptions::new_byte(lzma_sys::LZMA_DELTA_DIST_MIN).is_ok());
assert!(DeltaOptions::new_byte(lzma_sys::LZMA_DELTA_DIST_MAX).is_ok());
}

#[test]
fn stream_smoke() {
let mut filters = Filters::new();
filters.delta(&DeltaOptions::new_byte(10).unwrap());
filters.lzma2(&LzmaOptions::new_preset(6).unwrap());
let stream = Stream::new_stream_encoder(&filters, Check::Crc64).unwrap();

let d = XzDecoder::new(Vec::new());
let mut c = XzEncoder::new_stream(d, stream);
c.write_all(b"12834").unwrap();
let s = repeat("12345").take(100000).collect::<String>();
c.write_all(s.as_bytes()).unwrap();
let data = c.finish().unwrap().finish().unwrap();
assert_eq!(&data[0..5], b"12834");
assert_eq!(data.len(), 500005);
assert!(format!("12834{}", s).as_bytes() == &*data);
}
}
1 change: 1 addition & 0 deletions systest/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ fn main() {
cfg.type_name(|n, _s, _| n.to_string());
cfg.define("LZMA_API_STATIC", None);
cfg.skip_type(|n| n == "__enum_ty");
cfg.field_name(|_s, field| if field == "type_" { "type" } else { field }.to_string());
cfg.generate("../lzma-sys/src/lib.rs", "all.rs");
}
Loading