use std::hint::assert_unchecked;
use std::io;
use std::io::ErrorKind::{InvalidData, UnexpectedEof};
use streamvbyte64::{Coder, Coder0124};
#[allow(clippy::ptr_arg)]
pub fn patch(old: &[u8], mut patch: &[u8], new: &mut Vec<u8>) -> io::Result<()> {
let prefix_tag = patch.get(..1).ok_or(io::Error::from(UnexpectedEof))?;
patch = &patch[1..];
let coder = Coder0124::new();
let prefix_len = coder.data_len(prefix_tag);
if patch.len() < prefix_len {
return Err(io::Error::from(UnexpectedEof));
}
let (literals_len, controls, deltas_len, data_len) = {
let mut v = [0u32; 4];
coder.decode(prefix_tag, patch, &mut v);
(v[0] as usize, v[1] as usize, v[2] as usize, v[3] as usize)
};
patch = &patch[prefix_len..];
let mut literals = patch
.get(..literals_len)
.ok_or(io::Error::from(UnexpectedEof))?;
patch = &patch[literals_len..];
let tags_len = controls
.div_ceil(4)
.checked_mul(3)
.ok_or(io::Error::from(InvalidData))?
.checked_add(deltas_len.div_ceil(4))
.ok_or(io::Error::from(InvalidData))?;
let u32_seq_len = tags_len
.checked_mul(4)
.ok_or(io::Error::from(InvalidData))?;
unsafe { assert_unchecked(u32_seq_len >= controls.div_ceil(4) * 12) }
let tags = patch
.get(..tags_len)
.ok_or(io::Error::from(UnexpectedEof))?;
patch = &patch[tags_len..];
let (control_tags, delta_tags) = tags.split_at(controls.div_ceil(4) * 3);
let mut delta_diffs = patch
.get(..deltas_len)
.ok_or(io::Error::from(UnexpectedEof))?;
patch = &patch[deltas_len..];
let control_data_len = coder.data_len(control_tags);
if patch.len() < data_len || data_len < control_data_len {
return Err(io::Error::from(UnexpectedEof));
}
let data = &patch[..data_len];
let (control_data, delta_data) = data.split_at(control_data_len);
let mut u32_seq = vec![0; u32_seq_len];
let (control_seq, delta_pos) = u32_seq.split_at_mut(controls.div_ceil(4) * 12);
let controls_padded = controls.div_ceil(4) * 4;
unsafe {
assert_unchecked(delta_pos.len() >= deltas_len);
assert_unchecked(control_seq.len() >= controls_padded * 2 + controls);
}
let _ = coder.decode(control_tags, control_data, control_seq);
let _ = coder.decode_deltas(0, delta_tags, delta_data, delta_pos);
for (idx, pos) in delta_pos.iter_mut().enumerate() {
*pos = (*pos).wrapping_add(idx as u32);
}
for seek in &mut control_seq[..controls_padded] {
let x = *seek;
*seek = (x >> 1) ^ (x & 1).wrapping_neg()
}
let mut delta_pos = &delta_pos[..deltas_len];
let seeks = &control_seq[..controls];
let adds = &control_seq[controls_padded..][..controls];
let copies = &control_seq[controls_padded * 2..][..controls];
let mut old_cursor: usize = 0;
let mut copy_cursor: usize = 0;
for (&add, (©, &seek)) in adds.iter().zip(copies.iter().zip(seeks)) {
let (add, copy, seek) = (add as usize, copy as usize, seek as i32 as i64);
let old_slice = old
.get(old_cursor..)
.ok_or(io::Error::from(UnexpectedEof))?
.get(..add)
.ok_or(io::Error::from(UnexpectedEof))?;
if new.capacity().wrapping_sub(new.len()) < old_slice.len() {
Err(io::Error::from(UnexpectedEof))?;
}
new.extend_from_slice(old_slice);
let mut nonzero = delta_pos.len().min(delta_diffs.len());
for i in 0..nonzero {
let delta_cursor = copy_cursor.wrapping_add(delta_pos[i] as usize);
if delta_cursor >= new.len() {
nonzero = i;
break;
}
new[delta_cursor] = new[delta_cursor].wrapping_add(delta_diffs[i]);
}
delta_pos = &delta_pos[nonzero..];
delta_diffs = &delta_diffs[nonzero..];
let lit_slice = literals.get(..copy).ok_or(io::Error::from(UnexpectedEof))?;
if new.capacity().wrapping_sub(new.len()) < lit_slice.len() {
Err(io::Error::from(UnexpectedEof))?;
}
new.extend_from_slice(lit_slice);
literals = &literals[copy..];
copy_cursor = copy_cursor.wrapping_add(copy);
old_cursor = usize::try_from(
i64::try_from(
old_cursor
.checked_add(add)
.ok_or(io::Error::from(InvalidData))?,
)
.map_err(|_| io::Error::from(InvalidData))?
.checked_add(seek)
.ok_or(io::Error::from(InvalidData))?,
)
.map_err(|_| io::Error::from(InvalidData))?;
}
Ok(())
}