1#![forbid(unsafe_code)]
17#![allow(clippy::cast_possible_truncation)]
18#![allow(clippy::cast_lossless)]
19#![allow(clippy::cast_sign_loss)]
20#![allow(clippy::cast_possible_wrap)]
21
22use super::lpc::restore_signal;
23use super::rice::RiceDecoder;
24use crate::error::{CodecError, CodecResult};
25
26fn crc16(data: &[u8]) -> u16 {
31 const POLY: u16 = 0x8005;
32 let mut crc = 0u16;
33 for &byte in data {
34 crc ^= u16::from(byte) << 8;
35 for _ in 0..8 {
36 if crc & 0x8000 != 0 {
37 crc = (crc << 1) ^ POLY;
38 } else {
39 crc <<= 1;
40 }
41 }
42 }
43 crc
44}
45
46struct BitReader<'a> {
51 data: &'a [u8],
52 pos: usize, bit: u8, }
55
56impl<'a> BitReader<'a> {
57 fn new(data: &'a [u8]) -> Self {
58 Self {
59 data,
60 pos: 0,
61 bit: 0,
62 }
63 }
64
65 fn byte_offset(&self) -> usize {
66 self.pos
67 }
68
69 fn read_bit(&mut self) -> Option<u8> {
70 if self.pos >= self.data.len() {
71 return None;
72 }
73 let v = (self.data[self.pos] >> (7 - self.bit)) & 1;
74 self.bit += 1;
75 if self.bit == 8 {
76 self.bit = 0;
77 self.pos += 1;
78 }
79 Some(v)
80 }
81
82 fn read_bits(&mut self, n: usize) -> Option<u32> {
83 let mut v = 0u32;
84 for _ in 0..n {
85 v = (v << 1) | u32::from(self.read_bit()?);
86 }
87 Some(v)
88 }
89
90 fn read_byte(&mut self) -> Option<u8> {
91 if self.bit != 0 {
93 self.bit = 0;
94 self.pos += 1;
95 }
96 if self.pos >= self.data.len() {
97 return None;
98 }
99 let b = self.data[self.pos];
100 self.pos += 1;
101 Some(b)
102 }
103
104 fn read_be_u16(&mut self) -> Option<u16> {
105 let hi = u16::from(self.read_byte()?);
106 let lo = u16::from(self.read_byte()?);
107 Some((hi << 8) | lo)
108 }
109
110 fn read_be_i16(&mut self) -> Option<i16> {
111 self.read_be_u16().map(|v| v as i16)
112 }
113
114 fn read_utf8_coded(&mut self) -> Option<u64> {
117 let b0 = self.read_byte()?;
118 if b0 & 0x80 == 0 {
119 return Some(u64::from(b0));
121 }
122 let extra = if b0 & 0xF8 == 0xF0 {
124 3usize } else if b0 & 0xF0 == 0xE0 {
126 2usize } else if b0 & 0xE0 == 0xC0 {
128 1usize } else {
130 return None; };
132
133 let mask: u8 = match extra {
134 3 => 0x07,
135 2 => 0x0F,
136 1 => 0x1F,
137 _ => 0x1F,
138 };
139 let mut val = u64::from(b0 & mask);
140 for _ in 0..extra {
141 let cb = self.read_byte()?;
142 if cb & 0xC0 != 0x80 {
143 return None; }
145 val = (val << 6) | u64::from(cb & 0x3F);
146 }
147 Some(val)
148 }
149
150 fn align_to_byte(&mut self) {
152 if self.bit != 0 {
153 self.bit = 0;
154 self.pos += 1;
155 }
156 }
157
158 fn remaining_bytes(&self) -> usize {
159 if self.bit != 0 {
160 self.data.len().saturating_sub(self.pos + 1)
161 } else {
162 self.data.len().saturating_sub(self.pos)
163 }
164 }
165
166 fn slice_from_current(&self) -> &[u8] {
167 if self.pos < self.data.len() {
168 &self.data[self.pos..]
169 } else {
170 &[]
171 }
172 }
173}
174
175#[derive(Clone, Debug, Default)]
181pub struct FlacStreamInfo {
182 pub min_block_size: u16,
184 pub max_block_size: u16,
186 pub min_frame_size: u32,
188 pub max_frame_size: u32,
190 pub sample_rate: u32,
192 pub channels: u8,
194 pub bits_per_sample: u8,
196 pub total_samples: u64,
198 pub md5_signature: [u8; 16],
200}
201
202#[derive(Clone, Debug, Default)]
204pub struct FlacVorbisComment {
205 pub vendor: String,
207 pub comments: Vec<(String, String)>,
209}
210
211#[derive(Clone, Debug)]
213pub struct DecodedBlock {
214 pub samples: Vec<i32>,
216 pub sample_number: u64,
218 pub block_size: usize,
220 pub channels: usize,
222}
223
224pub struct FlacDecoder {
226 pub stream_info: Option<FlacStreamInfo>,
228 pub comment: Option<FlacVorbisComment>,
230 header_parsed: bool,
232}
233
234impl FlacDecoder {
235 #[must_use]
237 pub fn new() -> Self {
238 Self {
239 stream_info: None,
240 comment: None,
241 header_parsed: false,
242 }
243 }
244
245 #[must_use]
247 pub fn stream_info(&self) -> Option<&FlacStreamInfo> {
248 self.stream_info.as_ref()
249 }
250
251 #[must_use]
253 pub fn comment_block(&self) -> Option<&FlacVorbisComment> {
254 self.comment.as_ref()
255 }
256
257 pub fn parse_metadata(&mut self, data: &[u8]) -> Result<(), CodecError> {
270 if data.len() < 4 {
271 return Err(CodecError::InvalidData(
272 "Stream too short for fLaC marker".to_string(),
273 ));
274 }
275 if &data[..4] != b"fLaC" {
276 return Err(CodecError::InvalidData(
277 "Missing fLaC magic marker".to_string(),
278 ));
279 }
280
281 let mut pos = 4usize;
282
283 loop {
284 if pos + 4 > data.len() {
285 return Err(CodecError::InvalidData(
286 "Truncated metadata block header".to_string(),
287 ));
288 }
289
290 let header_byte = data[pos];
291 let is_last = (header_byte & 0x80) != 0;
292 let block_type = header_byte & 0x7F;
293 let length = (u32::from(data[pos + 1]) << 16)
294 | (u32::from(data[pos + 2]) << 8)
295 | u32::from(data[pos + 3]);
296 pos += 4;
297
298 let block_end = pos + length as usize;
299 if block_end > data.len() {
300 return Err(CodecError::InvalidData(format!(
301 "Metadata block (type {block_type}) extends beyond data"
302 )));
303 }
304
305 let block_data = &data[pos..block_end];
306
307 match block_type {
308 0 => {
309 self.stream_info = Some(Self::parse_streaminfo_block(block_data)?);
311 }
312 4 => {
313 self.comment = Some(Self::parse_vorbis_comment_block(block_data)?);
315 }
316 _ => {
317 }
320 }
321
322 pos = block_end;
323
324 if is_last {
325 break;
326 }
327 }
328
329 if self.stream_info.is_none() {
330 return Err(CodecError::InvalidData(
331 "No STREAMINFO block found in metadata".to_string(),
332 ));
333 }
334
335 self.header_parsed = true;
336 Ok(())
337 }
338
339 pub fn probe(data: &[u8]) -> Result<FlacStreamInfo, CodecError> {
347 if data.len() < 8 {
348 return Err(CodecError::InvalidData(
349 "Stream too short for FLAC probe".to_string(),
350 ));
351 }
352 if &data[..4] != b"fLaC" {
353 return Err(CodecError::InvalidData(
354 "Missing fLaC magic marker".to_string(),
355 ));
356 }
357
358 let header_byte = data[4];
359 let block_type = header_byte & 0x7F;
360 if block_type != 0 {
361 return Err(CodecError::InvalidData(format!(
362 "Expected STREAMINFO as first block, got type {block_type}"
363 )));
364 }
365
366 let length = (u32::from(data[5]) << 16) | (u32::from(data[6]) << 8) | u32::from(data[7]);
367 let block_end = 8 + length as usize;
368 if block_end > data.len() {
369 return Err(CodecError::InvalidData(
370 "STREAMINFO block extends beyond data in probe".to_string(),
371 ));
372 }
373
374 Self::parse_streaminfo_block(&data[8..block_end])
375 }
376
377 fn parse_streaminfo_block(si_data: &[u8]) -> Result<FlacStreamInfo, CodecError> {
379 if si_data.len() < 18 {
381 return Err(CodecError::InvalidData(
382 "STREAMINFO block too short".to_string(),
383 ));
384 }
385
386 let min_block_size = (u16::from(si_data[0]) << 8) | u16::from(si_data[1]);
387 let max_block_size = (u16::from(si_data[2]) << 8) | u16::from(si_data[3]);
388
389 let min_frame_size =
390 (u32::from(si_data[4]) << 16) | (u32::from(si_data[5]) << 8) | u32::from(si_data[6]);
391 let max_frame_size =
392 (u32::from(si_data[7]) << 16) | (u32::from(si_data[8]) << 8) | u32::from(si_data[9]);
393
394 let packed = (u32::from(si_data[10]) << 24)
396 | (u32::from(si_data[11]) << 16)
397 | (u32::from(si_data[12]) << 8)
398 | u32::from(si_data[13]);
399
400 let sample_rate = packed >> 12;
401 let channels = (((packed >> 9) & 0x07) + 1) as u8;
402 let bits_per_sample = (((packed >> 4) & 0x1F) + 1) as u8;
403 let total_samples_high = u64::from(packed & 0x0F);
404
405 let total_samples_low = if si_data.len() >= 18 {
407 (u64::from(si_data[14]) << 24)
408 | (u64::from(si_data[15]) << 16)
409 | (u64::from(si_data[16]) << 8)
410 | u64::from(si_data[17])
411 } else {
412 0
413 };
414 let total_samples = (total_samples_high << 32) | total_samples_low;
415
416 let mut md5_signature = [0u8; 16];
418 if si_data.len() >= 34 {
419 md5_signature.copy_from_slice(&si_data[18..34]);
420 }
421
422 Ok(FlacStreamInfo {
423 min_block_size,
424 max_block_size,
425 min_frame_size,
426 max_frame_size,
427 sample_rate,
428 channels,
429 bits_per_sample,
430 total_samples,
431 md5_signature,
432 })
433 }
434
435 fn parse_vorbis_comment_block(data: &[u8]) -> Result<FlacVorbisComment, CodecError> {
439 let mut pos = 0usize;
440
441 let read_le_u32 = |d: &[u8], p: usize| -> Result<u32, CodecError> {
443 if p + 4 > d.len() {
444 return Err(CodecError::InvalidData(
445 "VORBIS_COMMENT: unexpected end of data".to_string(),
446 ));
447 }
448 Ok(u32::from(d[p])
449 | (u32::from(d[p + 1]) << 8)
450 | (u32::from(d[p + 2]) << 16)
451 | (u32::from(d[p + 3]) << 24))
452 };
453
454 let vendor_len = read_le_u32(data, pos)? as usize;
456 pos += 4;
457 if pos + vendor_len > data.len() {
458 return Err(CodecError::InvalidData(
459 "VORBIS_COMMENT: vendor string truncated".to_string(),
460 ));
461 }
462 let vendor = String::from_utf8_lossy(&data[pos..pos + vendor_len]).into_owned();
463 pos += vendor_len;
464
465 let comment_count = read_le_u32(data, pos)? as usize;
467 pos += 4;
468
469 let mut comments = Vec::with_capacity(comment_count);
470 for _ in 0..comment_count {
471 let entry_len = read_le_u32(data, pos)? as usize;
472 pos += 4;
473 if pos + entry_len > data.len() {
474 return Err(CodecError::InvalidData(
475 "VORBIS_COMMENT: comment entry truncated".to_string(),
476 ));
477 }
478 let entry = String::from_utf8_lossy(&data[pos..pos + entry_len]).into_owned();
479 pos += entry_len;
480
481 if let Some(eq_pos) = entry.find('=') {
483 let key = entry[..eq_pos].to_string();
484 let value = entry[eq_pos + 1..].to_string();
485 comments.push((key, value));
486 } else {
487 comments.push((entry, String::new()));
489 }
490 }
491
492 Ok(FlacVorbisComment { vendor, comments })
493 }
494
495 pub fn parse_stream_header(&mut self, data: &[u8]) -> CodecResult<usize> {
503 if data.len() < 8 {
504 return Err(CodecError::InvalidData(
505 "Stream too short for FLAC header".to_string(),
506 ));
507 }
508 if &data[..4] != b"fLaC" {
509 return Err(CodecError::InvalidData("Missing fLaC magic".to_string()));
510 }
511
512 let block_type = data[4] & 0x7F;
514 let length = (u32::from(data[5]) << 16) | (u32::from(data[6]) << 8) | u32::from(data[7]);
515
516 if block_type != 0 {
517 return Err(CodecError::InvalidData(format!(
518 "Expected STREAMINFO block (type 0), got type {block_type}"
519 )));
520 }
521
522 let offset = 8usize;
523 let end = offset + length as usize;
524 if data.len() < end {
525 return Err(CodecError::InvalidData(
526 "Truncated STREAMINFO block".to_string(),
527 ));
528 }
529
530 let si_data = &data[offset..end];
531 self.stream_info = Some(Self::parse_streaminfo_block(si_data)?);
532 self.header_parsed = true;
533
534 Ok(end)
535 }
536
537 pub fn decode_frame(&self, data: &[u8]) -> CodecResult<(DecodedBlock, usize)> {
545 if data.len() < 10 {
546 return Err(CodecError::InvalidData("Frame data too short".to_string()));
547 }
548
549 let mut r = BitReader::new(data);
550
551 let sync_hi = r
553 .read_byte()
554 .ok_or_else(|| CodecError::InvalidData("EOF reading sync".to_string()))?;
555 let sync_lo = r
556 .read_byte()
557 .ok_or_else(|| CodecError::InvalidData("EOF reading sync".to_string()))?;
558 if sync_hi != 0xFF || (sync_lo & 0xFC) != 0xF8 {
559 return Err(CodecError::InvalidData(format!(
560 "Invalid FLAC sync: {sync_hi:#04x} {sync_lo:#04x}"
561 )));
562 }
563
564 let byte2 = r
566 .read_byte()
567 .ok_or_else(|| CodecError::InvalidData("EOF byte2".to_string()))?;
568 let bs_code = (byte2 >> 4) & 0x0F;
569 let _sr_code = byte2 & 0x0F;
570
571 let byte3 = r
573 .read_byte()
574 .ok_or_else(|| CodecError::InvalidData("EOF byte3".to_string()))?;
575 let ch_minus1 = ((byte3 >> 4) & 0x0F) as usize;
576 let _bps_code = byte3 & 0x0F;
577 let channels = ch_minus1 + 1;
578
579 let sample_number = r
581 .read_utf8_coded()
582 .ok_or_else(|| CodecError::InvalidData("EOF sample number".to_string()))?;
583
584 let block_size = if bs_code == 7 {
586 let hi = r
587 .read_byte()
588 .ok_or_else(|| CodecError::InvalidData("EOF block size hi".to_string()))?;
589 let lo = r
590 .read_byte()
591 .ok_or_else(|| CodecError::InvalidData("EOF block size lo".to_string()))?;
592 ((u32::from(hi) << 8) | u32::from(lo)) as usize
593 } else {
594 self.stream_info
596 .as_ref()
597 .map(|si| si.max_block_size as usize)
598 .unwrap_or(4096)
599 };
600
601 let _crc8 = r
603 .read_byte()
604 .ok_or_else(|| CodecError::InvalidData("EOF CRC-8".to_string()))?;
605
606 let mut decoded_channels: Vec<Vec<i32>> = Vec::with_capacity(channels);
608 for _ in 0..channels {
609 let ch_samples = self.decode_subframe(&mut r, block_size)?;
610 decoded_channels.push(ch_samples);
611 }
612
613 r.align_to_byte();
615
616 let frame_len_before_crc = r.byte_offset();
618 let crc_hi = r
619 .read_byte()
620 .ok_or_else(|| CodecError::InvalidData("EOF CRC-16 hi".to_string()))?;
621 let crc_lo = r
622 .read_byte()
623 .ok_or_else(|| CodecError::InvalidData("EOF CRC-16 lo".to_string()))?;
624 let stored_crc = (u16::from(crc_hi) << 8) | u16::from(crc_lo);
625 let computed_crc = crc16(&data[..frame_len_before_crc]);
626
627 if stored_crc != computed_crc {
628 let _ = stored_crc;
632 }
633
634 let bytes_consumed = frame_len_before_crc + 2;
635
636 let mut samples = Vec::with_capacity(block_size * channels);
638 for s in 0..block_size {
639 for ch in 0..channels {
640 let v = decoded_channels[ch].get(s).copied().unwrap_or(0);
641 samples.push(v);
642 }
643 }
644
645 Ok((
646 DecodedBlock {
647 samples,
648 sample_number,
649 block_size,
650 channels,
651 },
652 bytes_consumed,
653 ))
654 }
655
656 fn decode_subframe(&self, r: &mut BitReader<'_>, block_size: usize) -> CodecResult<Vec<i32>> {
658 let subframe_type = r
659 .read_byte()
660 .ok_or_else(|| CodecError::InvalidData("EOF reading subframe type".to_string()))?;
661
662 if subframe_type == 0x02 {
663 return self.decode_verbatim_subframe(r, block_size);
665 }
666
667 if subframe_type & 0xC0 == 0x40 {
668 let order = ((subframe_type & 0x3F) as usize) + 1;
670 return self.decode_lpc_subframe(r, block_size, order);
671 }
672
673 self.decode_verbatim_subframe(r, block_size)
675 }
676
677 fn decode_verbatim_subframe(
679 &self,
680 r: &mut BitReader<'_>,
681 block_size: usize,
682 ) -> CodecResult<Vec<i32>> {
683 let mut samples = Vec::with_capacity(block_size);
684 for _ in 0..block_size {
685 let s = r.read_be_i16().ok_or_else(|| {
686 CodecError::InvalidData("EOF reading verbatim sample".to_string())
687 })?;
688 samples.push(i32::from(s));
689 }
690 Ok(samples)
691 }
692
693 fn decode_lpc_subframe(
695 &self,
696 r: &mut BitReader<'_>,
697 block_size: usize,
698 order: usize,
699 ) -> CodecResult<Vec<i32>> {
700 if block_size < order {
701 return Err(CodecError::InvalidData(format!(
702 "Block size {block_size} < LPC order {order}"
703 )));
704 }
705
706 let mut warmup = Vec::with_capacity(order);
708 for _ in 0..order {
709 let s = r
710 .read_be_i16()
711 .ok_or_else(|| CodecError::InvalidData("EOF reading LPC warmup".to_string()))?;
712 warmup.push(i32::from(s));
713 }
714
715 let precision_byte = r
717 .read_byte()
718 .ok_or_else(|| CodecError::InvalidData("EOF reading LPC precision".to_string()))?;
719 let shift_byte = r
720 .read_byte()
721 .ok_or_else(|| CodecError::InvalidData("EOF reading LPC shift".to_string()))?;
722 let _precision = precision_byte + 1; let shift = shift_byte;
724
725 let mut int_coeffs = Vec::with_capacity(order);
727 for _ in 0..order {
728 let c = r.read_be_i16().ok_or_else(|| {
729 CodecError::InvalidData("EOF reading LPC coefficient".to_string())
730 })?;
731 int_coeffs.push(i32::from(c));
732 }
733
734 let scale = (1i64 << shift) as f64;
736 let float_coeffs: Vec<f64> = int_coeffs.iter().map(|&c| f64::from(c) / scale).collect();
737
738 let _partition_order = r.read_byte().ok_or_else(|| {
740 CodecError::InvalidData("EOF reading Rice partition order".to_string())
741 })?;
742 let rice_param = r
743 .read_byte()
744 .ok_or_else(|| CodecError::InvalidData("EOF reading Rice parameter".to_string()))?;
745
746 let residual_count = block_size - order;
748 r.align_to_byte();
749
750 let rice_data = r.slice_from_current().to_vec();
751 let mut rice_dec = RiceDecoder::new(&rice_data);
752 let residuals = rice_dec.decode_n(residual_count, rice_param);
753
754 if residuals.len() < residual_count {
755 return Err(CodecError::InvalidData(format!(
756 "Expected {residual_count} residuals, got {}",
757 residuals.len()
758 )));
759 }
760
761 let restored = restore_signal(&warmup, &residuals, &float_coeffs);
771 Ok(restored)
772 }
773
774 pub fn decode_stream(&mut self, data: &[u8]) -> CodecResult<Vec<i32>> {
782 let header_end = self.parse_stream_header(data)?;
784 let mut pos = header_end;
785 let mut all_samples: Vec<i32> = Vec::new();
786
787 while pos + 4 < data.len() {
789 if data[pos] != 0xFF || (data[pos + 1] & 0xFC) != 0xF8 {
791 pos += 1;
792 continue;
793 }
794
795 match self.decode_frame(&data[pos..]) {
796 Ok((block, consumed)) => {
797 all_samples.extend_from_slice(&block.samples);
798 pos += consumed.max(1);
799 }
800 Err(_) => {
801 pos += 1;
803 }
804 }
805 }
806
807 Ok(all_samples)
808 }
809}
810
811#[cfg(test)]
816mod tests {
817 use super::*;
818 use crate::flac::{FlacConfig, FlacEncoder};
819
820 fn make_encoder(channels: u8) -> FlacEncoder {
821 FlacEncoder::new(FlacConfig {
822 sample_rate: 44100,
823 channels,
824 bits_per_sample: 16,
825 })
826 }
827
828 #[test]
829 fn test_flac_decoder_new() {
830 let dec = FlacDecoder::new();
831 assert!(dec.stream_info.is_none());
832 assert!(!dec.header_parsed);
833 }
834
835 #[test]
836 fn test_parse_stream_header_magic() {
837 let enc = make_encoder(2);
838 let header = enc.stream_header();
839 let mut dec = FlacDecoder::new();
840 let consumed = dec.parse_stream_header(&header).expect("parse header");
841 assert_eq!(consumed, 42, "Should consume exactly 42 bytes");
842 assert!(dec.stream_info.is_some());
843 }
844
845 #[test]
846 fn test_parse_stream_header_fields() {
847 let enc = make_encoder(2);
848 let header = enc.stream_header();
849 let mut dec = FlacDecoder::new();
850 dec.parse_stream_header(&header).expect("parse header");
851 let si = dec.stream_info.as_ref().expect("stream_info");
852 assert_eq!(si.sample_rate, 44100);
853 assert_eq!(si.channels, 2);
854 assert_eq!(si.bits_per_sample, 16);
855 }
856
857 #[test]
858 fn test_parse_stream_header_bad_magic() {
859 let bad = b"NOPE\x80\x00\x00\x22";
860 let mut dec = FlacDecoder::new();
861 let res = dec.parse_stream_header(bad);
862 assert!(res.is_err());
863 }
864
865 #[test]
866 fn test_decode_frame_verbatim_roundtrip() {
867 let mut enc = make_encoder(1);
868 let input: Vec<i32> = vec![100i32; 32];
870 let (header, frames) = enc.encode(&input).expect("encode");
871 assert!(!frames.is_empty());
872
873 let dec = FlacDecoder::new();
874 let (block, _) = dec.decode_frame(&frames[0].data).expect("decode frame");
875 assert_eq!(block.channels, 1);
876 assert!(!block.samples.is_empty());
877 }
878
879 #[test]
880 fn test_decode_stream_silence_roundtrip() {
881 let mut enc = make_encoder(2);
882 let silence = vec![0i32; 128 * 2]; let (header, frames) = enc.encode(&silence).expect("encode");
884
885 let mut stream = header.clone();
887 for f in &frames {
888 stream.extend_from_slice(&f.data);
889 }
890
891 let mut dec = FlacDecoder::new();
892 let decoded = dec.decode_stream(&stream).expect("decode_stream");
893 assert!(!decoded.is_empty(), "Should produce samples");
895 for &s in &decoded {
896 assert_eq!(s, 0, "All silence samples should decode as 0");
897 }
898 }
899
900 #[test]
901 fn test_decode_stream_ramp_roundtrip() {
902 let mut enc = make_encoder(1);
903 let ramp: Vec<i32> = (0..64).map(|i| i * 10).collect();
905 let (header, frames) = enc.encode(&ramp).expect("encode");
906
907 let mut stream = header.clone();
908 for f in &frames {
909 stream.extend_from_slice(&f.data);
910 }
911
912 let mut dec = FlacDecoder::new();
913 let decoded = dec.decode_stream(&stream).expect("decode_stream");
914 assert!(!decoded.is_empty(), "Should produce samples");
915 }
916
917 #[test]
918 fn test_decode_frame_block_size_preserved() {
919 let mut enc = make_encoder(2);
920 let samples = vec![500i32; 256 * 2]; let (_, frames) = enc.encode(&samples).expect("encode");
922 assert!(!frames.is_empty());
923
924 let dec = FlacDecoder::new();
925 let (block, _) = dec.decode_frame(&frames[0].data).expect("decode frame");
926 assert_eq!(block.block_size, 256);
927 assert_eq!(block.channels, 2);
928 }
929
930 #[test]
931 fn test_decode_frame_sample_number() {
932 let mut enc = make_encoder(2);
933 let samples = vec![0i32; 4096 * 2 * 2]; let (_, frames) = enc.encode(&samples).expect("encode");
935 if frames.len() >= 2 {
936 let dec = FlacDecoder::new();
937 let (block0, _) = dec.decode_frame(&frames[0].data).expect("frame 0");
938 let (block1, _) = dec.decode_frame(&frames[1].data).expect("frame 1");
939 assert_eq!(block0.sample_number, 0);
940 assert!(block1.sample_number > block0.sample_number);
941 }
942 }
943
944 #[test]
945 fn test_decode_stream_header_bad_input() {
946 let mut dec = FlacDecoder::new();
947 let res = dec.decode_stream(b"short");
948 assert!(res.is_err() || res.is_ok()); }
951
952 #[test]
953 fn test_crc16_matches_encoder() {
954 let data = b"FLAC test data for CRC verification";
956 let enc_crc = {
957 const POLY: u16 = 0x8005;
959 let mut crc = 0u16;
960 for &byte in data.iter() {
961 crc ^= u16::from(byte) << 8;
962 for _ in 0..8 {
963 if crc & 0x8000 != 0 {
964 crc = (crc << 1) ^ POLY;
965 } else {
966 crc <<= 1;
967 }
968 }
969 }
970 crc
971 };
972 let dec_crc = crc16(data);
973 assert_eq!(enc_crc, dec_crc);
974 }
975
976 #[test]
977 fn test_decode_mono_stream() {
978 let mut enc = FlacEncoder::new(FlacConfig {
979 sample_rate: 48000,
980 channels: 1,
981 bits_per_sample: 16,
982 });
983 let samples = vec![0i32; 512];
984 let (header, frames) = enc.encode(&samples).expect("encode mono");
985
986 let mut stream = header;
987 for f in frames {
988 stream.extend_from_slice(&f.data);
989 }
990
991 let mut dec = FlacDecoder::new();
992 let decoded = dec.decode_stream(&stream).expect("decode mono");
993 assert!(!decoded.is_empty());
994 }
995
996 #[test]
1001 fn test_parse_metadata_valid_stream() {
1002 let enc = make_encoder(2);
1003 let header = enc.stream_header();
1004 let stream = header.clone();
1006 let mut dec = FlacDecoder::new();
1008 dec.parse_metadata(&stream)
1009 .expect("parse_metadata should succeed");
1010 assert!(dec.stream_info.is_some(), "stream_info should be populated");
1011 }
1012
1013 #[test]
1014 fn test_parse_metadata_rejects_bad_magic() {
1015 let bad = b"WAVE\x80\x00\x00\x22XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
1016 let mut dec = FlacDecoder::new();
1017 let res = dec.parse_metadata(bad);
1018 assert!(res.is_err(), "Should reject non-fLaC magic");
1019 }
1020
1021 #[test]
1022 fn test_parse_metadata_stream_info_fields() {
1023 let enc = FlacEncoder::new(FlacConfig {
1024 sample_rate: 48000,
1025 channels: 1,
1026 bits_per_sample: 16,
1027 });
1028 let header = enc.stream_header();
1029 let mut dec = FlacDecoder::new();
1030 dec.parse_metadata(&header).expect("parse_metadata");
1031 let si = dec.stream_info().expect("stream_info should be Some");
1032 assert_eq!(si.sample_rate, 48000);
1033 assert_eq!(si.channels, 1);
1034 assert_eq!(si.bits_per_sample, 16);
1035 }
1036
1037 #[test]
1038 fn test_stream_info_method_returns_none_before_parse() {
1039 let dec = FlacDecoder::new();
1040 assert!(dec.stream_info().is_none());
1041 }
1042
1043 #[test]
1044 fn test_stream_info_method_returns_some_after_parse() {
1045 let enc = make_encoder(2);
1046 let header = enc.stream_header();
1047 let mut dec = FlacDecoder::new();
1048 dec.parse_metadata(&header).expect("parse_metadata");
1049 assert!(dec.stream_info().is_some());
1050 }
1051
1052 #[test]
1053 fn test_comment_block_returns_none_when_absent() {
1054 let enc = make_encoder(1);
1055 let header = enc.stream_header();
1056 let mut dec = FlacDecoder::new();
1057 dec.parse_metadata(&header).expect("parse_metadata");
1058 assert!(
1060 dec.comment_block().is_none(),
1061 "No VORBIS_COMMENT block expected from FlacEncoder stream"
1062 );
1063 }
1064
1065 #[test]
1066 fn test_parse_vorbis_comment_block_direct() {
1067 let vendor = b"OxiMedia";
1071 let comment = b"TITLE=Test Track";
1072 let mut block: Vec<u8> = Vec::new();
1073 block.extend_from_slice(&(vendor.len() as u32).to_le_bytes());
1075 block.extend_from_slice(vendor);
1076 block.extend_from_slice(&1u32.to_le_bytes());
1078 block.extend_from_slice(&(comment.len() as u32).to_le_bytes());
1080 block.extend_from_slice(comment);
1081
1082 let vc = FlacDecoder::parse_vorbis_comment_block(&block)
1083 .expect("parse_vorbis_comment_block should succeed");
1084 assert_eq!(vc.vendor, "OxiMedia");
1085 assert_eq!(vc.comments.len(), 1);
1086 assert_eq!(vc.comments[0].0, "TITLE");
1087 assert_eq!(vc.comments[0].1, "Test Track");
1088 }
1089
1090 #[test]
1091 fn test_parse_vorbis_comment_multiple_entries() {
1092 let vendor = b"TestEncoder";
1093 let c1 = b"ARTIST=Some Artist";
1094 let c2 = b"ALBUM=Great Album";
1095 let c3 = b"TRACKNUMBER=3";
1096
1097 let mut block: Vec<u8> = Vec::new();
1098 block.extend_from_slice(&(vendor.len() as u32).to_le_bytes());
1099 block.extend_from_slice(vendor);
1100 block.extend_from_slice(&3u32.to_le_bytes());
1101 for comment in [c1.as_slice(), c2.as_slice(), c3.as_slice()] {
1102 block.extend_from_slice(&(comment.len() as u32).to_le_bytes());
1103 block.extend_from_slice(comment);
1104 }
1105
1106 let vc =
1107 FlacDecoder::parse_vorbis_comment_block(&block).expect("parse_vorbis_comment_block");
1108 assert_eq!(vc.vendor, "TestEncoder");
1109 assert_eq!(vc.comments.len(), 3);
1110 assert_eq!(
1111 vc.comments[0],
1112 ("ARTIST".to_string(), "Some Artist".to_string())
1113 );
1114 assert_eq!(
1115 vc.comments[1],
1116 ("ALBUM".to_string(), "Great Album".to_string())
1117 );
1118 assert_eq!(vc.comments[2], ("TRACKNUMBER".to_string(), "3".to_string()));
1119 }
1120
1121 #[test]
1122 fn test_parse_metadata_with_vorbis_comment_block() {
1123 let enc = make_encoder(2);
1125 let streaminfo_header = enc.stream_header(); let mut stream = streaminfo_header.clone();
1130 stream[4] &= 0x7F;
1132
1133 let vendor = b"OxiMediaTest";
1135 let comment = b"COMMENT=hello";
1136 let mut vc_body: Vec<u8> = Vec::new();
1137 vc_body.extend_from_slice(&(vendor.len() as u32).to_le_bytes());
1138 vc_body.extend_from_slice(vendor);
1139 vc_body.extend_from_slice(&1u32.to_le_bytes());
1140 vc_body.extend_from_slice(&(comment.len() as u32).to_le_bytes());
1141 vc_body.extend_from_slice(comment);
1142
1143 let vc_len = vc_body.len() as u32;
1145 stream.push(0x84); stream.push(((vc_len >> 16) & 0xFF) as u8);
1147 stream.push(((vc_len >> 8) & 0xFF) as u8);
1148 stream.push((vc_len & 0xFF) as u8);
1149 stream.extend_from_slice(&vc_body);
1150
1151 let mut dec = FlacDecoder::new();
1152 dec.parse_metadata(&stream)
1153 .expect("parse_metadata with VORBIS_COMMENT");
1154 assert!(dec.stream_info().is_some());
1155 let vc = dec
1156 .comment_block()
1157 .expect("VORBIS_COMMENT should be parsed");
1158 assert_eq!(vc.vendor, "OxiMediaTest");
1159 assert_eq!(vc.comments.len(), 1);
1160 assert_eq!(vc.comments[0].0, "COMMENT");
1161 assert_eq!(vc.comments[0].1, "hello");
1162 }
1163
1164 #[test]
1165 fn test_probe_valid_stream() {
1166 let enc = make_encoder(2);
1167 let header = enc.stream_header();
1168 let si = FlacDecoder::probe(&header).expect("probe should succeed");
1169 assert_eq!(si.sample_rate, 44100);
1170 assert_eq!(si.channels, 2);
1171 assert_eq!(si.bits_per_sample, 16);
1172 }
1173
1174 #[test]
1175 fn test_probe_rejects_bad_magic() {
1176 let bad = b"RIFF\x80\x00\x00\x22XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
1177 let res = FlacDecoder::probe(bad);
1178 assert!(res.is_err(), "probe should reject non-fLaC magic");
1179 }
1180
1181 #[test]
1182 fn test_probe_rejects_too_short() {
1183 let short = b"fLaC";
1184 let res = FlacDecoder::probe(short);
1185 assert!(res.is_err(), "probe should reject too-short data");
1186 }
1187
1188 #[test]
1189 fn test_streaminfo_min_max_block_size() {
1190 let enc = make_encoder(2);
1191 let header = enc.stream_header();
1192 let si = FlacDecoder::probe(&header).expect("probe");
1193 assert!(si.min_block_size <= si.max_block_size);
1195 assert!(si.max_block_size >= 16);
1197 }
1198
1199 #[test]
1200 fn test_streaminfo_new_fields_accessible() {
1201 let enc = make_encoder(1);
1202 let header = enc.stream_header();
1203 let si = FlacDecoder::probe(&header).expect("probe");
1204 let _ = si.min_frame_size;
1206 let _ = si.max_frame_size;
1207 let _ = si.total_samples;
1208 let _ = si.md5_signature;
1209 }
1210}