affs_read/
checksum.rs

1//! Checksum calculation functions.
2
3use crate::constants::BLOCK_SIZE;
4
5/// Calculate the normal checksum for a block.
6///
7/// Used for root blocks, entry blocks, etc.
8/// The checksum is calculated such that the sum of all longwords equals 0.
9#[inline]
10pub fn normal_sum(buf: &[u8; BLOCK_SIZE], checksum_offset: usize) -> u32 {
11    normal_sum_slice(buf, checksum_offset)
12}
13
14/// Calculate the normal checksum for a variable-size block.
15///
16/// Used for root blocks, entry blocks, etc. with variable block sizes.
17#[inline]
18pub fn normal_sum_slice(buf: &[u8], checksum_offset: usize) -> u32 {
19    let mut sum: u32 = 0;
20    for i in 0..(buf.len() / 4) {
21        if i != checksum_offset / 4 {
22            sum = sum.wrapping_add(read_u32_be_slice(buf, i * 4));
23        }
24    }
25    (sum as i32).wrapping_neg() as u32
26}
27
28/// Calculate the boot block checksum.
29///
30/// Special checksum algorithm for the boot block.
31#[inline]
32pub fn boot_sum(buf: &[u8; 1024]) -> u32 {
33    let mut sum: u32 = 0;
34    for i in 0..256 {
35        if i != 1 {
36            let d = read_u32_be_slice(buf, i * 4);
37            let new_sum = sum.wrapping_add(d);
38            // Handle overflow (carry)
39            if new_sum < sum {
40                sum = new_sum.wrapping_add(1);
41            } else {
42                sum = new_sum;
43            }
44        }
45    }
46    !sum
47}
48
49/// Calculate bitmap block checksum.
50#[inline]
51pub fn bitmap_sum(buf: &[u8; BLOCK_SIZE]) -> u32 {
52    let mut sum: u32 = 0;
53    for i in 1..128 {
54        sum = sum.wrapping_sub(read_u32_be(buf, i * 4));
55    }
56    sum
57}
58
59/// Read a big-endian u32 from a buffer.
60#[inline]
61pub const fn read_u32_be(buf: &[u8; BLOCK_SIZE], offset: usize) -> u32 {
62    u32::from_be_bytes([
63        buf[offset],
64        buf[offset + 1],
65        buf[offset + 2],
66        buf[offset + 3],
67    ])
68}
69
70/// Read a big-endian u32 from a slice.
71#[inline]
72pub const fn read_u32_be_slice(buf: &[u8], offset: usize) -> u32 {
73    u32::from_be_bytes([
74        buf[offset],
75        buf[offset + 1],
76        buf[offset + 2],
77        buf[offset + 3],
78    ])
79}
80
81/// Read a big-endian i32 from a buffer.
82#[inline]
83pub const fn read_i32_be(buf: &[u8; BLOCK_SIZE], offset: usize) -> i32 {
84    read_i32_be_slice(buf, offset)
85}
86
87/// Read a big-endian i32 from a slice.
88#[inline]
89pub const fn read_i32_be_slice(buf: &[u8], offset: usize) -> i32 {
90    i32::from_be_bytes([
91        buf[offset],
92        buf[offset + 1],
93        buf[offset + 2],
94        buf[offset + 3],
95    ])
96}
97
98/// Read a big-endian u16 from a buffer.
99#[inline]
100pub const fn read_u16_be(buf: &[u8; BLOCK_SIZE], offset: usize) -> u16 {
101    u16::from_be_bytes([buf[offset], buf[offset + 1]])
102}
103
104#[cfg(test)]
105mod tests {
106    use super::*;
107
108    #[test]
109    fn test_read_u32_be() {
110        let mut buf = [0u8; BLOCK_SIZE];
111        buf[0] = 0x12;
112        buf[1] = 0x34;
113        buf[2] = 0x56;
114        buf[3] = 0x78;
115        assert_eq!(read_u32_be(&buf, 0), 0x12345678);
116    }
117
118    #[test]
119    fn test_read_i32_be() {
120        let mut buf = [0u8; BLOCK_SIZE];
121        buf[0] = 0xFF;
122        buf[1] = 0xFF;
123        buf[2] = 0xFF;
124        buf[3] = 0xFD;
125        assert_eq!(read_i32_be(&buf, 0), -3);
126    }
127}