frnsc-prefetch 0.13.3

Pure rust windows prefetch parser implementation
Documentation
use forensic_rs::err::{ForensicError, ForensicResult};

pub fn decompress(in_buf: &[u8], out_buf: &mut Vec<u8>) -> ForensicResult<()> {
    let mut buffered_flags = 0;
    let mut buffered_flag_count = 0;
    let mut input_position = 0;
    let mut output_position = 0;
    let mut last_length_half_byte = 0;
    loop {
        if buffered_flag_count == 0 {
            buffered_flags = u32::from_le_bytes(
                in_buf[input_position..input_position + 4]
                    .try_into()
                    .unwrap(),
            );
            input_position += 4;
            buffered_flag_count = 32;
        }
        buffered_flag_count -= 1;
        if (buffered_flags & (1 << buffered_flag_count)) == 0 {
            out_buf.push(in_buf[input_position]);
            input_position += 1;
            output_position += 1;
        } else {
            if input_position == in_buf.len() {
                return Ok(());
            }
            let match_bytes = u16::from_le_bytes(
                in_buf[input_position..input_position + 2]
                    .try_into()
                    .unwrap(),
            ) as u32;
            input_position += 2;
            let mut match_length = match_bytes % 8;
            let match_offset = (match_bytes / 8) + 1;
            if match_length == 7 {
                if last_length_half_byte == 0 {
                    match_length = (in_buf[input_position] as u32) % 16;
                    last_length_half_byte = input_position;
                    input_position += 1;
                } else {
                    match_length = (in_buf[last_length_half_byte] as u32) / 16;
                    last_length_half_byte = 0;
                }
                if match_length == 15 {
                    match_length = in_buf[input_position] as u32;
                    input_position += 1;
                    if match_length == 255 {
                        match_length = u16::from_le_bytes(
                            in_buf[input_position..input_position + 2]
                                .try_into()
                                .unwrap(),
                        ) as u32;
                        input_position += 2;
                        if match_length == 0 {
                            match_length = u32::from_le_bytes(
                                in_buf[input_position..input_position + 4]
                                    .try_into()
                                    .unwrap(),
                            );
                            input_position += 4;
                        }
                        if match_length < 22 {
                            return Err(ForensicError::bad_format_str(
                                "decompress_LZ77(): Invalid match length, must be greater than 22",
                            ));
                        }
                        match_length -= 22;
                    }
                    match_length += 15;
                }
                match_length += 7;
            }
            match_length += 3;
            for _ in 0..match_length {
                out_buf.push(out_buf[output_position - match_offset as usize]);
                output_position += 1;
            }
        }
    }
}

#[test]
fn basic_lz77_decompression() {
    let uncompressed = b"abcdefghijklmnopqrstuvwxyz";
    let encoded: [u8; 30] = [
        0x3f, 0x00, 0x00, 0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
        0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
    ];

    let mut decoded_value = Vec::with_capacity(1024);
    decompress(&encoded, &mut decoded_value).unwrap();
    assert_eq!(uncompressed, &decoded_value[..]);
}

#[test]
fn basic_lz77_decompression_2() {
    let uncompressed = b"abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc";
    let encoded: [u8; 13] = [
        0xff, 0xff, 0xff, 0x1f, 0x61, 0x62, 0x63, 0x17, 0x00, 0x0f, 0xff, 0x26, 0x01,
    ];

    let mut decoded_value = Vec::with_capacity(1024);
    decompress(&encoded, &mut decoded_value).unwrap();
    assert_eq!(uncompressed, &decoded_value[..]);
}