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