inky_frame/fs/volume/
name.rs

1// Permission is hereby granted, free of charge, to any person obtaining a copy
2// of this software and associated documentation files (the "Software"), to deal
3// in the Software without restriction, including without limitation the rights
4// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
5// copies of the Software, and to permit persons to whom the Software is
6// furnished to do so, subject to the following conditions:
7//
8// The above copyright notice and this permission notice shall be included in
9// all copies or substantial portions of the Software.
10//
11// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17// SOFTWARE.
18//
19
20#![no_implicit_prelude]
21
22extern crate core;
23
24use core::clone::Clone;
25use core::cmp::{self, PartialEq};
26use core::convert::AsRef;
27use core::default::Default;
28use core::iter::Iterator;
29use core::ops::Deref;
30use core::option::Option::{None, Some};
31use core::result::Result::{self, Err, Ok};
32use core::str::from_utf8_unchecked;
33use core::unreachable;
34
35use crate::fs::{DeviceError, FatVersion};
36
37pub struct LongName(pub(super) [u8; LongName::SIZE]);
38pub struct ShortName(pub(super) [u8; ShortName::SIZE]);
39pub struct VolumeName(pub(super) [u8; VolumeName::SIZE]);
40
41impl LongName {
42    pub const SIZE: usize = 0xFFusize;
43
44    #[inline(always)]
45    pub const fn empty() -> LongName {
46        LongName([0u8; LongName::SIZE])
47    }
48
49    #[inline]
50    pub fn from_slice_truncate(v: &[u8]) -> LongName {
51        let mut n = LongName([0x20u8; LongName::SIZE]);
52        n.fill_inner(v);
53        n
54    }
55    #[inline]
56    pub fn from_str_truncate(v: impl AsRef<str>) -> LongName {
57        LongName::from_slice_truncate(v.as_ref().as_bytes())
58    }
59    #[inline]
60    pub fn from_slice(v: &[u8]) -> Result<LongName, DeviceError> {
61        if v.len() > LongName::SIZE {
62            Err(DeviceError::NameTooLong)
63        } else {
64            Ok(LongName::from_slice_truncate(v))
65        }
66    }
67    #[inline]
68    pub fn from_str(v: impl AsRef<str>) -> Result<LongName, DeviceError> {
69        if v.as_ref().len() > LongName::SIZE {
70            Err(DeviceError::NameTooLong)
71        } else {
72            Ok(LongName::from_str_truncate(v))
73        }
74    }
75
76    #[inline(always)]
77    pub fn len(&self) -> usize {
78        self.0.iter().position(|v| *v == 0).unwrap_or(LongName::SIZE)
79    }
80    #[inline(always)]
81    pub fn as_str(&self) -> &str {
82        unsafe { from_utf8_unchecked(&self.0[0..self.0.iter().position(|v| *v == 0).unwrap_or(LongName::SIZE)]) }
83    }
84    pub fn lfn_size(&self) -> u8 {
85        let mut r = self.len();
86        if r <= 13 {
87            return 1;
88        }
89        r += 1; // NULL CHAR
90        let c = r / 0xC;
91        if (c * 0xC) == r {
92            return c as u8;
93        }
94        if r > 0xC {
95            r += 1; // ADD PAD
96        }
97        (r / 0xC) as u8 + 1
98    }
99    #[inline(always)]
100    pub fn is_self(&self) -> bool {
101        self.0[0] == b'.' && self.0[1] == 0
102    }
103    #[inline(always)]
104    pub fn is_empty(&self) -> bool {
105        self.0[0] == 0
106    }
107    #[inline(always)]
108    pub fn as_bytes(&self) -> &[u8] {
109        &self.0[0..self.0.iter().position(|v| *v == 0).unwrap_or(LongName::SIZE)]
110    }
111    #[inline(always)]
112    pub fn is_parent(&self) -> bool {
113        self.0[0] == b'.' && self.0[1] == b'.' && self.0[2] == 0
114    }
115    #[inline]
116    pub fn fill(&mut self, v: &[u8]) -> Result<(), DeviceError> {
117        if v.len() > LongName::SIZE {
118            return Err(DeviceError::NameTooLong);
119        }
120        self.fill_inner(v);
121        Ok(())
122    }
123    #[inline]
124    pub fn fill_str(&mut self, v: impl AsRef<str>) -> Result<(), DeviceError> {
125        self.fill(v.as_ref().as_bytes())
126    }
127
128    #[inline(always)]
129    pub(super) fn reset(&mut self) {
130        self.0.fill(0)
131    }
132    pub(super) fn fill_lfn(&mut self, b: &[u8]) -> u8 {
133        if b.len() < 0x20 {
134            return 0u8;
135        }
136        let v = ((b[0] & 0x1F) as usize - 1) * 0xD;
137        for i in 0..0xD {
138            if i + v >= LongName::SIZE {
139                break;
140            }
141            let c = b[LongName::pos_to_lfn(i)];
142            if c == 0 {
143                break;
144            }
145            self.0[v + i] = c;
146        }
147        b[0xD]
148    }
149
150    #[inline(always)]
151    pub(super) fn pos_to_lfn(v: usize) -> usize {
152        match v {
153            0 => 1,
154            1 => 3,
155            2 => 5,
156            3 => 7,
157            4 => 9,
158            5 => 14,
159            6 => 16,
160            7 => 18,
161            8 => 20,
162            9 => 22,
163            10 => 24,
164            11 => 28,
165            12 => 30,
166            _ => unreachable!(),
167        }
168    }
169
170    #[inline]
171    fn fill_inner(&mut self, v: &[u8]) {
172        if v.len() < LongName::SIZE {
173            self.0[0..v.len()].copy_from_slice(v)
174        } else {
175            self.0.copy_from_slice(&v[0..LongName::SIZE]);
176        }
177    }
178}
179impl ShortName {
180    pub const SIZE: usize = 0xBusize;
181    pub const SIZE_EXT: usize = 0x3usize;
182    pub const SIZE_NAME: usize = 0x8usize;
183
184    pub const SELF: ShortName = ShortName([0x2E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20]);
185    pub const PARENT: ShortName = ShortName([0x2E, 0x2E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20]);
186
187    #[inline]
188    pub fn empty() -> ShortName {
189        ShortName([0x20u8; ShortName::SIZE])
190    }
191    #[inline]
192    pub fn from_slice(v: &[u8]) -> ShortName {
193        let mut n = ShortName([0x20u8; ShortName::SIZE]);
194        n.fill(v);
195        n
196    }
197    #[inline]
198    pub fn from_str(v: impl AsRef<str>) -> ShortName {
199        ShortName::from_slice(v.as_ref().as_bytes())
200    }
201
202    #[inline]
203    pub fn name(&self) -> &str {
204        unsafe {
205            from_utf8_unchecked(
206                &self.0[0..self.0[0..ShortName::SIZE_NAME]
207                    .iter()
208                    .position(|v| *v == 0x20)
209                    .unwrap_or(ShortName::SIZE_NAME)],
210            )
211        }
212    }
213    #[inline]
214    pub fn as_str(&self) -> &str {
215        let i = self.extension_len();
216        if i == 0 {
217            self.name()
218        } else {
219            unsafe { from_utf8_unchecked(&self.0[0..ShortName::SIZE_NAME + i]) }
220        }
221    }
222    #[inline]
223    pub fn checksum(&self) -> u8 {
224        let mut s = 0u8;
225        for i in self.0.iter() {
226            s = ((s & 1) << 7).wrapping_add((s >> 1) + *i);
227        }
228        s
229    }
230    #[inline(always)]
231    pub fn is_self(&self) -> bool {
232        self.0.eq(&ShortName::SELF.0)
233    }
234    #[inline(always)]
235    pub fn is_parent(&self) -> bool {
236        self.0.eq(&ShortName::PARENT.0)
237    }
238    #[inline(always)]
239    pub fn as_bytes(&self) -> &[u8] {
240        &self.0
241    }
242    #[inline(always)]
243    pub fn extension(&self) -> &str {
244        unsafe { from_utf8_unchecked(&self.0[ShortName::SIZE_NAME..ShortName::SIZE_NAME + self.extension_len()]) }
245    }
246    #[inline(always)]
247    pub fn fill(&mut self, v: &[u8]) {
248        ShortName::to_sfn(v, self);
249    }
250    #[inline]
251    pub fn fill_str(&mut self, v: impl AsRef<str>) {
252        self.fill(v.as_ref().as_bytes());
253    }
254
255    #[inline(always)]
256    pub(super) fn fill_inner(&mut self, v: &[u8]) {
257        self.0.copy_from_slice(&v[0..ShortName::SIZE])
258    }
259
260    #[inline(always)]
261    fn transform_char(v: u8) -> u8 {
262        match v {
263            0x00..=0x1F | 0x20 | 0x22 | 0x2A | 0x2B | 0x2C | 0x2F | 0x3A | 0x3B | 0x3C | 0x3D | 0x3E | 0x3F | 0x5B | 0x5C | 0x5D | 0x7C => b'+',
264            v if v >= b'a' && v <= b'z' => v - 0x20,
265            v => v,
266        }
267    }
268    fn to_sfn(b: &[u8], sfn: &mut ShortName) {
269        // Look for SELF and PARENT names
270        match b.len() {
271            0 => return,
272            1 if b[0] == b'.' => {
273                sfn.0.copy_from_slice(&ShortName::SELF.0);
274                return;
275            },
276            2 if b[0] == b'.' && b[1] == b'.' => {
277                sfn.0.copy_from_slice(&ShortName::PARENT.0);
278                return;
279            },
280            _ => (),
281        }
282        // Extract the extension first, if there is one.
283        // 'n' is the end of the 'name'.
284        let n = match b.iter().rposition(|v| *v == b'.') {
285            Some(i) => {
286                // We drop any chars more than 3 for the extension.
287                match b.len().saturating_sub(i + 1) {
288                    0 => (),
289                    1 => sfn.0[ShortName::SIZE_NAME] = b[i + 1],
290                    2 => {
291                        sfn.0[ShortName::SIZE_NAME] = b[i + 1];
292                        sfn.0[ShortName::SIZE_NAME + 1] = b[i + 2];
293                    },
294                    _ => sfn.0[ShortName::SIZE_NAME..ShortName::SIZE].copy_from_slice(&b[i + 1..i + 4]),
295                }
296                i
297            },
298            None => b.len(),
299        };
300        if n < ShortName::SIZE_NAME {
301            sfn.0[0..n].copy_from_slice(&b[0..n]);
302            sfn.0[n..ShortName::SIZE_NAME].fill(0x20)
303        } else if n == ShortName::SIZE_NAME {
304            sfn.0[0..ShortName::SIZE_NAME].copy_from_slice(&b[0..ShortName::SIZE_NAME])
305        } else {
306            sfn.0[0..ShortName::SIZE_NAME - 2].copy_from_slice(&b[0..ShortName::SIZE_NAME - 2]);
307            // NOTE(sf): We don't really know the "number" of files contained, like
308            //           we could read the dir first before setting this last bit
309            //           (or after setting it).
310            // NOTE(sf): ^ Would be a lot of work tbh.
311            sfn.0[ShortName::SIZE_NAME - 2] = b'~';
312            sfn.0[ShortName::SIZE_NAME - 1] = b'1';
313        }
314        // Flatten any spaces to '_'. We don't flatten spaces in extensions.
315        // This only goes the length of the original string, so the empty
316        // bytes stay as spaces.
317        for i in 0..cmp::min(n, ShortName::SIZE_NAME) {
318            if sfn.0[i] == 0x20 {
319                sfn.0[i] = b'_'
320            }
321        }
322        // Last, make sure every a-z is capitalized.
323        for i in sfn.0[0..ShortName::SIZE_NAME].iter_mut() {
324            *i = ShortName::transform_char(*i)
325        }
326    }
327
328    #[inline(always)]
329    fn extension_len(&self) -> usize {
330        match (
331            self.0[ShortName::SIZE_NAME],
332            self.0[ShortName::SIZE_NAME + 1],
333            self.0[ShortName::SIZE_NAME + 2],
334        ) {
335            (0x20, 0x20, 0x20) => 0,
336            (_, 0x20, 0x20) => 1,
337            (_, _, 0x20) => 2,
338            (..) => 3,
339        }
340    }
341}
342impl VolumeName {
343    pub const SIZE: usize = 0xBusize;
344
345    #[inline]
346    pub fn empty() -> VolumeName {
347        VolumeName([0x20u8; VolumeName::SIZE])
348    }
349
350    #[inline]
351    pub(super) fn from_slice(f: &FatVersion, v: &[u8]) -> VolumeName {
352        let i = match f {
353            FatVersion::Fat16(_) => 0x2B,
354            FatVersion::Fat32(_) => 0x47,
355        };
356        let mut n = VolumeName([0x20u8; VolumeName::SIZE]);
357        if (v.len().saturating_sub(i)) < VolumeName::SIZE {
358            n.0[0..(v.len().saturating_sub(i))].copy_from_slice(v)
359        } else {
360            n.0.copy_from_slice(&v[i..VolumeName::SIZE + i]);
361        }
362        n
363    }
364
365    #[inline(always)]
366    pub fn as_str(&self) -> &str {
367        unsafe { from_utf8_unchecked(&self.0[0..self.0.iter().position(|v| *v == 0x20).unwrap_or(VolumeName::SIZE)]) }
368    }
369    #[inline(always)]
370    pub fn as_bytes(&self) -> &[u8] {
371        &self.0
372    }
373}
374
375impl PartialEq for ShortName {
376    #[inline(always)]
377    fn eq(&self, other: &ShortName) -> bool {
378        self.0.eq(&other.0)
379    }
380}
381impl PartialEq<str> for ShortName {
382    #[inline(always)]
383    fn eq(&self, other: &str) -> bool {
384        self.eq(other.as_bytes())
385    }
386}
387impl PartialEq<[u8]> for ShortName {
388    #[inline]
389    fn eq(&self, other: &[u8]) -> bool {
390        let mut v = ShortName::empty();
391        v.fill(other);
392        v.0.eq(&self.0)
393    }
394}
395
396impl PartialEq for LongName {
397    #[inline(always)]
398    fn eq(&self, other: &LongName) -> bool {
399        self.0.eq(&other.0)
400    }
401}
402impl PartialEq<str> for LongName {
403    #[inline(always)]
404    fn eq(&self, other: &str) -> bool {
405        self.eq(other.as_bytes())
406    }
407}
408impl PartialEq<[u8]> for LongName {
409    #[inline(always)]
410    fn eq(&self, other: &[u8]) -> bool {
411        self.as_bytes().eq(other)
412    }
413}
414
415impl Deref for LongName {
416    type Target = [u8];
417
418    #[inline(always)]
419    fn deref(&self) -> &[u8] {
420        self.as_bytes()
421    }
422}
423impl AsRef<str> for LongName {
424    #[inline(always)]
425    fn as_ref(&self) -> &str {
426        self.as_str()
427    }
428}
429
430impl Clone for ShortName {
431    #[inline(always)]
432    fn clone(&self) -> ShortName {
433        ShortName(self.0.clone())
434    }
435}
436impl Deref for ShortName {
437    type Target = [u8];
438
439    #[inline(always)]
440    fn deref(&self) -> &[u8] {
441        &self.0
442    }
443}
444impl AsRef<str> for ShortName {
445    #[inline(always)]
446    fn as_ref(&self) -> &str {
447        self.as_str()
448    }
449}
450
451impl Clone for VolumeName {
452    #[inline(always)]
453    fn clone(&self) -> VolumeName {
454        VolumeName(self.0.clone())
455    }
456}
457impl Deref for VolumeName {
458    type Target = [u8];
459
460    #[inline(always)]
461    fn deref(&self) -> &[u8] {
462        self.as_bytes()
463    }
464}
465impl Default for VolumeName {
466    #[inline(always)]
467    fn default() -> VolumeName {
468        VolumeName::empty()
469    }
470}
471impl AsRef<str> for VolumeName {
472    #[inline(always)]
473    fn as_ref(&self) -> &str {
474        self.as_str()
475    }
476}
477
478#[cfg(feature = "debug")]
479mod display {
480    extern crate core;
481
482    use core::fmt::{Debug, Display, Formatter, Result, Write};
483    use core::iter::Iterator;
484    use core::result::Result::Ok;
485
486    use crate::fs::{LongName, ShortName, VolumeName};
487
488    impl Debug for LongName {
489        #[inline(always)]
490        fn fmt(&self, f: &mut Formatter<'_>) -> Result {
491            f.write_str(self.as_str())
492        }
493    }
494    impl Display for LongName {
495        #[inline(always)]
496        fn fmt(&self, f: &mut Formatter<'_>) -> Result {
497            f.write_str(self.as_str())
498        }
499    }
500
501    impl Debug for ShortName {
502        fn fmt(&self, f: &mut Formatter<'_>) -> Result {
503            for (i, v) in self.0.iter().enumerate() {
504                if i == 8 {
505                    f.write_char('.')?;
506                }
507                if *v == 0x20 {
508                    f.write_char('.')?;
509                } else {
510                    f.write_char(*v as _)?;
511                }
512            }
513            Ok(())
514        }
515    }
516    impl Display for ShortName {
517        #[inline]
518        fn fmt(&self, f: &mut Formatter<'_>) -> Result {
519            f.write_str(self.name())?;
520            f.write_char('.')?;
521            f.write_str(self.extension())
522        }
523    }
524
525    impl Debug for VolumeName {
526        #[inline(always)]
527        fn fmt(&self, f: &mut Formatter<'_>) -> Result {
528            f.write_str(self.as_str())
529        }
530    }
531    impl Display for VolumeName {
532        #[inline(always)]
533        fn fmt(&self, f: &mut Formatter<'_>) -> Result {
534            f.write_str(self.as_str())
535        }
536    }
537}