Files
brk/crates/brk_reader/src/xor_index.rs
2026-04-14 22:53:10 +02:00

71 lines
1.9 KiB
Rust

use crate::xor_bytes::{XOR_LEN, XORBytes};
#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
pub struct XORIndex(usize);
impl XORIndex {
/// Phase-aligned `XORIndex` for a buffer that conceptually starts
/// at `offset` in the blk file.
#[inline]
pub fn at_offset(offset: usize) -> Self {
Self(offset & (XOR_LEN - 1))
}
#[inline]
pub(crate) fn phase(self) -> usize {
self.0
}
#[inline]
pub(crate) fn set_phase(&mut self, phase: usize) {
self.0 = phase & (XOR_LEN - 1);
}
#[inline]
pub fn add_assign(&mut self, i: usize) {
self.0 = (self.0 + i) & (XOR_LEN - 1);
}
/// XOR-decode `bytes` in place, advancing the phase. Aligned 8-byte
/// chunks XOR against the full mask in one go (auto-vectorised by
/// LLVM); only the head/tail straddling alignment are scalar.
pub fn bytes<'a>(&mut self, bytes: &'a mut [u8], xor_bytes: XORBytes) -> &'a mut [u8] {
if xor_bytes.is_identity() {
return bytes;
}
let xb = *xor_bytes;
let mut phase = self.0;
let len = bytes.len();
let mut i = 0;
while phase != 0 && i < len {
bytes[i] ^= xb[phase];
phase = (phase + 1) & (XOR_LEN - 1);
i += 1;
}
let body_len = (len - i) & !(XOR_LEN - 1);
for chunk in bytes[i..i + body_len].chunks_exact_mut(XOR_LEN) {
for (b, m) in chunk.iter_mut().zip(xb) {
*b ^= m;
}
}
i += body_len;
while i < len {
bytes[i] ^= xb[phase];
phase = (phase + 1) & (XOR_LEN - 1);
i += 1;
}
self.0 = phase;
bytes
}
/// XOR-decode `buffer` as if it lived at `offset` in the blk file.
#[inline]
pub fn decode_at(buffer: &mut [u8], offset: usize, xor_bytes: XORBytes) {
Self::at_offset(offset).bytes(buffer, xor_bytes);
}
}