use super::common::{read_byte, read_two_le, retrieve_control_bit};
pub(crate) unsafe fn prs_decompress(mut source: *const u8, mut dest: *mut u8) -> usize {
let mut control_byte = read_byte(&mut source);
let mut current_bit_position = 0;
let mut file_size = 0;
loop {
if retrieve_control_bit(&mut control_byte, &mut current_bit_position, &mut source) == 1 {
*dest = read_byte(&mut source) as u8;
dest = dest.add(1);
file_size += 1;
continue;
}
if retrieve_control_bit(&mut control_byte, &mut current_bit_position, &mut source) == 1 {
if decode_long_copy(&mut source, &mut dest, &mut file_size) {
break;
}
} else {
decode_short_copy(
&mut control_byte,
&mut current_bit_position,
&mut source,
&mut dest,
&mut file_size,
);
}
}
file_size
}
#[inline]
unsafe fn decode_long_copy(
source: &mut *const u8,
dest: &mut *mut u8,
file_size: &mut usize,
) -> bool {
let ofs_bytes = read_two_le(source) as isize;
if ofs_bytes == 0 {
return true;
}
let offset = (ofs_bytes >> 3) | -0x2000;
let length = ofs_bytes as usize & 0b111;
let length = if length == 0 {
read_byte(source) + 1 } else {
length + 2 };
let dest_local = *dest; let src_addr = dest_local.wrapping_add(offset as usize);
for i in 0..length {
*dest_local.add(i) = *src_addr.add(i);
}
*dest = dest_local.add(length);
*file_size += length;
false
}
#[inline]
unsafe fn decode_short_copy(
control_byte: &mut usize,
current_bit_position: &mut usize,
source: &mut *const u8,
dest: &mut *mut u8,
file_size: &mut usize,
) {
let mut length = retrieve_control_bit(control_byte, current_bit_position, source) << 1;
length |= retrieve_control_bit(control_byte, current_bit_position, source);
length += 2;
let offset = read_byte(source) as isize | -0x100;
let dest_local = *dest; let src_addr = dest_local.wrapping_add(offset as usize);
for i in 0..length {
*dest_local.add(i) = *src_addr.add(i);
}
*dest = dest_local.add(length);
*file_size += length;
}