use crate::error::PatchError;
use crate::op::Op;
use crate::wire::{self, Layout};
pub fn apply_patch(old: &[u8], patch: &[u8]) -> Result<Vec<u8>, PatchError> {
let mut out = Vec::with_capacity(estimate_apply_capacity(patch.len()));
apply_patch_into(old, patch, &mut out)?;
Ok(out)
}
pub fn apply_patch_into(old: &[u8], patch: &[u8], out: &mut Vec<u8>) -> Result<(), PatchError> {
match wire::parse(patch)? {
Layout::V1(_) => {}
Layout::V2(header) => header.check_base(old)?,
}
for op in Op::iter(patch) {
match op? {
Op::Copy { offset, len } => {
let start = usize::try_from(offset).map_err(|_| PatchError::Overflow)?;
let len_usize = usize::try_from(len).map_err(|_| PatchError::Overflow)?;
let end = start.checked_add(len_usize).ok_or(PatchError::Overflow)?;
let slice = old.get(start..end).ok_or(PatchError::CopyOutOfBounds {
offset,
len,
old_len: old.len(),
})?;
out.extend_from_slice(slice);
}
Op::Add(bytes) => out.extend_from_slice(bytes),
}
}
Ok(())
}
#[inline]
fn estimate_apply_capacity(patch_len: usize) -> usize {
patch_len.saturating_mul(2).clamp(64, 1 << 20)
}