use crate::control::Aehobak as AehobakControl;
use crate::control::Bsdiff as BsdiffControl;
use std::io;
use std::io::Read;
use streamvbyte64::{Coder, Coder0124};
#[allow(clippy::ptr_arg)]
pub fn decode<T: Read>(reader: &mut T, patch: &mut Vec<u8>) -> io::Result<()> {
let mut prefix = [0u8; 17];
reader.read_exact(&mut prefix[..1])?;
let coder = Coder0124::new();
let prefix_len = coder.data_len(&prefix[..1]);
reader.read_exact(&mut prefix[1..1 + prefix_len])?;
let (controls_len, deltas_len, control_data_len, literals_len) = {
let mut v = [0u32; 4];
let (tag, data) = prefix.as_mut_slice().split_at_mut(1);
coder.decode(tag, data, &mut v);
(v[0] as usize, v[1] as usize, v[2] as usize, v[3] as usize)
};
let control_tags_len = (controls_len * 3 + 3) / 4;
let delta_tags_len = (deltas_len + 3) / 4;
let mut control_tags = vec![0; control_tags_len];
let mut control_data = vec![0; control_data_len];
let mut delta_diffs = vec![0; deltas_len];
let mut literals = vec![0; literals_len];
let mut delta_tags = vec![0; delta_tags_len];
reader.read_exact(&mut control_tags)?;
reader.read_exact(&mut delta_tags)?;
let delta_data_len = coder.data_len(&delta_tags);
reader.read_exact(&mut control_data)?;
reader.read_exact(&mut literals)?;
let mut delta_data = vec![0; delta_data_len];
reader.read_exact(&mut delta_data)?;
reader.read_exact(&mut delta_diffs)?;
let mut controls = vec![0; 4 * control_tags_len];
let _ = coder.decode(&control_tags, &control_data, &mut controls);
controls.truncate(controls_len * 3);
let mut delta_skips = vec![0; 4 * delta_tags_len];
let _ = coder.decode(&delta_tags, &delta_data, &mut delta_skips);
delta_skips.truncate(deltas_len);
let mut literals = literals.as_slice();
let mut delta_skips = delta_skips.as_slice();
let mut delta_diffs = delta_diffs.as_slice();
let mut delta_buf = Vec::new();
let mut delta_cursor = 0;
let mut stream_cursor = 0;
for buffer in controls.chunks_exact(3) {
let control: BsdiffControl = (&AehobakControl::try_from(buffer).unwrap()).into();
let (add, copy) = (control.add as usize, control.copy as usize);
control.encode(patch);
delta_buf.clear();
delta_buf.resize(add, 0);
while !delta_skips.is_empty() && !delta_diffs.is_empty() {
let new_delta_cursor = delta_cursor + delta_skips[0] as usize;
if new_delta_cursor >= stream_cursor + add {
break;
}
delta_buf[new_delta_cursor - stream_cursor] = delta_diffs[0];
delta_cursor = new_delta_cursor + 1;
delta_skips = &delta_skips[1..];
delta_diffs = &delta_diffs[1..];
}
patch.extend(&delta_buf);
patch.extend(&literals[..copy]);
literals = &literals[copy..];
stream_cursor += add;
}
Ok(())
}