1use crate::*;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
4#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
5pub struct Flac {
6 pub audio: Audio,
7 pub dfla: Dfla,
8}
9
10impl Atom for Flac {
11 const KIND: FourCC = FourCC::new(b"fLaC");
12
13 fn decode_body<B: Buf>(buf: &mut B) -> Result<Self> {
14 let audio = Audio::decode(buf)?;
15
16 let mut dfla = None;
17 while let Some(atom) = Any::decode_maybe(buf)? {
18 match atom {
19 Any::Dfla(atom) => dfla = atom.into(),
20 unknown => Self::decode_unknown(&unknown)?,
21 }
22 }
23
24 Ok(Self {
25 audio,
26 dfla: dfla.ok_or(Error::MissingBox(Dfla::KIND))?,
27 })
28 }
29
30 fn encode_body<B: BufMut>(&self, buf: &mut B) -> Result<()> {
31 self.audio.encode(buf)?;
32 self.dfla.encode(buf)?;
33 Ok(())
34 }
35}
36
37#[derive(Debug, Clone, PartialEq, Eq)]
38#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
39pub enum FlacMetadataBlock {
40 StreamInfo {
41 minimum_block_size: u16,
42 maximum_block_size: u16,
43 minimum_frame_size: u24,
44 maximum_frame_size: u24,
45 sample_rate: u32,
46 num_channels_minus_one: u8,
47 bits_per_sample_minus_one: u8,
48 number_of_interchannel_samples: u64,
49 md5_checksum: Vec<u8>,
50 },
51 Padding,
52 Application,
53 SeekTable,
54 VorbisComment {
55 vendor_string: String,
56 comments: Vec<String>,
57 },
58 CueSheet,
59 Picture,
60 Reserved,
61 Forbidden,
62}
63
64impl FlacMetadataBlock {
65 fn encode_initial_byte<B: BufMut>(buf: &mut B, block_type: u8, is_last: bool) -> Result<()> {
66 match is_last {
67 true => (0x80 | block_type).encode(buf),
68 false => block_type.encode(buf),
69 }
70 }
71 fn encode<B: BufMut>(&self, buf: &mut B, is_last: bool) -> Result<()> {
72 match self {
73 FlacMetadataBlock::StreamInfo {
74 minimum_block_size,
75 maximum_block_size,
76 minimum_frame_size,
77 maximum_frame_size,
78 sample_rate,
79 num_channels_minus_one,
80 bits_per_sample_minus_one,
81 number_of_interchannel_samples,
82 md5_checksum,
83 } => {
84 Self::encode_initial_byte(buf, 0u8, is_last)?;
85 u24::from([0u8, 0u8, 0u8]).encode(buf)?;
87 let length_position = buf.len();
88 minimum_block_size.encode(buf)?;
89 maximum_block_size.encode(buf)?;
90 minimum_frame_size.encode(buf)?;
91 maximum_frame_size.encode(buf)?;
92 (((*sample_rate as u64) << 44)
93 | ((*num_channels_minus_one as u64) << 41)
94 | ((*bits_per_sample_minus_one as u64) << 36)
95 | number_of_interchannel_samples)
96 .encode(buf)?;
97 if md5_checksum.len() != 16 {
98 return Err(Error::MissingContent(
99 "StreamInfo.md5_checksum must be 16 bytes",
100 ));
101 }
102 md5_checksum.encode(buf)?;
103 let length: u24 = ((buf.len() - length_position) as u32)
104 .try_into()
105 .map_err(|_| Error::TooLarge(Dfla::KIND))?;
106 buf.set_slice(length_position - 3, &length.to_be_bytes());
107 }
108 FlacMetadataBlock::Padding => { }
109 FlacMetadataBlock::Application => { }
110 FlacMetadataBlock::SeekTable => { }
111 FlacMetadataBlock::VorbisComment {
112 vendor_string,
113 comments,
114 } => {
115 Self::encode_initial_byte(buf, 4u8, is_last)?;
116
117 u24::from([0u8, 0u8, 0u8]).encode(buf)?;
119 let length_position = buf.len();
120 let vendor_string_bytes = vendor_string.as_bytes();
121 let vendor_string_len: u32 = vendor_string_bytes.len() as u32;
122 vendor_string_len.to_le_bytes().encode(buf)?;
123 vendor_string_bytes.encode(buf)?;
124 let number_of_comments: u32 = comments.len() as u32;
125 number_of_comments.to_le_bytes().encode(buf)?;
126 for comment in comments {
127 let comment_bytes = comment.as_bytes();
128 let comment_len: u32 = comment_bytes.len() as u32;
129 comment_len.to_le_bytes().encode(buf)?;
130 comment_bytes.encode(buf)?;
131 }
132 let length: u24 = ((buf.len() - length_position) as u32)
133 .try_into()
134 .map_err(|_| Error::TooLarge(Dfla::KIND))?;
135 buf.set_slice(length_position - 3, &length.to_be_bytes());
136 }
137 FlacMetadataBlock::CueSheet => { }
138 FlacMetadataBlock::Picture => { }
139 FlacMetadataBlock::Reserved => { }
140 FlacMetadataBlock::Forbidden => { }
141 }
142 Ok(())
143 }
144}
145
146#[derive(Debug, Clone, PartialEq, Eq)]
148#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
149pub struct Dfla {
150 pub blocks: Vec<FlacMetadataBlock>,
151}
152
153fn parse_stream_info(arr: &[u8]) -> Result<FlacMetadataBlock> {
155 let buf = &mut std::io::Cursor::new(arr);
156 let minimum_block_size = u16::decode(buf)?;
157 let maximum_block_size = u16::decode(buf)?;
158 let minimum_frame_size = u24::decode(buf)?;
159 let maximum_frame_size = u24::decode(buf)?;
160 let temp64 = u64::decode(buf)?;
161 let sample_rate: u32 = (temp64 >> 44) as u32; let num_channels_minus_one: u8 = ((temp64 >> 41) & 0x07) as u8; let bits_per_sample_minus_one: u8 = ((temp64 >> 36) & 0x1F) as u8; let number_of_interchannel_samples: u64 = temp64 & 0x0000_000F_FFFF_FFFF; let md5_checksum: Vec<u8> = Vec::decode_exact(buf, 16)?;
166 Ok(FlacMetadataBlock::StreamInfo {
167 minimum_block_size,
168 maximum_block_size,
169 minimum_frame_size,
170 maximum_frame_size,
171 sample_rate,
172 num_channels_minus_one,
173 bits_per_sample_minus_one,
174 number_of_interchannel_samples,
175 md5_checksum,
176 })
177}
178
179fn parse_vorbis_comment(arr: &[u8]) -> Result<FlacMetadataBlock> {
183 let buf = &mut std::io::Cursor::new(arr);
184 let vendor_string_length = u32::from_le_bytes(<[u8; 4]>::decode(buf)?) as usize;
185 let vendor_string_bytes: Vec<u8> = Vec::decode_exact(buf, vendor_string_length)?;
186 let vendor_string = String::from_utf8_lossy(&vendor_string_bytes)
187 .trim_end_matches('\0')
188 .to_string();
189 let number_of_fields = u32::from_le_bytes(<[u8; 4]>::decode(buf)?) as usize;
190 if number_of_fields > buf.remaining() / 4 {
193 return Err(Error::OutOfBounds);
194 }
195 let mut comments = Vec::with_capacity(number_of_fields.min(4096));
196 for _ in 0..number_of_fields {
197 let field_length = u32::from_le_bytes(<[u8; 4]>::decode(buf)?) as usize;
198 let field_bytes: Vec<u8> = Vec::decode_exact(buf, field_length)?;
199 let comment = String::from_utf8_lossy(&field_bytes)
200 .trim_end_matches('\0')
201 .to_string();
202 comments.push(comment);
203 }
204 Ok(FlacMetadataBlock::VorbisComment {
205 vendor_string,
206 comments,
207 })
208}
209
210impl AtomExt for Dfla {
211 type Ext = ();
212
213 const KIND_EXT: FourCC = FourCC::new(b"dfLa");
214
215 fn decode_body_ext<B: Buf>(buf: &mut B, _ext: ()) -> Result<Self> {
216 let mut is_last_block = false;
217 let mut metadata_blocks = Vec::new();
218 while buf.has_remaining() && !is_last_block {
219 let initial_bytes = u32::decode(buf)?;
220 is_last_block = (initial_bytes & 0x80_00_00_00) == 0x80_00_00_00;
221 let block_type = ((initial_bytes >> 24) & 0x7f) as u8;
222 let length = initial_bytes & 0x00_FF_FF_FF;
223 let block_data: Vec<u8> = Vec::decode_exact(buf, length as usize)?;
224 let metadata_block = match block_type {
225 0 => parse_stream_info(&block_data)?,
226 1 => FlacMetadataBlock::Padding,
227 2 => FlacMetadataBlock::Application,
228 3 => FlacMetadataBlock::SeekTable,
229 4 => parse_vorbis_comment(&block_data)?,
230 5 => FlacMetadataBlock::CueSheet,
231 6 => FlacMetadataBlock::Picture,
232 7..=126 => FlacMetadataBlock::Reserved,
233 127 => FlacMetadataBlock::Forbidden,
234 _ => unreachable!("FLAC Metadata Block type is only 7 bits"),
235 };
236 metadata_blocks.push(metadata_block);
237 }
238 Ok(Dfla {
239 blocks: metadata_blocks,
240 })
241 }
242
243 fn encode_body_ext<B: BufMut>(&self, buf: &mut B) -> Result<()> {
244 if self.blocks.is_empty() {
245 return Err(Error::MissingContent("Streaminfo"));
246 }
247 for (i, metadata_block) in self.blocks.iter().enumerate() {
248 let is_last = i + 1 == self.blocks.len();
249 metadata_block.encode(buf, is_last)?;
250 }
251 Ok(())
252 }
253}
254
255#[cfg(test)]
256mod tests {
257 use super::*;
258
259 const ENCODED_DFLA: &[u8] = &[
261 0x00, 0x00, 0x00, 0x32, 0x64, 0x66, 0x4c, 0x61, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
262 0x22, 0x12, 0x00, 0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x23, 0x8e, 0x0a, 0xc4, 0x43, 0x70,
263 0x00, 0x01, 0xd8, 0x00, 0x75, 0x30, 0x88, 0x11, 0x2d, 0xd5, 0x7a, 0x13, 0xe7, 0xf7, 0x22,
264 0xd0, 0xee, 0x56, 0xae, 0xa3,
265 ];
266
267 #[test]
268 fn test_dfla_decode() {
269 let buf: &mut std::io::Cursor<&[u8]> = &mut std::io::Cursor::new(ENCODED_DFLA);
270
271 let dfla = Dfla::decode(buf).expect("failed to decode dfLa");
272
273 assert_eq!(
274 dfla,
275 Dfla {
276 blocks: vec![FlacMetadataBlock::StreamInfo {
277 minimum_block_size: 4608,
278 maximum_block_size: 4608,
279 minimum_frame_size: 16u32.try_into().expect("should fit in u24"),
280 maximum_frame_size: 9102u32.try_into().expect("should fit in u24"),
281 sample_rate: 44100,
282 num_channels_minus_one: 1,
283 bits_per_sample_minus_one: 23,
284 number_of_interchannel_samples: 120832,
285 md5_checksum: vec![
286 117, 48, 136, 17, 45, 213, 122, 19, 231, 247, 34, 208, 238, 86, 174, 163
287 ]
288 },]
289 }
290 );
291 }
292
293 #[test]
294 fn test_dfla_encode() {
295 let dfla = Dfla {
296 blocks: vec![FlacMetadataBlock::StreamInfo {
297 minimum_block_size: 4608,
298 maximum_block_size: 4608,
299 minimum_frame_size: 16u32.try_into().expect("should fit in u24"),
300 maximum_frame_size: 9102u32.try_into().expect("should fit in u24"),
301 sample_rate: 44100,
302 num_channels_minus_one: 1,
303 bits_per_sample_minus_one: 23,
304 number_of_interchannel_samples: 120832,
305 md5_checksum: vec![
306 117, 48, 136, 17, 45, 213, 122, 19, 231, 247, 34, 208, 238, 86, 174, 163,
307 ],
308 }],
309 };
310
311 let mut buf = Vec::new();
312 dfla.encode(&mut buf).unwrap();
313
314 assert_eq!(buf.as_slice(), ENCODED_DFLA);
315 }
316
317 const ENCODED_DFLA_2: &[u8] = &[
319 0x00, 0x00, 0x00, 0x7c, 0x64, 0x66, 0x4c, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
320 0x22, 0x12, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xc4, 0x40, 0x70,
321 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
322 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x46, 0x20, 0x00, 0x00, 0x00, 0x72, 0x65,
323 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x6c, 0x69, 0x62, 0x46, 0x4c, 0x41, 0x43,
324 0x20, 0x31, 0x2e, 0x34, 0x2e, 0x33, 0x20, 0x32, 0x30, 0x32, 0x33, 0x30, 0x36, 0x32, 0x33,
325 0x01, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x44, 0x45, 0x53, 0x43, 0x52, 0x49, 0x50,
326 0x54, 0x49, 0x4f, 0x4e, 0x3d, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x74, 0x65, 0x73, 0x74, 0x20,
327 0x77, 0x61, 0x76, 0x65,
328 ];
329
330 #[test]
331 fn test_dfla2_decode() {
332 let buf: &mut std::io::Cursor<&[u8]> = &mut std::io::Cursor::new(ENCODED_DFLA_2);
333
334 let dfla = Dfla::decode(buf).expect("failed to decode dfLa");
335
336 assert_eq!(
337 dfla,
338 Dfla {
339 blocks: vec![
340 FlacMetadataBlock::StreamInfo {
341 minimum_block_size: 4608,
342 maximum_block_size: 4608,
343 minimum_frame_size: 0u32.try_into().expect("should fit in u24"),
344 maximum_frame_size: 0u32.try_into().expect("should fit in u24"),
345 sample_rate: 44100,
346 num_channels_minus_one: 0,
347 bits_per_sample_minus_one: 7,
348 number_of_interchannel_samples: 0,
349 md5_checksum: vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
350 },
351 FlacMetadataBlock::VorbisComment {
352 vendor_string: "reference libFLAC 1.4.3 20230623".into(),
353 comments: vec!["DESCRIPTION=audiotest wave".into()],
354 },
355 ]
356 }
357 );
358 }
359
360 const ENCODED_DFLA_VORBIS_HUGE_COUNT: &[u8] = &[
363 0x84, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
367 ];
368
369 #[test]
370 fn test_dfla_vorbis_huge_count() {
371 let buf = &mut std::io::Cursor::new(ENCODED_DFLA_VORBIS_HUGE_COUNT);
372 assert!(matches!(
373 Dfla::decode_body_ext(buf, ()),
374 Err(Error::OutOfBounds)
375 ));
376 }
377
378 #[test]
379 fn test_dfla2_encode() {
380 let dfla = Dfla {
381 blocks: vec![
382 FlacMetadataBlock::StreamInfo {
383 minimum_block_size: 4608,
384 maximum_block_size: 4608,
385 minimum_frame_size: 0u32.try_into().expect("should fit in u24"),
386 maximum_frame_size: 0u32.try_into().expect("should fit in u24"),
387 sample_rate: 44100,
388 num_channels_minus_one: 0,
389 bits_per_sample_minus_one: 7,
390 number_of_interchannel_samples: 0,
391 md5_checksum: vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
392 },
393 FlacMetadataBlock::VorbisComment {
394 vendor_string: "reference libFLAC 1.4.3 20230623".into(),
395 comments: vec!["DESCRIPTION=audiotest wave".into()],
396 },
397 ],
398 };
399
400 let mut buf = Vec::new();
401 dfla.encode(&mut buf).unwrap();
402
403 assert_eq!(buf.as_slice(), ENCODED_DFLA_2);
404 }
405}