mp4_atom/meta/ilst/
mod.rs1mod covr;
2mod cprt;
3mod data;
4mod desc;
5mod name;
6mod tool;
7mod year;
8
9pub use covr::*;
10pub use cprt::*;
11pub use desc::*;
12pub use name::*;
13pub use tool::*;
14pub use year::*;
15
16use crate::*;
17
18#[derive(Debug, Clone, PartialEq, Eq, Default)]
19#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
20pub struct Ilst {
21 pub name: Option<Name>,
22 pub year: Option<Year>, pub covr: Option<Covr>,
24 pub desc: Option<Desc>,
25 pub ctoo: Option<Tool>, pub cprt: Option<Copyright>, }
28
29impl Atom for Ilst {
30 const KIND: FourCC = FourCC::new(b"ilst");
31
32 fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
33 let mut name = None;
34 let mut year = None;
35 let mut covr = None;
36 let mut desc = None;
37 let mut ctoo = None;
38 let mut cprt = None;
39
40 while let Some(header) = Header::decode_maybe(buf)? {
46 let size = header.size.unwrap_or(buf.remaining());
47 if size > buf.remaining() {
48 break;
51 }
52 match header.kind {
53 Name::KIND => name = Some(Name::decode_atom(&header, buf)?),
54 Year::KIND => year = Some(Year::decode_atom(&header, buf)?),
55 Covr::KIND => covr = Some(Covr::decode_atom(&header, buf)?),
56 Desc::KIND => desc = Some(Desc::decode_atom(&header, buf)?),
57 Tool::KIND => ctoo = Some(Tool::decode_atom(&header, buf)?),
58 Copyright::KIND => cprt = Some(Copyright::decode_atom(&header, buf)?),
59 kind => {
60 let body = Vec::decode(&mut buf.slice(size))?;
61 buf.advance(size);
62 Self::decode_unknown(&Any::Unknown(kind, body))?;
63 }
64 }
65 }
66
67 Ok(Ilst {
68 name,
69 year,
70 covr,
71 desc,
72 ctoo,
73 cprt,
74 })
75 }
76
77 fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
78 self.name.encode(buf)?;
79 self.year.encode(buf)?;
80 self.covr.encode(buf)?;
81 self.desc.encode(buf)?;
82 self.ctoo.encode(buf)?;
83 self.cprt.encode(buf)?;
84 Ok(())
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91
92 #[test]
93 fn test_ilst() {
94 let expected = Ilst {
95 year: Year("src_year".to_string()).into(),
96 ..Default::default()
97 };
98
99 let mut buf = Vec::new();
100 expected.encode(&mut buf).unwrap();
101
102 let mut buf = buf.as_ref();
103 let decoded = Ilst::decode(&mut buf).unwrap();
104 assert_eq!(decoded, expected);
105 }
106
107 #[test]
108 fn test_ilst_empty() {
109 let expected = Ilst::default();
110 let mut buf = Vec::new();
111 expected.encode(&mut buf).unwrap();
112
113 let mut buf = buf.as_ref();
114 let decoded = Ilst::decode(&mut buf).unwrap();
115 assert_eq!(decoded, expected);
116 }
117
118 fn atom_box(fourcc: &[u8; 4], body: &[u8]) -> Vec<u8> {
120 let mut v = Vec::with_capacity(8 + body.len());
121 v.extend_from_slice(&((8 + body.len()) as u32).to_be_bytes());
122 v.extend_from_slice(fourcc);
123 v.extend_from_slice(body);
124 v
125 }
126
127 #[test]
132 fn test_ilst_itunes_cprt() {
133 let text = b"(c) 2026 Example";
134 let mut data_body = Vec::new();
135 data_body.extend_from_slice(&1u32.to_be_bytes()); data_body.extend_from_slice(&0u32.to_be_bytes()); data_body.extend_from_slice(text);
138 let cprt_item = atom_box(b"cprt", &atom_box(b"data", &data_body));
139 let encoded = atom_box(b"ilst", &cprt_item);
140
141 let decoded = Ilst::decode(&mut encoded.as_slice()).unwrap();
142 assert_eq!(
143 decoded,
144 Ilst {
145 cprt: Some(Copyright {
146 country_indicator: 0,
147 language_indicator: 0,
148 text: "(c) 2026 Example".into(),
149 }),
150 ..Default::default()
151 }
152 );
153
154 let mut reencoded = Vec::new();
156 decoded.encode(&mut reencoded).unwrap();
157 assert_eq!(reencoded, encoded);
158 }
159
160 #[test]
163 fn test_ilst_unknown_item() {
164 let mut data_body = Vec::new();
165 data_body.extend_from_slice(&1u32.to_be_bytes());
166 data_body.extend_from_slice(&0u32.to_be_bytes());
167 data_body.extend_from_slice(b"Some Artist");
168 let art_item = atom_box(b"\xa9ART", &atom_box(b"data", &data_body));
169 let encoded = atom_box(b"ilst", &art_item);
170
171 let result = Ilst::decode(&mut encoded.as_slice());
172 match result {
173 Err(Error::UnexpectedBox(kind)) => assert_eq!(kind, FourCC::new(b"\xa9ART")),
174 other => panic!("expected UnexpectedBox, got {other:?}"),
175 }
176 }
177}