1use crate::bitstream::BitReader;
12use crate::error::FlacError;
13
14pub(crate) const FLAC_MARKER: &[u8; 4] = b"fLaC";
16
17const STREAMINFO_LEN: usize = 34;
19
20#[derive(Debug, Clone, PartialEq, Eq)]
22pub struct StreamInfo {
23 pub min_block_size: u16,
24 pub max_block_size: u16,
25 pub min_frame_size: u32,
26 pub max_frame_size: u32,
27 pub sample_rate: u32,
28 pub channels: u8,
29 pub bits_per_sample: u8,
30 pub total_samples: u64,
32 pub md5: [u8; 16],
34}
35
36#[derive(Debug)]
39pub(crate) struct Header {
40 pub stream_info: StreamInfo,
41 pub frame_start: usize,
42}
43
44pub(crate) fn read_header(bytes: &[u8]) -> Result<Header, FlacError> {
47 if bytes.len() < 4 || &bytes[0..4] != FLAC_MARKER {
48 return Err(FlacError::NotFlac);
49 }
50 let mut pos = 4;
51 let mut stream_info: Option<StreamInfo> = None;
52
53 loop {
54 if pos + 4 > bytes.len() {
56 return Err(FlacError::Truncated);
57 }
58 let header = bytes[pos];
59 let is_last = header & 0x80 != 0;
60 let block_type = header & 0x7F;
61 let length = ((bytes[pos + 1] as usize) << 16)
62 | ((bytes[pos + 2] as usize) << 8)
63 | bytes[pos + 3] as usize;
64 pos += 4;
65 let end = pos.checked_add(length).ok_or(FlacError::Truncated)?;
68 if end > bytes.len() {
69 return Err(FlacError::Truncated);
70 }
71
72 if block_type == 0 {
73 if length != STREAMINFO_LEN {
75 return Err(FlacError::CorruptStream(format!(
76 "STREAMINFO length is {length}, expected {STREAMINFO_LEN}"
77 )));
78 }
79 if stream_info.is_some() {
80 return Err(FlacError::CorruptStream(
81 "more than one STREAMINFO block".into(),
82 ));
83 }
84 stream_info = Some(parse_stream_info(&bytes[pos..pos + length])?);
85 } else if block_type == 127 {
86 return Err(FlacError::CorruptStream(
87 "invalid metadata block type 127".into(),
88 ));
89 }
90 pos += length;
93 if is_last {
94 break;
95 }
96 }
97
98 let stream_info =
99 stream_info.ok_or_else(|| FlacError::CorruptStream("no STREAMINFO block found".into()))?;
100 Ok(Header {
101 stream_info,
102 frame_start: pos,
103 })
104}
105
106fn parse_stream_info(body: &[u8]) -> Result<StreamInfo, FlacError> {
107 let mut r = BitReader::new(body);
108 let min_block_size = r.read_u32(16)? as u16;
109 let max_block_size = r.read_u32(16)? as u16;
110 let min_frame_size = r.read_u32(24)?;
111 let max_frame_size = r.read_u32(24)?;
112 let sample_rate = r.read_u32(20)?;
113 let channels = r.read_u32(3)? as u8 + 1;
114 let bits_per_sample = r.read_u32(5)? as u8 + 1;
115 let total_samples = r.read_u64(36)?;
116 let mut md5 = [0u8; 16];
117 for b in md5.iter_mut() {
118 *b = r.read_u32(8)? as u8;
119 }
120
121 if sample_rate == 0 {
122 return Err(FlacError::CorruptStream(
123 "STREAMINFO sample rate is zero".into(),
124 ));
125 }
126
127 Ok(StreamInfo {
128 min_block_size,
129 max_block_size,
130 min_frame_size,
131 max_frame_size,
132 sample_rate,
133 channels,
134 bits_per_sample,
135 total_samples,
136 md5,
137 })
138}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143
144 fn synthetic_header() -> Vec<u8> {
146 let mut v = Vec::new();
147 v.extend_from_slice(FLAC_MARKER);
148 v.push(0x80);
150 v.extend_from_slice(&[0x00, 0x00, 0x22]);
151 v.extend_from_slice(&[0x10, 0x00, 0x10, 0x00]);
154 v.extend_from_slice(&[0, 0, 0, 0, 0, 0]);
156 let mut bits = Vec::new();
161 push_bits(&mut bits, 44100, 20);
162 push_bits(&mut bits, 1, 3); push_bits(&mut bits, 15, 5); push_bits(&mut bits, 88200, 36); let packed = pack(&bits);
166 v.extend_from_slice(&packed);
167 v.extend_from_slice(&[0xAB; 16]);
169 v
170 }
171
172 fn push_bits(out: &mut Vec<u8>, value: u64, n: u32) {
173 for i in (0..n).rev() {
174 out.push(((value >> i) & 1) as u8);
175 }
176 }
177
178 fn pack(bits: &[u8]) -> Vec<u8> {
179 let mut out = vec![0u8; bits.len().div_ceil(8)];
180 for (i, &bit) in bits.iter().enumerate() {
181 if bit != 0 {
182 out[i / 8] |= 1 << (7 - (i % 8));
183 }
184 }
185 out
186 }
187
188 #[test]
189 fn rejects_non_flac() {
190 assert_eq!(read_header(b"RIFFxxxx").unwrap_err(), FlacError::NotFlac);
191 assert_eq!(read_header(b"fL").unwrap_err(), FlacError::NotFlac);
192 }
193
194 #[test]
195 fn parses_synthetic_streaminfo() {
196 let h = read_header(&synthetic_header()).unwrap();
197 let si = &h.stream_info;
198 assert_eq!(si.min_block_size, 4096);
199 assert_eq!(si.max_block_size, 4096);
200 assert_eq!(si.sample_rate, 44100);
201 assert_eq!(si.channels, 2);
202 assert_eq!(si.bits_per_sample, 16);
203 assert_eq!(si.total_samples, 88200);
204 assert_eq!(si.md5, [0xAB; 16]);
205 assert_eq!(h.frame_start, synthetic_header().len());
206 }
207
208 #[test]
209 fn truncated_header_errors() {
210 let full = synthetic_header();
211 assert_eq!(read_header(&full[..10]).unwrap_err(), FlacError::Truncated);
212 }
213
214 #[test]
215 fn rejects_zero_sample_rate() {
216 let mut h = synthetic_header();
217 h[18] = 0;
219 h[19] = 0;
220 h[20] &= 0x0F; assert!(matches!(read_header(&h), Err(FlacError::CorruptStream(_))));
222 }
223}