use qbsdiff::Bspatch;
const MAX_PREALLOC_BYTES: u64 = 64 * 1024 * 1024;
pub fn apply_diff(before: &[u8], delta: &[u8]) -> Result<Vec<u8>, std::io::Error> {
let patcher = Bspatch::new(delta)?;
let prealloc = patcher.hint_target_size().min(MAX_PREALLOC_BYTES) as usize;
let mut out = Vec::with_capacity(prealloc);
patcher.apply(before, std::io::Cursor::new(&mut out))?;
Ok(out)
}
#[cfg(test)]
mod tests {
use super::*;
use qbsdiff::Bsdiff;
fn make_delta(before: &[u8], after: &[u8]) -> Vec<u8> {
let mut delta = Vec::new();
Bsdiff::new(before, after)
.compare(std::io::Cursor::new(&mut delta))
.expect("compare");
delta
}
#[test]
fn test_apply_diff_text_round_trip() {
let before = b"the quick brown fox jumps over the lazy dog";
let after = b"the quick brown cat jumps over the lazy dog";
let delta = make_delta(before, after);
let result = apply_diff(before, &delta).unwrap();
assert_eq!(result, after);
}
#[test]
fn test_apply_diff_binary_round_trip() {
let before: Vec<u8> = (0..1024u32).map(|i| (i % 251) as u8).collect();
let mut after = before.clone();
for i in [10usize, 200, 500, 900] {
after[i] = after[i].wrapping_add(7);
}
let delta = make_delta(&before, &after);
let result = apply_diff(&before, &delta).unwrap();
assert_eq!(result, after);
}
#[test]
fn test_apply_diff_empty_to_nonempty() {
let before: &[u8] = b"";
let after = b"hello";
let delta = make_delta(before, after);
let result = apply_diff(before, &delta).unwrap();
assert_eq!(result, after);
}
#[test]
fn test_apply_diff_malformed_errors() {
let bogus_delta = b"not a real bsdiff delta";
let result = apply_diff(b"anything", bogus_delta);
assert!(result.is_err(), "expected malformed-delta error");
}
#[test]
fn test_apply_diff_wrong_source_does_not_panic() {
let src_a = b"AAAAAAAAAAAAAAAAAAAA";
let src_b = b"BBBBBBBBBBBBBBBBBBBB";
let target = b"CCCCCCCCCCCCCCCCCCCC";
let delta = make_delta(src_a, target);
let _ = apply_diff(src_b, &delta);
}
#[test]
fn test_apply_diff_forged_oversize_header_is_safe() {
let before = b"the quick brown fox jumps over the lazy dog";
let after = b"the quick brown cat jumps over the lazy dog";
let mut forged = make_delta(before, after);
assert!(forged.len() >= 32, "delta must contain a full header");
let huge: u64 = 1 << 60;
forged[24..32].copy_from_slice(&huge.to_le_bytes());
let result = apply_diff(before, &forged).expect("clamped apply must succeed");
assert_eq!(
result, after,
"forging the size hint must not corrupt output"
);
}
#[test]
fn test_apply_diff_capacity_hint_is_clamped() {
let huge_hint: u64 = u64::MAX;
let clamped = huge_hint.min(MAX_PREALLOC_BYTES) as usize;
assert_eq!(clamped, MAX_PREALLOC_BYTES as usize);
let small_hint: u64 = 4096;
assert_eq!(small_hint.min(MAX_PREALLOC_BYTES) as usize, 4096);
}
}