use byteorder::{ByteOrder, NetworkEndian};
const _RFC1071_CHUNK_SIZE: usize = 32;
#[allow(dead_code)]
pub(crate) fn confirm_checksum(mut data: &[u8]) -> u16 {
let mut acc = 0;
while data.len() >= _RFC1071_CHUNK_SIZE {
let mut d = &data[.._RFC1071_CHUNK_SIZE];
while d.len() >= 2 {
acc += NetworkEndian::read_u16(d) as u32;
d = &d[2..];
}
data = &data[_RFC1071_CHUNK_SIZE..];
}
while data.len() >= 2 {
acc += NetworkEndian::read_u16(data) as u32;
data = &data[2..];
}
if let Some(&v) = data.first() {
acc += (v as u32) << 8;
}
propagate_carries(acc)
}
#[allow(dead_code)]
fn propagate_carries(word: u32) -> u16 {
let sum = (word >> 16) + (word & 0xffff);
((sum >> 16) as u16) + (sum as u16)
}
pub fn calculate(data: &[u8], checksum_position: usize) -> u16 {
let mut result: u16 = 0;
for (i, pair) in data.chunks(2).enumerate() {
if i == checksum_position {
continue;
}
result =
ones_complement(result, ((pair[0] as u16) << 8) | pair[1] as u16);
}
!result
}
fn ones_complement(mut first: u16, mut second: u16) -> u16 {
let mut carry: u32 = 10;
let mut result: u16 = 0;
while carry != 0 {
let tmp_res = first as u32 + second as u32;
result = (tmp_res & 0xFFFF) as u16;
carry = tmp_res >> 16;
first = result;
second = carry as u16;
}
result
}