use std::{error::Error, fmt};
pub fn pack(data: &[u8]) -> Vec<u8> {
let mut result = Vec::with_capacity(data.len());
let mut dnext = 0;
let de = data.len();
'outer: while dnext + 8 <= de {
let mut s_packed_buf = [0; 8];
let mut s_packed_pos = 0;
let mut tag: u8 = 0x00;
for i in 0..8 {
let byte = data[dnext];
dnext += 1;
let bit = byte != 0;
s_packed_buf[s_packed_pos] = byte;
s_packed_pos += bit as usize;
tag |= (bit as u8) << i;
}
match tag {
0x00 => { let dn_initial = dnext;
for _ in 0..31 { let dlast = dnext;
if dnext + 8 <= de {
for _ in 0..8 {
dnext += (data[dnext] == 0) as usize;
}
if dlast + 8 != dnext {
break;
};
} else { for _ in 0..(de-dnext) {
dnext += (data[dnext] == 0) as usize;
}
result.push(0x00);
result.push((8 - 1) + (dnext - dn_initial) as u8);
if dnext == de {
return result;
} else { continue 'outer;
}
}
}
result.push(0x00);
result.push((8 - 1) + (dnext - dn_initial) as u8);
},
0xff => { result.push(0xff);
result.extend_from_slice(&s_packed_buf);
let dn_initial = dnext;
let mut cur_chunk_zeros: u32;
let mut last_chunk_zeros: u32 = 0;
for _ in 0..31 { if dnext + 8 <= de {
cur_chunk_zeros = 0;
for _ in 0..8 {
cur_chunk_zeros += (data[dnext] == 0) as u32;
dnext += 1;
}
if last_chunk_zeros + cur_chunk_zeros >= 3 {
if last_chunk_zeros > 0 {
dnext -= 16;
for _ in 0..16 {
dnext += (data[dnext] != 0) as usize;
} } else {
dnext -= 8;
for _ in 0..8 {
dnext += (data[dnext] != 0) as usize;
} }
} else {
last_chunk_zeros = cur_chunk_zeros;
}
} else { let bytes_left = de-dnext;
cur_chunk_zeros = 0;
for _ in 0..bytes_left {
cur_chunk_zeros += (data[dnext] == 0) as u32;
dnext += 1;
}
if last_chunk_zeros + cur_chunk_zeros >= 3 {
let amount = if dnext - bytes_left - 8 >= dn_initial {
bytes_left + 8
} else {
bytes_left
};
dnext -= amount;
for _ in 0..amount {
dnext += (data[dnext] != 0) as usize;
}
result.push((dnext - dn_initial) as u8);
result.extend_from_slice(&data[dn_initial..dnext]);
continue 'outer;
} else {
result.push((dnext - dn_initial) as u8);
result.extend_from_slice(&data[dn_initial..dnext]);
return result;
}
}
}
result.push((dnext - dn_initial) as u8); result.extend_from_slice(&data[dn_initial..dnext]); },
t => { result.push(t);
result.extend_from_slice(&s_packed_buf[0..s_packed_pos]);
}
}
}
let delta = de-dnext;
if delta > 0 {
let mut s_packed_buf = [0; 8];
let mut s_packed_pos = 0;
let mut tag: u8 = (0x00ff << delta) as u8; for i in 0..delta {
let byte = data[dnext];
dnext += 1;
let bit = byte != 0;
s_packed_buf[s_packed_pos] = byte;
s_packed_pos += bit as usize;
tag |= (bit as u8) << i;
}
result.push(tag);
result.extend_from_slice(&s_packed_buf[0..s_packed_pos]);
}
result
}
#[derive(Debug, PartialEq, Clone, Copy, Hash, Eq, PartialOrd, Ord)]
pub struct UnexpectedEOF(u8);
impl fmt::Display for UnexpectedEOF {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Tag {} expected more bytes, but got EOF!", self.0)
}
}
impl Error for UnexpectedEOF {}
pub fn unpack(data: &[u8], expected_size_hint: usize) -> Result<Vec<u8>, UnexpectedEOF> {
let mut result = Vec::with_capacity(expected_size_hint + (expected_size_hint / 16));
let mut dnext: usize = 0;
let de = data.len();
while dnext < de {
let tag = data[dnext];
dnext += 1;
match tag {
0x00 => {
if dnext >= de { return Err(UnexpectedEOF(0x00)); }
let size = data[dnext] as usize + 1;
dnext += 1;
result.resize(result.len() + size, 0x00);
},
0xff => {
if dnext + 9 > de { result.extend_from_slice(&data[dnext..de]);
return Ok(result);
}
result.extend_from_slice(&data[dnext..dnext+8]); dnext += 8;
let size = data[dnext] as usize;
dnext += 1;
if dnext + size > de {
return Err(UnexpectedEOF(0xff));
}
result.extend_from_slice(&data[dnext..dnext+size]); dnext += size;
},
tag => {
let n_bytes = LOOKUP_NUM_1_IN_U8[tag as usize];
dnext -= 1;
if dnext + n_bytes < de {
for n in 0..8 {
let is_bit_non_zero= (tag & (0x01_u8 << n)) >> n; dnext += is_bit_non_zero as usize;
let byte = data[dnext] & (is_bit_non_zero * 0xFF);
result.push(byte);
}
dnext += 1;
} else {
let n_zeros = 8 - n_bytes;
let bytes_left = de - dnext - 1;
let n_valid = n_zeros + bytes_left;
let clean_tag = tag & (0xFF >> (8 - n_valid)); let clean_n1 = LOOKUP_NUM_1_IN_U8[clean_tag as usize];
if clean_n1 != bytes_left {
return Err(UnexpectedEOF(tag));
}
for n in 0..n_valid {
let is_bit_non_zero = (tag & (0x01_u8 << n)) >> n; dnext += is_bit_non_zero as usize;
let byte = data[dnext] & (is_bit_non_zero * 0xFF);
result.push(byte);
}
return Ok(result);
}
}
}
}
Ok(result)
}
const LOOKUP_NUM_1_IN_U8: [usize; 256] = [ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
];