Skip to main content

mp4_edit/atom/
fourcc.rs

1use derive_more::Deref;
2use std::fmt;
3
4#[derive(Default, Clone, Copy, Deref, PartialEq, Eq)]
5pub struct FourCC(pub(crate) [u8; 4]);
6
7impl FourCC {
8    pub const fn new(typ: &[u8; 4]) -> Self {
9        Self(*typ)
10    }
11
12    pub fn into_bytes(self) -> [u8; 4] {
13        self.0
14    }
15
16    pub fn as_bytes(&self) -> &[u8; 4] {
17        &self.0
18    }
19
20    pub fn as_str(&self) -> &str {
21        std::str::from_utf8(&self.0).unwrap_or("????")
22    }
23}
24
25impl From<[u8; 4]> for FourCC {
26    fn from(value: [u8; 4]) -> Self {
27        FourCC(value)
28    }
29}
30
31impl PartialEq<&[u8; 4]> for FourCC {
32    fn eq(&self, other: &&[u8; 4]) -> bool {
33        &self.0 == *other
34    }
35}
36
37impl PartialEq<[u8; 4]> for FourCC {
38    fn eq(&self, other: &[u8; 4]) -> bool {
39        &self.0 == other
40    }
41}
42
43impl fmt::Display for FourCC {
44    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45        let fourcc = std::str::from_utf8(&self.0)
46            .map_or_else(|_| convert_mac_roman_to_utf8(&self.0), ToOwned::to_owned);
47        if fourcc
48            .trim_matches(|c| !char::is_ascii_alphanumeric(&c))
49            .is_empty()
50        {
51            // show bytes when not valid
52            fmt::Debug::fmt(&self.0, f)
53        } else {
54            write!(f, "{fourcc}")
55        }
56    }
57}
58
59impl fmt::Debug for FourCC {
60    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61        write!(f, "FourCC({self})")
62    }
63}
64
65fn convert_mac_roman_to_utf8(bytes: &[u8]) -> String {
66    let mut result = String::new();
67    for &byte in bytes {
68        match byte {
69            0xA9 => result.push('©'), // Copyright symbol
70            0xAE => result.push('®'), // Registered trademark symbol
71            0x99 => result.push('™'), // Trademark symbol
72            // For other bytes, treat as ASCII if valid, otherwise use replacement char
73            b if b.is_ascii() => result.push(b as char),
74            _ => result.push('�'),
75        }
76    }
77    result
78}