1use crate::*;
2
3const DATA_4CC: FourCC = FourCC::new(b"data");
4const TYPE_INDICATOR_UTF8: u32 = 1u32;
5
6#[derive(Debug, Clone, PartialEq, Eq)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8pub struct Tool {
9 pub country_indicator: u16,
10 pub language_indicator: u16,
11 pub text: String,
12}
13
14impl Tool {
15 pub fn new(country_indicator: u16, language_indicator: u16, text: String) -> Result<Self> {
16 Ok(Self {
17 country_indicator,
18 language_indicator,
19 text,
20 })
21 }
22}
23
24impl Atom for Tool {
25 const KIND: FourCC = FourCC::new(b"\xa9too");
26
27 fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
28 let type_indicator_or_len = u32::decode(buf)?;
29 match type_indicator_or_len {
30 1 => {
31 let country_indicator = u16::decode(buf)?;
34 let language_indicator = u16::decode(buf)?;
35 Ok(Tool {
36 country_indicator,
37 language_indicator,
38 text: String::decode(buf)?,
39 })
40 }
41 _ => {
42 let fourcc = FourCC::decode(buf)?;
45 if fourcc != DATA_4CC {
46 return Err(Error::UnexpectedBox(fourcc));
47 }
48 let type_indicator = u32::decode(buf)?;
49 if type_indicator != TYPE_INDICATOR_UTF8 {
50 return Err(Error::Unsupported(
51 "Only UTF-8 text is supported in ilst tool box",
52 ));
53 }
54 let country_indicator = u16::decode(buf)?;
55 let language_indicator = u16::decode(buf)?;
56 let remaining_bytes = buf.remaining();
57 let body = &mut buf.slice(remaining_bytes);
58 let text = String::from_utf8(body.to_vec()).map_err(|_| Error::InvalidSize)?;
59 buf.advance(remaining_bytes);
60 Ok(Tool {
61 country_indicator,
62 language_indicator,
63 text,
64 })
65 }
66 }
67 }
68
69 fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
70 let text_bytes = self.text.as_bytes();
71 let nested_len = (4 + 4 + 4 + 2 + 2 + text_bytes.len()) as u32;
76 nested_len.encode(buf)?;
77 DATA_4CC.encode(buf)?;
78 TYPE_INDICATOR_UTF8.encode(buf)?;
79 self.country_indicator.encode(buf)?;
80 self.language_indicator.encode(buf)?;
81 text_bytes.encode(buf)?;
82 Ok(())
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 #[test]
91 fn test_ilst_tool_short_style() {
92 let buf = vec![
93 0, 0, 0, 28, 0xa9, b't', b'o', b'o', 0, 0, 0, 1, 0, 0, 0, 0, b'L', b'a', b'v', b'f',
94 b'6', b'1', b'.', b'7', b'.', b'1', b'0', b'0',
95 ];
96
97 let parse_result = Tool::decode(&mut buf.as_slice());
98 assert!(parse_result.is_ok());
99 let ctoo = parse_result.unwrap();
100 assert_eq!(ctoo.country_indicator, 0);
101 assert_eq!(ctoo.language_indicator, 0);
102 assert_eq!(ctoo.text, "Lavf61.7.100");
103 }
104
105 const ENCODED_CTOO: &[u8] = &[
106 0x00, 0x00, 0x00, 0x24, 0xA9, 0x74, 0x6F, 0x6F, 0x00, 0x00, 0x00, 0x1C, b'd', b'a', b't',
107 b'a', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, b'L', b'a', b'v', b'f', b'6', b'1',
108 b'.', b'7', b'.', b'1', b'0', b'0',
109 ];
110
111 #[test]
112 fn test_ilst_tool_long_style() {
113 let inbuf: &mut std::io::Cursor<&&[u8]> = &mut std::io::Cursor::new(&ENCODED_CTOO);
114 let parse_result = Tool::decode(inbuf);
115 assert!(parse_result.is_ok());
116 let ctoo = parse_result.unwrap();
117 assert_eq!(ctoo.country_indicator, 0);
118 assert_eq!(ctoo.language_indicator, 0);
119 assert_eq!(ctoo.text, "Lavf61.7.100");
120
121 let mut outbuf = Vec::new();
122 ctoo.encode(&mut outbuf).unwrap();
123
124 assert_eq!(outbuf.as_slice(), ENCODED_CTOO);
125 }
126
127 #[test]
128 fn test_bad_nested_atom() {
129 let buf = vec![
130 0x00, 0x00, 0x00, 28, 0xA9, 0x74, 0x6F, 0x6F, 0x00, 0x00, 0x00, 0x1C, b'd', b'a', b't',
131 b'x', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, b't', b'e', b's', b't',
132 ];
133
134 let parse_result = Tool::decode(&mut buf.as_slice());
135 assert!(parse_result.is_err());
136 match parse_result.err().unwrap() {
137 Error::UnexpectedBox(four_cc) => {
138 assert_eq!(four_cc, FourCC::new(b"datx"));
139 }
140 _ => {
141 panic!("unexpected error");
142 }
143 }
144 }
145
146 #[test]
147 fn test_bad_type_indicator() {
148 let buf = vec![
149 0x00, 0x00, 0x00, 28, 0xA9, 0x74, 0x6F, 0x6F, 0x00, 0x00, 0x00, 0x1C, b'd', b'a', b't',
150 b'a', 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, b't', b'e', b's', b't',
151 ];
152
153 let parse_result = Tool::decode(&mut buf.as_slice());
154 assert!(parse_result.is_err());
155 match parse_result.err().unwrap() {
156 Error::Unsupported(s) => {
157 assert_eq!(s, "Only UTF-8 text is supported in ilst tool box")
158 }
159 _ => {
160 panic!("unexpected error");
161 }
162 }
163 }
164}