use crate::control::Aehobak as AehobakControl;
use crate::control::Bsdiff as BsdiffControl;
use std::io;
use std::io::Write;
use streamvbyte64::{Coder, Coder0124};
pub fn encode<T: Write>(patch: &[u8], writer: &mut T) -> io::Result<()> {
encode_internal(patch, writer)
}
fn encode_internal(mut patch: &[u8], writer: &mut dyn Write) -> io::Result<()> {
let mut encoder = EncoderState::new(patch.len());
while 24 <= patch.len() {
let control: AehobakControl = BsdiffControl::try_from(&patch[..24])
.unwrap()
.try_into()
.unwrap();
let (add, copy) = (control.add as usize, control.copy as usize);
encoder.control(control);
patch = &patch[24..];
encoder.add_diffed(&patch[..add]);
patch = &patch[add..];
encoder.copy(&patch[..copy]);
patch = &patch[copy..];
}
encoder.finalize(writer)
}
pub struct EncoderState {
literals: Vec<u8>,
seeks: Vec<u32>,
adds: Vec<u32>,
copies: Vec<u32>,
delta_skips: Vec<u32>,
delta_diffs: Vec<u8>,
add_cursor: usize,
delta_cursor: usize,
}
impl EncoderState {
pub fn new(len: usize) -> Self {
let ops = len / 16; Self {
literals: Vec::with_capacity(ops),
seeks: Vec::with_capacity(ops),
adds: Vec::with_capacity(ops),
copies: Vec::with_capacity(ops),
delta_skips: Vec::with_capacity(ops),
delta_diffs: Vec::with_capacity(ops),
add_cursor: 0,
delta_cursor: 0,
}
}
pub fn control(&mut self, control: AehobakControl) {
control.encode((&mut self.adds, &mut self.copies, &mut self.seeks));
}
pub fn add(&mut self, old: &[u8], new: &[u8]) {
let add = old.len();
assert_eq!(add, new.len());
for (i, delta) in new
.iter()
.zip(old)
.map(|(n, o)| n.wrapping_sub(*o))
.enumerate()
{
if delta != 0 {
let skip = self.add_cursor + i - self.delta_cursor;
self.delta_skips.push(skip.try_into().unwrap());
self.delta_diffs.push(delta);
self.delta_cursor += skip + 1;
}
}
self.add_cursor += add;
}
pub fn add_diffed(&mut self, deltas: &[u8]) {
for (i, &delta) in deltas.iter().enumerate() {
if delta != 0 {
let skip = self.add_cursor + i - self.delta_cursor;
self.delta_skips.push(skip.try_into().unwrap());
self.delta_diffs.push(delta);
self.delta_cursor += skip + 1;
}
}
self.add_cursor += deltas.len();
}
pub fn copy(&mut self, new: &[u8]) {
self.literals.extend(new);
}
pub fn finalize(&mut self, writer: &mut dyn Write) -> io::Result<()> {
let coder = Coder0124::new();
let controls = self.adds.len();
let padding = controls.wrapping_neg() % 4;
self.seeks.resize(controls + padding, 0);
self.adds.resize(controls + padding, 0);
self.copies.resize(controls + padding, 0);
let padding = self.delta_skips.len().wrapping_neg() % 4;
self.delta_skips.resize(self.delta_skips.len() + padding, 0);
let mut u32_seq = Vec::with_capacity(
self.adds.len() + self.copies.len() + self.delta_skips.len() + self.seeks.len(),
);
u32_seq.extend(&self.copies);
u32_seq.extend(&self.delta_skips);
u32_seq.extend(&self.seeks);
u32_seq.extend(&self.adds);
let (tag_len, data_len) = Coder0124::max_compressed_bytes(u32_seq.len());
let mut encoded = vec![0u8; tag_len + data_len];
let (tags, data) = encoded.split_at_mut(tag_len);
let data_len = coder.encode(&u32_seq, tags, data);
let data = &data[..data_len];
let mut prefix = [0u8; 17];
let prefix_len = 1 + {
let (tag, data) = prefix.as_mut_slice().split_at_mut(1);
coder.encode(
&[
self.delta_diffs.len() as u32,
self.literals.len() as u32,
controls as u32,
data_len as u32,
],
tag,
data,
)
};
writer.write_all(&prefix[..prefix_len])?;
writer.write_all(&self.delta_diffs)?;
writer.write_all(&self.literals)?;
writer.write_all(tags)?;
writer.write_all(data)?;
Ok(())
}
}