embedded_fat/fat/
lfn.rs

1use core::str;
2
3use crate::ShortFileName;
4
5const LFN_BUFFER_SIZE: usize = 255 * 4;
6
7#[allow(missing_docs)]
8#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
9pub struct LfnEntry {
10    pub is_start: bool,
11    pub sequence: u8,
12    pub checksum: u8,
13    pub buffer: [char; 13],
14}
15
16pub(crate) struct LfnVisitor {
17    buffer: [u8; LFN_BUFFER_SIZE],
18    state: Option<LfnVisitorState>,
19}
20
21struct LfnVisitorState {
22    buffer_used: usize,
23    last_sequence: u8,
24    checksum: u8,
25}
26
27impl Default for LfnVisitor {
28    fn default() -> Self {
29        Self {
30            buffer: [0; LFN_BUFFER_SIZE],
31            state: Default::default(),
32        }
33    }
34}
35
36impl LfnVisitor {
37    pub(crate) fn visit(&mut self, entry: &LfnEntry) {
38        if entry.is_start {
39            if entry.sequence > 20 {
40                self.state = None;
41            } else {
42                let mut state = LfnVisitorState {
43                    buffer_used: 0,
44                    last_sequence: entry.sequence,
45                    checksum: entry.checksum,
46                };
47                state.extend_buffer(&mut self.buffer, &entry.buffer);
48                self.state = Some(state);
49            }
50        } else if let Some(state) = self.state.as_mut() {
51            if state.checksum != entry.checksum || state.last_sequence != entry.sequence + 1 {
52                self.state = None;
53            } else {
54                state.last_sequence -= 1;
55                state.extend_buffer(&mut self.buffer, &entry.buffer);
56            }
57        } else {
58            self.state = None;
59        }
60    }
61
62    pub(crate) fn take(&mut self, short_name: &ShortFileName) -> Option<&str> {
63        self.state.take().as_ref().and_then(|state| {
64            if state.last_sequence != 1 || state.checksum != short_name.lfn_checksum() {
65                None
66            } else {
67                let active_buffer = &mut self.buffer[..state.buffer_used];
68                active_buffer.reverse();
69                str::from_utf8(active_buffer)
70                    .ok()
71                    .map(|s| s.split('\0').next().unwrap())
72            }
73        })
74    }
75}
76
77impl LfnVisitorState {
78    fn extend_buffer(&mut self, buffer: &mut [u8], extension: &[char]) {
79        let remaining_buffer = &mut buffer[self.buffer_used..];
80        let mut used = 0;
81        for c in extension {
82            let s = c.encode_utf8(&mut remaining_buffer[used..]);
83            used += s.len();
84        }
85        remaining_buffer[..used].reverse();
86        self.buffer_used += used;
87    }
88}