mod arm;
mod ia64;
mod ppc;
mod riscv;
mod sparc;
mod x86;
use alloc::{vec, vec::Vec};
use crate::Read;
#[cfg(feature = "encoder")]
use crate::Write;
struct BcjFilter {
is_encoder: bool,
pos: usize,
prev_mask: u32,
filter: FilterFn,
}
type FilterFn = fn(filter: &mut BcjFilter, buf: &mut [u8]) -> usize;
impl BcjFilter {
#[inline]
fn code(&mut self, buf: &mut [u8]) -> usize {
let filter = self.filter;
filter(self, buf)
}
}
const FILTER_BUF_SIZE: usize = 4096;
pub struct BcjReader<R> {
inner: R,
filter: BcjFilter,
state: State,
}
#[derive(Debug, Default)]
struct State {
filter_buf: Vec<u8>,
pos: usize,
filtered: usize,
unfiltered: usize,
end_reached: bool,
}
impl<R> BcjReader<R> {
fn new(inner: R, filter: BcjFilter) -> Self {
Self {
inner,
filter,
state: State {
filter_buf: vec![0; FILTER_BUF_SIZE],
..Default::default()
},
}
}
pub fn into_inner(self) -> R {
self.inner
}
pub fn inner(&self) -> &R {
&self.inner
}
pub fn inner_mut(&mut self) -> &mut R {
&mut self.inner
}
#[inline]
pub fn new_x86(inner: R, start_pos: usize) -> Self {
Self::new(inner, BcjFilter::new_x86(start_pos, false))
}
#[inline]
pub fn new_arm(inner: R, start_pos: usize) -> Self {
Self::new(inner, BcjFilter::new_arm(start_pos, false))
}
#[inline]
pub fn new_arm64(inner: R, start_pos: usize) -> Self {
Self::new(inner, BcjFilter::new_arm64(start_pos, false))
}
#[inline]
pub fn new_arm_thumb(inner: R, start_pos: usize) -> Self {
Self::new(inner, BcjFilter::new_arm_thumb(start_pos, false))
}
#[inline]
pub fn new_ppc(inner: R, start_pos: usize) -> Self {
Self::new(inner, BcjFilter::new_power_pc(start_pos, false))
}
#[inline]
pub fn new_sparc(inner: R, start_pos: usize) -> Self {
Self::new(inner, BcjFilter::new_sparc(start_pos, false))
}
#[inline]
pub fn new_ia64(inner: R, start_pos: usize) -> Self {
Self::new(inner, BcjFilter::new_ia64(start_pos, false))
}
#[inline]
pub fn new_riscv(inner: R, start_pos: usize) -> Self {
Self::new(inner, BcjFilter::new_riscv(start_pos, false))
}
}
impl<R: Read> Read for BcjReader<R> {
fn read(&mut self, buf: &mut [u8]) -> crate::Result<usize> {
if buf.is_empty() {
return Ok(0);
}
let mut len = buf.len();
let mut state = core::mem::take(&mut self.state);
let mut off = 0;
let mut size = 0;
loop {
if state.filtered > 0 {
let copy_size = state.filtered.min(len);
let pos = state.pos;
buf[off..(off + copy_size)]
.copy_from_slice(&state.filter_buf[pos..(pos + copy_size)]);
state.pos += copy_size;
state.filtered -= copy_size;
off += copy_size;
len -= copy_size;
size += copy_size;
}
if state.pos + state.filtered + state.unfiltered == FILTER_BUF_SIZE {
state.filter_buf.rotate_left(state.pos);
state.pos = 0;
}
if len == 0 || state.end_reached {
self.state = state;
return Ok(if size > 0 { size } else { 0 });
}
assert_eq!(state.filtered, 0);
let mut in_size = FILTER_BUF_SIZE - (state.pos + state.filtered + state.unfiltered);
let start = state.pos + state.filtered + state.unfiltered;
let temp = &mut state.filter_buf[start..(start + in_size)];
in_size = match self.inner.read(temp) {
Ok(s) => s,
Err(error) => {
self.state = state;
return Err(error);
}
};
if in_size == 0 {
state.end_reached = true;
state.filtered = state.unfiltered;
state.unfiltered = 0;
} else {
state.unfiltered += in_size;
state.filtered = self
.filter
.code(&mut state.filter_buf[state.pos..(state.pos + state.unfiltered)]);
assert!(state.filtered <= state.unfiltered);
state.unfiltered -= state.filtered;
}
}
}
}
#[cfg(feature = "encoder")]
pub struct BcjWriter<W> {
inner: W,
filter: BcjFilter,
buffer: Vec<u8>,
}
#[cfg(feature = "encoder")]
impl<W> BcjWriter<W> {
fn new(inner: W, filter: BcjFilter) -> Self {
Self {
inner,
filter,
buffer: Vec::with_capacity(FILTER_BUF_SIZE),
}
}
pub fn into_inner(self) -> W {
self.inner
}
pub fn inner(&self) -> &W {
&self.inner
}
pub fn inner_mut(&mut self) -> &mut W {
&mut self.inner
}
#[inline]
pub fn new_x86(inner: W, start_pos: usize) -> Self {
Self::new(inner, BcjFilter::new_x86(start_pos, true))
}
#[inline]
pub fn new_arm(inner: W, start_pos: usize) -> Self {
Self::new(inner, BcjFilter::new_arm(start_pos, true))
}
#[inline]
pub fn new_arm64(inner: W, start_pos: usize) -> Self {
Self::new(inner, BcjFilter::new_arm64(start_pos, true))
}
#[inline]
pub fn new_arm_thumb(inner: W, start_pos: usize) -> Self {
Self::new(inner, BcjFilter::new_arm_thumb(start_pos, true))
}
#[inline]
pub fn new_ppc(inner: W, start_pos: usize) -> Self {
Self::new(inner, BcjFilter::new_power_pc(start_pos, true))
}
#[inline]
pub fn new_sparc(inner: W, start_pos: usize) -> Self {
Self::new(inner, BcjFilter::new_sparc(start_pos, true))
}
#[inline]
pub fn new_ia64(inner: W, start_pos: usize) -> Self {
Self::new(inner, BcjFilter::new_ia64(start_pos, true))
}
#[inline]
pub fn new_riscv(inner: W, start_pos: usize) -> Self {
Self::new(inner, BcjFilter::new_riscv(start_pos, true))
}
pub fn finish(mut self) -> crate::Result<W>
where
W: Write,
{
if !self.buffer.is_empty() {
self.inner.write_all(&self.buffer)?;
self.buffer.clear();
}
self.inner.flush()?;
Ok(self.inner)
}
}
#[cfg(feature = "encoder")]
impl<W: Write> Write for BcjWriter<W> {
fn write(&mut self, buf: &[u8]) -> crate::Result<usize> {
let original_len = buf.len();
self.buffer.extend_from_slice(buf);
let filtered_size = self.filter.code(&mut self.buffer);
if filtered_size > 0 {
self.inner.write_all(&self.buffer[..filtered_size])?;
}
if filtered_size < self.buffer.len() {
self.buffer.copy_within(filtered_size.., 0);
self.buffer.truncate(self.buffer.len() - filtered_size);
} else {
self.buffer.clear();
}
Ok(original_len)
}
fn flush(&mut self) -> crate::Result<()> {
self.inner.flush()
}
}
#[cfg(all(feature = "encoder", feature = "std"))]
#[cfg(test)]
mod tests {
use std::io::{copy, Cursor};
use super::*;
#[test]
fn test_bcj_x86_roundtrip() {
let test_data = std::fs::read("tests/data/wget-x86").unwrap();
let mut encoded_buffer = Vec::new();
let mut writer = BcjWriter::new_x86(Cursor::new(&mut encoded_buffer), 0);
copy(&mut test_data.as_slice(), &mut writer).expect("Failed to encode data");
writer.finish().expect("Failed to finish encoding");
assert!(test_data != encoded_buffer);
let mut decoded_data = Vec::new();
let mut reader = BcjReader::new_x86(Cursor::new(&encoded_buffer), 0);
copy(&mut reader, &mut decoded_data).expect("Failed to decode data");
assert!(test_data == decoded_data);
}
#[test]
fn test_bcj_arm_roundtrip() {
let test_data = std::fs::read("tests/data/wget-arm").unwrap();
let mut encoded_buffer = Vec::new();
let mut writer = BcjWriter::new_arm(Cursor::new(&mut encoded_buffer), 0);
copy(&mut test_data.as_slice(), &mut writer).expect("Failed to encode data");
writer.finish().expect("Failed to finish encoding");
assert!(test_data != encoded_buffer);
let mut decoded_data = Vec::new();
let mut reader = BcjReader::new_arm(Cursor::new(&encoded_buffer), 0);
copy(&mut reader, &mut decoded_data).expect("Failed to decode data");
assert!(test_data == decoded_data);
}
#[test]
fn test_bcj_arm64_roundtrip() {
let test_data = std::fs::read("tests/data/wget-arm64").unwrap();
let mut encoded_buffer = Vec::new();
let mut writer = BcjWriter::new_arm64(Cursor::new(&mut encoded_buffer), 0);
copy(&mut test_data.as_slice(), &mut writer).expect("Failed to encode data");
writer.finish().expect("Failed to finish encoding");
assert!(test_data != encoded_buffer);
let mut decoded_data = Vec::new();
let mut reader = BcjReader::new_arm64(Cursor::new(&encoded_buffer), 0);
copy(&mut reader, &mut decoded_data).expect("Failed to decode data");
assert!(test_data == decoded_data);
}
#[test]
fn test_bcj_arm_thumb_roundtrip() {
let test_data = std::fs::read("tests/data/wget-arm-thumb").unwrap();
let mut encoded_buffer = Vec::new();
let mut writer = BcjWriter::new_arm_thumb(Cursor::new(&mut encoded_buffer), 0);
copy(&mut test_data.as_slice(), &mut writer).expect("Failed to encode data");
writer.finish().expect("Failed to finish encoding");
assert!(test_data != encoded_buffer);
let mut decoded_data = Vec::new();
let mut reader = BcjReader::new_arm_thumb(Cursor::new(&encoded_buffer), 0);
copy(&mut reader, &mut decoded_data).expect("Failed to decode data");
assert!(test_data == decoded_data);
}
#[test]
fn test_bcj_ppc_roundtrip() {
let test_data = std::fs::read("tests/data/wget-ppc").unwrap();
let mut encoded_buffer = Vec::new();
let mut writer = BcjWriter::new_ppc(Cursor::new(&mut encoded_buffer), 0);
copy(&mut test_data.as_slice(), &mut writer).expect("Failed to encode data");
writer.finish().expect("Failed to finish encoding");
assert!(test_data != encoded_buffer);
let mut decoded_data = Vec::new();
let mut reader = BcjReader::new_ppc(Cursor::new(&encoded_buffer), 0);
copy(&mut reader, &mut decoded_data).expect("Failed to decode data");
assert!(test_data == decoded_data);
}
#[test]
fn test_bcj_sparc_roundtrip() {
let test_data = std::fs::read("tests/data/wget-sparc").unwrap();
let mut encoded_buffer = Vec::new();
let mut writer = BcjWriter::new_sparc(Cursor::new(&mut encoded_buffer), 0);
copy(&mut test_data.as_slice(), &mut writer).expect("Failed to encode data");
writer.finish().expect("Failed to finish encoding");
assert!(test_data != encoded_buffer);
let mut decoded_data = Vec::new();
let mut reader = BcjReader::new_sparc(Cursor::new(&encoded_buffer), 0);
copy(&mut reader, &mut decoded_data).expect("Failed to decode data");
assert!(test_data == decoded_data);
}
#[test]
fn test_bcj_ia64_roundtrip() {
let test_data = std::fs::read("tests/data/wget-ia64").unwrap();
let mut encoded_buffer = Vec::new();
let mut writer = BcjWriter::new_ia64(Cursor::new(&mut encoded_buffer), 0);
copy(&mut test_data.as_slice(), &mut writer).expect("Failed to encode data");
writer.finish().expect("Failed to finish encoding");
assert!(test_data != encoded_buffer);
let mut decoded_data = Vec::new();
let mut reader = BcjReader::new_ia64(Cursor::new(&encoded_buffer), 0);
copy(&mut reader, &mut decoded_data).expect("Failed to decode data");
assert!(test_data == decoded_data);
}
#[test]
fn test_bcj_riscv_roundtrip() {
let test_data = std::fs::read("tests/data/wget-riscv").unwrap();
let mut encoded_buffer = Vec::new();
let mut writer = BcjWriter::new_riscv(Cursor::new(&mut encoded_buffer), 0);
copy(&mut test_data.as_slice(), &mut writer).expect("Failed to encode data");
writer.finish().expect("Failed to finish encoding");
assert!(test_data != encoded_buffer);
let mut decoded_data = Vec::new();
let mut reader = BcjReader::new_riscv(Cursor::new(&encoded_buffer), 0);
copy(&mut reader, &mut decoded_data).expect("Failed to decode data");
assert!(test_data == decoded_data);
}
}