Skip to main content

disk_core/
bits.rs

1//! Big-endian (MSB-first) allocation-bitmap helpers, as used by HFS, HFS+ and ProDOS.
2
3/// Test whether the bit at `index` is set in a big-endian bitmap.
4#[inline]
5#[allow(dead_code)]
6pub fn bitmap_test_bit_be(data: &[u8], index: u32) -> bool {
7    let byte_idx = index as usize / 8;
8    let bit_idx = 7 - (index % 8);
9    byte_idx < data.len() && (data[byte_idx] >> bit_idx) & 1 == 1
10}
11
12/// Set the bit at `index` in a big-endian bitmap.
13#[inline]
14pub fn bitmap_set_bit_be(data: &mut [u8], index: u32) {
15    let byte_idx = index as usize / 8;
16    let bit_idx = 7 - (index % 8);
17    data[byte_idx] |= 1u8 << bit_idx;
18}
19
20/// Clear the bit at `index` in a big-endian bitmap.
21#[inline]
22pub fn bitmap_clear_bit_be(data: &mut [u8], index: u32) {
23    let byte_idx = index as usize / 8;
24    let bit_idx = 7 - (index % 8);
25    data[byte_idx] &= !(1u8 << bit_idx);
26}
27
28#[allow(dead_code)]
29/// Find the first set (1) bit in a big-endian bitmap within `max_bits`.
30/// ProDOS uses bit=1 for FREE blocks, so this finds the first free block.
31pub fn bitmap_find_set_bit_be(data: &[u8], max_bits: u32) -> Option<u32> {
32    (0..max_bits).find(|&bit| bitmap_test_bit_be(data, bit))
33}
34
35#[allow(dead_code)]
36/// Find the first clear (0) bit in a big-endian bitmap within `max_bits`.
37pub fn bitmap_find_clear_bit_be(data: &[u8], max_bits: u32) -> Option<u32> {
38    (0..max_bits).find(|&bit| !bitmap_test_bit_be(data, bit))
39}
40
41/// Collect every contiguous run of clear bits in a big-endian bitmap as
42/// `(start, length)` pairs. Used by the HFS+ multi-extent allocator
43/// (largest-run-first) — see `allocate_extents` in `src/fs/hfsplus.rs`.
44pub fn bitmap_collect_clear_runs_be(data: &[u8], max_bits: u32) -> Vec<(u32, u32)> {
45    let mut runs = Vec::new();
46    let mut run_start = 0u32;
47    let mut run_len = 0u32;
48    for bit in 0..max_bits {
49        if bitmap_test_bit_be(data, bit) {
50            if run_len > 0 {
51                runs.push((run_start, run_len));
52                run_len = 0;
53            }
54            run_start = bit + 1;
55        } else {
56            if run_len == 0 {
57                run_start = bit;
58            }
59            run_len += 1;
60        }
61    }
62    if run_len > 0 {
63        runs.push((run_start, run_len));
64    }
65    runs
66}
67
68/// Find a contiguous run of `count` clear bits in a big-endian bitmap.
69/// Returns the starting bit index, or None if no such run exists.
70pub fn bitmap_find_clear_run_be(data: &[u8], max_bits: u32, count: u32) -> Option<u32> {
71    if count == 0 {
72        return Some(0);
73    }
74    let mut run_start = 0u32;
75    let mut run_len = 0u32;
76    for bit in 0..max_bits {
77        if bitmap_test_bit_be(data, bit) {
78            run_start = bit + 1;
79            run_len = 0;
80        } else {
81            run_len += 1;
82            if run_len >= count {
83                return Some(run_start);
84            }
85        }
86    }
87    None
88}