1use std::io::{Read, Seek, SeekFrom};
2
3use crate::bitreader::BitReader;
4use crate::crc::ape_crc;
5use crate::entropy::EntropyState;
6use crate::error::{ApeError, ApeResult};
7use crate::format::{
8 self, ApeFileInfo, APE_FORMAT_FLAG_AIFF, APE_FORMAT_FLAG_BIG_ENDIAN, APE_FORMAT_FLAG_CAF,
9 APE_FORMAT_FLAG_FLOATING_POINT, APE_FORMAT_FLAG_SIGNED_8_BIT, APE_FORMAT_FLAG_SND,
10 APE_FORMAT_FLAG_W64,
11};
12use crate::id3v2::{self, Id3v2Tag};
13use crate::predictor::{Predictor3950, Predictor3950_32};
14use crate::range_coder::RangeCoder;
15use crate::tag::{self, ApeTag};
16use crate::unprepare;
17
18const SPECIAL_FRAME_MONO_SILENCE: i32 = 1;
20const SPECIAL_FRAME_LEFT_SILENCE: i32 = 1;
21const SPECIAL_FRAME_RIGHT_SILENCE: i32 = 2;
22const SPECIAL_FRAME_PSEUDO_STEREO: i32 = 4;
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum SourceFormat {
27 Wav,
28 Aiff,
29 W64,
30 Snd,
31 Caf,
32 Unknown,
33}
34
35#[derive(Debug, Clone, Copy)]
37pub struct SeekResult {
38 pub frame_index: u32,
40 pub skip_samples: u32,
42 pub actual_sample: u64,
44}
45
46#[derive(Debug, Clone)]
48pub struct ApeInfo {
49 pub version: u16,
51 pub compression_level: u16,
52 pub sample_rate: u32,
53 pub channels: u16,
54 pub bits_per_sample: u16,
55 pub total_samples: u64,
56 pub total_frames: u32,
57 pub blocks_per_frame: u32,
58 pub final_frame_blocks: u32,
59 pub duration_ms: u64,
60 pub block_align: u16,
61
62 pub format_flags: u16,
64 pub bytes_per_sample: u16,
65 pub average_bitrate_kbps: u32,
66 pub decompressed_bitrate_kbps: u32,
67 pub file_size_bytes: u64,
68
69 pub is_big_endian: bool,
71 pub is_floating_point: bool,
72 pub is_signed_8bit: bool,
73
74 pub source_format: SourceFormat,
76}
77
78impl ApeInfo {
79 fn from_file_info(info: &ApeFileInfo) -> Self {
80 let flags = info.header.format_flags;
81 let source_format = if flags & APE_FORMAT_FLAG_AIFF != 0 {
82 SourceFormat::Aiff
83 } else if flags & APE_FORMAT_FLAG_W64 != 0 {
84 SourceFormat::W64
85 } else if flags & APE_FORMAT_FLAG_SND != 0 {
86 SourceFormat::Snd
87 } else if flags & APE_FORMAT_FLAG_CAF != 0 {
88 SourceFormat::Caf
89 } else {
90 SourceFormat::Wav
91 };
92
93 ApeInfo {
94 version: info.descriptor.version,
95 compression_level: info.header.compression_level,
96 sample_rate: info.header.sample_rate,
97 channels: info.header.channels,
98 bits_per_sample: info.header.bits_per_sample,
99 total_samples: info.total_blocks as u64,
100 total_frames: info.header.total_frames,
101 blocks_per_frame: info.header.blocks_per_frame,
102 final_frame_blocks: info.header.final_frame_blocks,
103 duration_ms: info.length_ms as u64,
104 block_align: info.block_align,
105
106 format_flags: flags,
107 bytes_per_sample: info.bytes_per_sample,
108 average_bitrate_kbps: if info.length_ms > 0 {
109 (info.file_bytes * 8 / info.length_ms as u64) as u32
110 } else {
111 0
112 },
113 decompressed_bitrate_kbps: info.decompressed_bitrate as u32,
114 file_size_bytes: info.file_bytes,
115
116 is_big_endian: flags & APE_FORMAT_FLAG_BIG_ENDIAN != 0,
117 is_floating_point: flags & APE_FORMAT_FLAG_FLOATING_POINT != 0,
118 is_signed_8bit: flags & APE_FORMAT_FLAG_SIGNED_8_BIT != 0,
119
120 source_format,
121 }
122 }
123
124 pub fn frame_samples(&self, frame_idx: u32) -> u32 {
126 if frame_idx == self.total_frames - 1 {
127 self.final_frame_blocks
128 } else {
129 self.blocks_per_frame
130 }
131 }
132
133 pub fn generate_wav_header(&self) -> Vec<u8> {
146 let data_size = self.total_samples as u32 * self.block_align as u32;
147 let file_size = 36 + data_size;
148
149 let mut header = Vec::with_capacity(44);
150 header.extend_from_slice(b"RIFF");
151 header.extend_from_slice(&file_size.to_le_bytes());
152 header.extend_from_slice(b"WAVE");
153
154 header.extend_from_slice(b"fmt ");
156 header.extend_from_slice(&16u32.to_le_bytes()); header.extend_from_slice(&1u16.to_le_bytes()); header.extend_from_slice(&self.channels.to_le_bytes());
159 header.extend_from_slice(&self.sample_rate.to_le_bytes());
160 let byte_rate = self.sample_rate * self.block_align as u32;
161 header.extend_from_slice(&byte_rate.to_le_bytes());
162 header.extend_from_slice(&self.block_align.to_le_bytes());
163 header.extend_from_slice(&self.bits_per_sample.to_le_bytes());
164
165 header.extend_from_slice(b"data");
167 header.extend_from_slice(&data_size.to_le_bytes());
168
169 header
170 }
171}
172
173enum Predictors {
178 Path16(Vec<Predictor3950>),
179 Path32(Vec<Predictor3950_32>),
180}
181
182pub struct ApeDecoder<R: Read + Seek> {
184 reader: R,
185 file_info: ApeFileInfo,
186 info: ApeInfo,
187 predictors: Predictors,
188 entropy_states: Vec<EntropyState>,
189 range_coder: RangeCoder,
190 interim_mode: bool,
191}
192
193impl<R: Read + Seek> ApeDecoder<R> {
194 pub fn new(mut reader: R) -> ApeResult<Self> {
196 let file_info = format::parse(&mut reader)?;
197 let version = file_info.descriptor.version as i32;
198 let channels = file_info.header.channels;
199 let bits = file_info.header.bits_per_sample;
200 let compression = file_info.header.compression_level as u32;
201
202 if version < 3950 {
203 return Err(ApeError::UnsupportedVersion(file_info.descriptor.version));
204 }
205
206 let predictors = if bits >= 32 {
207 Predictors::Path32(
208 (0..channels)
209 .map(|_| Predictor3950_32::new(compression, version))
210 .collect(),
211 )
212 } else {
213 Predictors::Path16(
214 (0..channels)
215 .map(|_| Predictor3950::new(compression, version, bits))
216 .collect(),
217 )
218 };
219
220 let entropy_states = (0..channels).map(|_| EntropyState::new()).collect();
221 let info = ApeInfo::from_file_info(&file_info);
222
223 Ok(ApeDecoder {
224 reader,
225 file_info,
226 info,
227 predictors,
228 entropy_states,
229 range_coder: RangeCoder::new(),
230 interim_mode: false,
231 })
232 }
233
234 pub fn info(&self) -> &ApeInfo {
236 &self.info
237 }
238
239 pub fn total_frames(&self) -> u32 {
241 self.info.total_frames
242 }
243
244 pub fn decode_frame(&mut self, frame_idx: u32) -> ApeResult<Vec<u8>> {
246 if frame_idx >= self.info.total_frames {
247 return Err(ApeError::DecodingError("frame index out of bounds"));
248 }
249
250 let frame_data = self.read_frame_data(frame_idx)?;
251 let seek_remainder = self.seek_remainder(frame_idx);
252 let frame_blocks = self.file_info.frame_block_count(frame_idx) as usize;
253 let version = self.info.version as i32;
254 let channels = self.info.channels;
255 let bits = self.info.bits_per_sample;
256 let block_align = self.info.block_align as usize;
257
258 match &mut self.predictors {
259 Predictors::Path16(predictors) => {
260 let result = try_decode_frame_16(
261 &frame_data,
262 seek_remainder,
263 frame_blocks,
264 version,
265 channels,
266 bits,
267 block_align,
268 predictors,
269 &mut self.entropy_states,
270 &mut self.range_coder,
271 );
272
273 match result {
274 Ok(pcm) => Ok(pcm),
275 Err(ApeError::InvalidChecksum) if bits == 24 && !self.interim_mode => {
276 self.interim_mode = true;
277 for p in predictors.iter_mut() {
278 p.set_interim_mode(true);
279 }
280 try_decode_frame_16(
281 &frame_data,
282 seek_remainder,
283 frame_blocks,
284 version,
285 channels,
286 bits,
287 block_align,
288 predictors,
289 &mut self.entropy_states,
290 &mut self.range_coder,
291 )
292 }
293 Err(e) => Err(e),
294 }
295 }
296 Predictors::Path32(predictors) => try_decode_frame_32(
297 &frame_data,
298 seek_remainder,
299 frame_blocks,
300 version,
301 channels,
302 bits,
303 block_align,
304 predictors,
305 &mut self.entropy_states,
306 &mut self.range_coder,
307 ),
308 }
309 }
310
311 pub fn decode_all(&mut self) -> ApeResult<Vec<u8>> {
313 let total_pcm_bytes = self.info.total_samples as usize * self.info.block_align as usize;
314 let mut pcm_output = Vec::with_capacity(total_pcm_bytes);
315
316 for frame_idx in 0..self.info.total_frames {
317 let frame_pcm = self.decode_frame(frame_idx)?;
318 pcm_output.extend_from_slice(&frame_pcm);
319 }
320
321 Ok(pcm_output)
322 }
323
324 pub fn decode_all_with<F: FnMut(f64) -> bool>(
329 &mut self,
330 mut on_progress: F,
331 ) -> ApeResult<Vec<u8>> {
332 let total = self.info.total_frames as f64;
333 let total_pcm_bytes = self.info.total_samples as usize * self.info.block_align as usize;
334 let mut pcm_output = Vec::with_capacity(total_pcm_bytes);
335
336 for frame_idx in 0..self.info.total_frames {
337 let frame_pcm = self.decode_frame(frame_idx)?;
338 pcm_output.extend_from_slice(&frame_pcm);
339
340 if !on_progress((frame_idx + 1) as f64 / total) {
341 return Err(ApeError::DecodingError("cancelled"));
342 }
343 }
344
345 Ok(pcm_output)
346 }
347
348 pub fn decode_all_parallel(&mut self, thread_count: usize) -> ApeResult<Vec<u8>> {
356 if thread_count <= 1 {
357 return self.decode_all();
358 }
359
360 let total_frames = self.info.total_frames;
361 let version = self.info.version as i32;
362 let channels = self.info.channels;
363 let bits = self.info.bits_per_sample;
364 let compression = self.info.compression_level as u32;
365 let block_align = self.info.block_align as usize;
366
367 let mut frame_data_list: Vec<(Vec<u8>, u32, usize)> =
369 Vec::with_capacity(total_frames as usize);
370 for frame_idx in 0..total_frames {
371 let data = self.read_frame_data(frame_idx)?;
372 let seek_remainder = self.seek_remainder(frame_idx);
373 let frame_blocks = self.file_info.frame_block_count(frame_idx) as usize;
374 frame_data_list.push((data, seek_remainder, frame_blocks));
375 }
376
377 let chunk_size = (total_frames as usize + thread_count - 1) / thread_count;
379 let chunks: Vec<Vec<(usize, Vec<u8>, u32, usize)>> = frame_data_list
380 .into_iter()
381 .enumerate()
382 .collect::<Vec<_>>()
383 .chunks(chunk_size)
384 .map(|chunk| {
385 chunk
386 .iter()
387 .map(|(i, (data, sr, fb))| (*i, data.clone(), *sr, *fb))
388 .collect()
389 })
390 .collect();
391
392 let mut handles = Vec::new();
393 for chunk in chunks {
394 let v = version;
395 let ch = channels;
396 let b = bits;
397 let comp = compression;
398 let ba = block_align;
399
400 handles.push(std::thread::spawn(
401 move || -> ApeResult<Vec<(usize, Vec<u8>)>> {
402 let mut results = Vec::with_capacity(chunk.len());
403
404 let mut predictors: Vec<Predictor3950> =
406 (0..ch).map(|_| Predictor3950::new(comp, v, b)).collect();
407 let mut entropy_states: Vec<EntropyState> =
408 (0..ch).map(|_| EntropyState::new()).collect();
409 let mut range_coder = RangeCoder::new();
410
411 for (frame_idx, frame_data, seek_remainder, frame_blocks) in chunk {
412 let pcm = if b >= 32 {
413 let mut preds32: Vec<Predictor3950_32> =
414 (0..ch).map(|_| Predictor3950_32::new(comp, v)).collect();
415 try_decode_frame_32(
416 &frame_data,
417 seek_remainder,
418 frame_blocks,
419 v,
420 ch,
421 b,
422 ba,
423 &mut preds32,
424 &mut entropy_states,
425 &mut range_coder,
426 )?
427 } else {
428 try_decode_frame_16(
429 &frame_data,
430 seek_remainder,
431 frame_blocks,
432 v,
433 ch,
434 b,
435 ba,
436 &mut predictors,
437 &mut entropy_states,
438 &mut range_coder,
439 )?
440 };
441 results.push((frame_idx, pcm));
442 }
443 Ok(results)
444 },
445 ));
446 }
447
448 let mut all_results: Vec<(usize, Vec<u8>)> = Vec::with_capacity(total_frames as usize);
450 for handle in handles {
451 let chunk_results = handle
452 .join()
453 .map_err(|_| ApeError::DecodingError("thread panicked"))??;
454 all_results.extend(chunk_results);
455 }
456 all_results.sort_by_key(|(idx, _)| *idx);
457
458 let total_pcm = self.info.total_samples as usize * block_align;
459 let mut pcm_output = Vec::with_capacity(total_pcm);
460 for (_, pcm) in all_results {
461 pcm_output.extend_from_slice(&pcm);
462 }
463
464 Ok(pcm_output)
465 }
466
467 pub fn decode_range(&mut self, start_sample: u64, end_sample: u64) -> ApeResult<Vec<u8>> {
473 let start = start_sample.min(self.info.total_samples);
474 let end = end_sample.min(self.info.total_samples);
475 if start >= end {
476 return Ok(Vec::new());
477 }
478
479 let bpf = self.info.blocks_per_frame as u64;
480 let block_align = self.info.block_align as usize;
481 let first_frame = (start / bpf) as u32;
482 let last_frame = ((end - 1) / bpf).min(self.info.total_frames as u64 - 1) as u32;
483
484 let range_samples = (end - start) as usize;
485 let mut pcm_output = Vec::with_capacity(range_samples * block_align);
486
487 for frame_idx in first_frame..=last_frame {
488 let frame_pcm = self.decode_frame(frame_idx)?;
489 let frame_start_sample = frame_idx as u64 * bpf;
490 let frame_end_sample = frame_start_sample + self.info.frame_samples(frame_idx) as u64;
491
492 let overlap_start = start.max(frame_start_sample) - frame_start_sample;
494 let overlap_end = end.min(frame_end_sample) - frame_start_sample;
495
496 let byte_start = overlap_start as usize * block_align;
497 let byte_end = overlap_end as usize * block_align;
498
499 if byte_end <= frame_pcm.len() {
500 pcm_output.extend_from_slice(&frame_pcm[byte_start..byte_end]);
501 }
502 }
503
504 Ok(pcm_output)
505 }
506
507 pub fn seek(&mut self, sample: u64) -> ApeResult<SeekResult> {
511 if self.info.total_frames == 0 {
512 return Ok(SeekResult {
513 frame_index: 0,
514 skip_samples: 0,
515 actual_sample: 0,
516 });
517 }
518 let sample = sample.min(self.info.total_samples.saturating_sub(1));
519 let frame_index = (sample / self.info.blocks_per_frame as u64) as u32;
520 let frame_index = frame_index.min(self.info.total_frames - 1);
521 let frame_start = frame_index as u64 * self.info.blocks_per_frame as u64;
522 let skip_samples = (sample - frame_start) as u32;
523
524 Ok(SeekResult {
525 frame_index,
526 skip_samples,
527 actual_sample: sample,
528 })
529 }
530
531 pub fn decode_from(&mut self, sample: u64) -> ApeResult<Vec<u8>> {
534 let pos = self.seek(sample)?;
535 let frame_pcm = self.decode_frame(pos.frame_index)?;
536 let skip_bytes = pos.skip_samples as usize * self.info.block_align as usize;
537 Ok(frame_pcm[skip_bytes..].to_vec())
538 }
539
540 pub fn wav_header_data(&self) -> Option<&[u8]> {
543 if self.file_info.wav_header_data.is_empty() {
544 None
545 } else {
546 Some(&self.file_info.wav_header_data)
547 }
548 }
549
550 pub fn wav_terminating_bytes(&self) -> u32 {
552 self.file_info.terminating_data_bytes
553 }
554
555 pub fn read_tag(&mut self) -> ApeResult<Option<ApeTag>> {
558 tag::read_tag(&mut self.reader)
559 }
560
561 pub fn read_id3v2_tag(&mut self) -> ApeResult<Option<Id3v2Tag>> {
564 id3v2::read_id3v2(&mut self.reader)
565 }
566
567 pub fn stored_md5(&self) -> &[u8; 16] {
569 &self.file_info.descriptor.md5
570 }
571
572 pub fn verify_md5(&mut self) -> ApeResult<bool> {
579 use md5::{Digest, Md5};
580
581 let desc = &self.file_info.descriptor;
582
583 if desc.version < 3980 {
585 return Err(ApeError::UnsupportedVersion(desc.version));
586 }
587
588 if desc.md5 == [0u8; 16] {
590 return Ok(true); }
592
593 let junk = self.file_info.junk_header_bytes as u64;
594 let desc_bytes = desc.descriptor_bytes as u64;
595 let header_bytes = desc.header_bytes as u64;
596 let seek_table_bytes = desc.seek_table_bytes as u64;
597 let header_data_bytes = desc.header_data_bytes as u64;
598 let frame_data_bytes = self.file_info.ape_frame_data_bytes;
599 let term_bytes = desc.terminating_data_bytes as u64;
600
601 let mut hasher = Md5::new();
602
603 let header_data_pos = junk + desc_bytes + header_bytes + seek_table_bytes;
605 self.reader.seek(SeekFrom::Start(header_data_pos))?;
606 copy_to_hasher(&mut self.reader, &mut hasher, header_data_bytes)?;
607
608 copy_to_hasher(&mut self.reader, &mut hasher, frame_data_bytes + term_bytes)?;
611
612 let header_pos = junk + desc_bytes;
614 self.reader.seek(SeekFrom::Start(header_pos))?;
615 copy_to_hasher(&mut self.reader, &mut hasher, header_bytes)?;
616
617 copy_to_hasher(&mut self.reader, &mut hasher, seek_table_bytes)?;
620
621 let computed: [u8; 16] = hasher.finalize().into();
623 Ok(computed == desc.md5)
624 }
625
626 pub fn frames(&mut self) -> FrameIterator<'_, R> {
628 FrameIterator {
629 decoder: self,
630 current_frame: 0,
631 }
632 }
633
634 fn seek_remainder(&self, frame_idx: u32) -> u32 {
637 let seek_byte = self.file_info.seek_byte(frame_idx);
638 let seek_byte_0 = self.file_info.seek_byte(0);
639 ((seek_byte - seek_byte_0) % 4) as u32
640 }
641
642 fn read_frame_data(&mut self, frame_idx: u32) -> ApeResult<Vec<u8>> {
643 let seek_byte = self.file_info.seek_byte(frame_idx);
644 let seek_remainder = self.seek_remainder(frame_idx);
645 let frame_bytes = self.file_info.frame_byte_count(frame_idx);
646 let read_bytes = (frame_bytes as u32 + seek_remainder + 4) as usize;
647
648 self.reader
649 .seek(SeekFrom::Start(seek_byte - seek_remainder as u64))?;
650 let mut frame_data = vec![0u8; read_bytes];
651 let bytes_read = self.reader.read(&mut frame_data)?;
652 if bytes_read < read_bytes.saturating_sub(4) {
653 return Err(ApeError::DecodingError("short read on frame data"));
654 }
655 frame_data.truncate(bytes_read);
656 Ok(frame_data)
657 }
658}
659
660pub struct FrameIterator<'a, R: Read + Seek> {
662 decoder: &'a mut ApeDecoder<R>,
663 current_frame: u32,
664}
665
666impl<'a, R: Read + Seek> Iterator for FrameIterator<'a, R> {
667 type Item = ApeResult<Vec<u8>>;
668
669 fn next(&mut self) -> Option<Self::Item> {
670 if self.current_frame >= self.decoder.info.total_frames {
671 return None;
672 }
673 let frame_idx = self.current_frame;
674 self.current_frame += 1;
675 Some(self.decoder.decode_frame(frame_idx))
676 }
677
678 fn size_hint(&self) -> (usize, Option<usize>) {
679 let remaining = (self.decoder.info.total_frames - self.current_frame) as usize;
680 (remaining, Some(remaining))
681 }
682}
683
684pub fn decode<R: Read + Seek>(reader: &mut R) -> ApeResult<Vec<u8>> {
686 let mut decoder = ApeDecoder::new_from_ref(reader)?;
690 decoder.decode_all()
691}
692
693impl<R: Read + Seek> ApeDecoder<R> {
694 fn new_from_ref<'a>(reader: &'a mut R) -> ApeResult<ApeDecoder<&'a mut R>> {
695 ApeDecoder::new(reader)
696 }
697}
698
699fn try_decode_frame_16(
704 frame_data: &[u8],
705 seek_remainder: u32,
706 frame_blocks: usize,
707 version: i32,
708 channels: u16,
709 bits: u16,
710 block_align: usize,
711 predictors: &mut [Predictor3950],
712 entropy_states: &mut [EntropyState],
713 range_coder: &mut RangeCoder,
714) -> ApeResult<Vec<u8>> {
715 let mut br = BitReader::from_frame_bytes(frame_data, seek_remainder * 8);
716
717 let mut stored_crc = br.decode_value_x_bits(32);
719 let mut special_codes: i32 = 0;
720 if version > 3820 {
721 if stored_crc & 0x80000000 != 0 {
722 special_codes = br.decode_value_x_bits(32) as i32;
723 }
724 stored_crc &= 0x7FFFFFFF;
725 }
726
727 for p in predictors.iter_mut() {
728 p.flush();
729 }
730 for s in entropy_states.iter_mut() {
731 s.flush();
732 }
733 range_coder.flush_bit_array(&mut br);
734
735 let mut last_x: i32 = 0;
736 let mut pcm_output = Vec::with_capacity(frame_blocks * block_align);
737
738 let decode_result: ApeResult<()> = (|| {
739 if channels == 2 {
740 if (special_codes & SPECIAL_FRAME_LEFT_SILENCE) != 0
741 && (special_codes & SPECIAL_FRAME_RIGHT_SILENCE) != 0
742 {
743 for _ in 0..frame_blocks {
744 unprepare::unprepare(&[0, 0], channels, bits, &mut pcm_output)?;
745 }
746 } else if (special_codes & SPECIAL_FRAME_PSEUDO_STEREO) != 0 {
747 for _ in 0..frame_blocks {
748 let val = entropy_states[0].decode_value_range(range_coder, &mut br)?;
749 let x = predictors[0].decompress_value(val, 0);
750 unprepare::unprepare(&[x, 0], channels, bits, &mut pcm_output)?;
751 }
752 } else if version >= 3950 {
753 for _ in 0..frame_blocks {
754 let ny = entropy_states[1].decode_value_range(range_coder, &mut br)?;
755 let nx = entropy_states[0].decode_value_range(range_coder, &mut br)?;
756 let y = predictors[1].decompress_value(ny, last_x as i64);
757 let x = predictors[0].decompress_value(nx, y as i64);
758 last_x = x;
759 unprepare::unprepare(&[x, y], channels, bits, &mut pcm_output)?;
760 }
761 } else {
762 for _ in 0..frame_blocks {
763 let ex = entropy_states[0].decode_value_range(range_coder, &mut br)?;
764 let ey = entropy_states[1].decode_value_range(range_coder, &mut br)?;
765 let x = predictors[0].decompress_value(ex, 0);
766 let y = predictors[1].decompress_value(ey, 0);
767 unprepare::unprepare(&[x, y], channels, bits, &mut pcm_output)?;
768 }
769 }
770 } else if channels == 1 {
771 if (special_codes & SPECIAL_FRAME_MONO_SILENCE) != 0 {
772 for _ in 0..frame_blocks {
773 unprepare::unprepare(&[0], channels, bits, &mut pcm_output)?;
774 }
775 } else {
776 for _ in 0..frame_blocks {
777 let val = entropy_states[0].decode_value_range(range_coder, &mut br)?;
778 let decoded = predictors[0].decompress_value(val, 0);
779 unprepare::unprepare(&[decoded], channels, bits, &mut pcm_output)?;
780 }
781 }
782 } else {
783 let ch = channels as usize;
784 let mut values = vec![0i32; ch];
785 for _ in 0..frame_blocks {
786 for c in 0..ch {
787 let val = entropy_states[c].decode_value_range(range_coder, &mut br)?;
788 values[c] = predictors[c].decompress_value(val, 0);
789 }
790 unprepare::unprepare(&values, channels, bits, &mut pcm_output)?;
791 }
792 }
793 Ok(())
794 })();
795
796 decode_result?;
797
798 range_coder.finalize(&mut br);
800 let computed_crc = ape_crc(&pcm_output);
801 if computed_crc != stored_crc {
802 return Err(ApeError::InvalidChecksum);
803 }
804
805 apply_post_processing(&mut pcm_output, bits, channels);
807
808 Ok(pcm_output)
809}
810
811fn try_decode_frame_32(
812 frame_data: &[u8],
813 seek_remainder: u32,
814 frame_blocks: usize,
815 version: i32,
816 channels: u16,
817 bits: u16,
818 block_align: usize,
819 predictors: &mut [Predictor3950_32],
820 entropy_states: &mut [EntropyState],
821 range_coder: &mut RangeCoder,
822) -> ApeResult<Vec<u8>> {
823 let mut br = BitReader::from_frame_bytes(frame_data, seek_remainder * 8);
824
825 let mut stored_crc = br.decode_value_x_bits(32);
826 let mut special_codes: i32 = 0;
827 if version > 3820 {
828 if stored_crc & 0x80000000 != 0 {
829 special_codes = br.decode_value_x_bits(32) as i32;
830 }
831 stored_crc &= 0x7FFFFFFF;
832 }
833
834 for p in predictors.iter_mut() {
835 p.flush();
836 }
837 for s in entropy_states.iter_mut() {
838 s.flush();
839 }
840 range_coder.flush_bit_array(&mut br);
841
842 let mut last_x: i64 = 0;
843 let mut pcm_output = Vec::with_capacity(frame_blocks * block_align);
844
845 if channels == 2 {
846 if (special_codes & SPECIAL_FRAME_LEFT_SILENCE) != 0
847 && (special_codes & SPECIAL_FRAME_RIGHT_SILENCE) != 0
848 {
849 for _ in 0..frame_blocks {
850 unprepare::unprepare(&[0, 0], channels, bits, &mut pcm_output)?;
851 }
852 } else if (special_codes & SPECIAL_FRAME_PSEUDO_STEREO) != 0 {
853 for _ in 0..frame_blocks {
854 let val = entropy_states[0].decode_value_range(range_coder, &mut br)?;
855 let x = predictors[0].decompress_value(val, 0);
856 unprepare::unprepare(&[x as i32, 0], channels, bits, &mut pcm_output)?;
857 }
858 } else {
859 for _ in 0..frame_blocks {
860 let ny = entropy_states[1].decode_value_range(range_coder, &mut br)?;
861 let nx = entropy_states[0].decode_value_range(range_coder, &mut br)?;
862 let y = predictors[1].decompress_value(ny, last_x);
863 let x = predictors[0].decompress_value(nx, y as i64);
864 last_x = x as i64;
865 unprepare::unprepare(&[x as i32, y as i32], channels, bits, &mut pcm_output)?;
866 }
867 }
868 } else if channels == 1 {
869 if (special_codes & SPECIAL_FRAME_MONO_SILENCE) != 0 {
870 for _ in 0..frame_blocks {
871 unprepare::unprepare(&[0], channels, bits, &mut pcm_output)?;
872 }
873 } else {
874 for _ in 0..frame_blocks {
875 let val = entropy_states[0].decode_value_range(range_coder, &mut br)?;
876 let decoded = predictors[0].decompress_value(val, 0);
877 unprepare::unprepare(&[decoded as i32], channels, bits, &mut pcm_output)?;
878 }
879 }
880 }
881
882 range_coder.finalize(&mut br);
883 let computed_crc = ape_crc(&pcm_output);
884 if computed_crc != stored_crc {
885 return Err(ApeError::InvalidChecksum);
886 }
887
888 apply_post_processing(&mut pcm_output, bits, channels);
890
891 Ok(pcm_output)
892}
893
894fn copy_to_hasher<R: Read>(reader: &mut R, hasher: &mut md5::Md5, mut n: u64) -> ApeResult<()> {
902 use md5::Digest;
903 let mut buf = [0u8; 16384];
904 while n > 0 {
905 let to_read = (n as usize).min(buf.len());
906 reader.read_exact(&mut buf[..to_read])?;
907 hasher.update(&buf[..to_read]);
908 n -= to_read as u64;
909 }
910 Ok(())
911}
912
913fn apply_post_processing(pcm: &mut [u8], bits: u16, _channels: u16) {
916 let _ = (pcm, bits);
932}
933
934#[allow(dead_code)]
939fn float_transform_sample(sample_in: u32) -> u32 {
940 let mut out: u32 = 0;
941 out |= sample_in & 0xC3FF_FFFF;
942 out |= !(sample_in & 0x3C00_0000) ^ 0xC3FF_FFFF;
943 if out & 0x8000_0000 != 0 {
944 out = !out | 0x8000_0000;
945 }
946 out
947}
948
949#[allow(dead_code)]
951fn byte_swap_samples(pcm: &mut [u8], bytes_per_sample: usize) {
952 match bytes_per_sample {
953 2 => {
954 for chunk in pcm.chunks_exact_mut(2) {
955 chunk.swap(0, 1);
956 }
957 }
958 3 => {
959 for chunk in pcm.chunks_exact_mut(3) {
960 chunk.swap(0, 2);
961 }
962 }
963 4 => {
964 for chunk in pcm.chunks_exact_mut(4) {
965 chunk.swap(0, 3);
966 chunk.swap(1, 2);
967 }
968 }
969 _ => {}
970 }
971}
972
973#[cfg(test)]
974mod tests {
975 use super::*;
976 use std::fs::File;
977 use std::io::BufReader;
978 use std::path::PathBuf;
979
980 fn test_fixture_path(name: &str) -> PathBuf {
981 PathBuf::from(env!("CARGO_MANIFEST_DIR"))
982 .join("tests/fixtures")
983 .join(name)
984 }
985
986 fn load_reference_pcm(name: &str) -> Vec<u8> {
987 let path = test_fixture_path(&format!("ref/{}", name));
988 let data = std::fs::read(&path)
989 .unwrap_or_else(|e| panic!("Failed to read {}: {}", path.display(), e));
990 data[44..].to_vec()
991 }
992
993 fn open_ape(name: &str) -> BufReader<File> {
994 let path = test_fixture_path(&format!("ape/{}", name));
995 let file = File::open(&path)
996 .unwrap_or_else(|e| panic!("Failed to open {}: {}", path.display(), e));
997 BufReader::new(file)
998 }
999
1000 fn decode_ape_file(name: &str) -> ApeResult<Vec<u8>> {
1001 let mut reader = open_ape(name);
1002 decode(&mut reader)
1003 }
1004
1005 #[test]
1008 fn test_decode_sine_16s_c1000() {
1009 let decoded = decode_ape_file("sine_16s_c1000.ape").unwrap();
1010 let expected = load_reference_pcm("sine_16s_c1000.wav");
1011 assert_eq!(decoded.len(), expected.len());
1012 assert_eq!(decoded, expected);
1013 }
1014
1015 #[test]
1016 fn test_decode_sine_16s_c2000() {
1017 let decoded = decode_ape_file("sine_16s_c2000.ape").unwrap();
1018 let expected = load_reference_pcm("sine_16s_c2000.wav");
1019 assert_eq!(decoded, expected);
1020 }
1021
1022 #[test]
1023 fn test_decode_silence_16s() {
1024 let decoded = decode_ape_file("silence_16s_c2000.ape").unwrap();
1025 let expected = load_reference_pcm("silence_16s_c2000.wav");
1026 assert_eq!(decoded, expected);
1027 }
1028
1029 #[test]
1030 fn test_decode_sine_16m() {
1031 let decoded = decode_ape_file("sine_16m_c2000.ape").unwrap();
1032 let expected = load_reference_pcm("sine_16m_c2000.wav");
1033 assert_eq!(decoded, expected);
1034 }
1035
1036 #[test]
1037 fn test_decode_short_16s() {
1038 let decoded = decode_ape_file("short_16s_c2000.ape").unwrap();
1039 let expected = load_reference_pcm("short_16s_c2000.wav");
1040 assert_eq!(decoded, expected);
1041 }
1042
1043 #[test]
1044 fn test_decode_all_compression_levels() {
1045 for level in &["c1000", "c2000", "c3000", "c4000", "c5000"] {
1046 let name = format!("sine_16s_{}.ape", level);
1047 let ref_name = format!("sine_16s_{}.wav", level);
1048 let decoded = decode_ape_file(&name).unwrap_or_else(|e| panic!("{}: {:?}", name, e));
1049 let expected = load_reference_pcm(&ref_name);
1050 assert_eq!(decoded, expected, "Mismatch for {}", name);
1051 }
1052 }
1053
1054 #[test]
1055 fn test_decode_8bit() {
1056 let decoded = decode_ape_file("sine_8s_c2000.ape").unwrap();
1057 let expected = load_reference_pcm("sine_8s_c2000.wav");
1058 assert_eq!(decoded, expected);
1059 }
1060
1061 #[test]
1062 fn test_decode_24bit() {
1063 let decoded = decode_ape_file("sine_24s_c2000.ape").unwrap();
1064 let expected = load_reference_pcm("sine_24s_c2000.wav");
1065 assert_eq!(decoded, expected);
1066 }
1067
1068 #[test]
1069 fn test_decode_32bit() {
1070 let decoded = decode_ape_file("sine_32s_c2000.ape").unwrap();
1071 let expected = load_reference_pcm("sine_32s_c2000.wav");
1072 assert_eq!(decoded, expected);
1073 }
1074
1075 #[test]
1076 fn test_decode_multiframe() {
1077 let decoded = decode_ape_file("multiframe_16s_c2000.ape").unwrap();
1078 let expected = load_reference_pcm("multiframe_16s_c2000.wav");
1079 assert_eq!(decoded, expected);
1080 }
1081
1082 #[test]
1083 fn test_decode_identical_channels() {
1084 let decoded = decode_ape_file("identical_16s_c2000.ape").unwrap();
1085 let expected = load_reference_pcm("identical_16s_c2000.wav");
1086 assert_eq!(decoded, expected);
1087 }
1088
1089 #[test]
1090 fn test_decode_all_fixtures() {
1091 let fixtures = [
1092 "dc_offset_16s_c2000.ape",
1093 "identical_16s_c2000.ape",
1094 "impulse_16s_c2000.ape",
1095 "left_only_16s_c2000.ape",
1096 "multiframe_16s_c2000.ape",
1097 "noise_16s_c2000.ape",
1098 "short_16s_c2000.ape",
1099 "silence_16s_c2000.ape",
1100 "sine_16m_c2000.ape",
1101 "sine_16s_c1000.ape",
1102 "sine_16s_c2000.ape",
1103 "sine_16s_c3000.ape",
1104 "sine_16s_c4000.ape",
1105 "sine_16s_c5000.ape",
1106 "sine_24s_c2000.ape",
1107 "sine_32s_c2000.ape",
1108 "sine_8s_c2000.ape",
1109 ];
1110
1111 for fixture in &fixtures {
1112 let ref_name = fixture.replace(".ape", ".wav");
1113 let decoded = decode_ape_file(fixture)
1114 .unwrap_or_else(|e| panic!("Failed to decode {}: {:?}", fixture, e));
1115 let expected = load_reference_pcm(&ref_name);
1116 assert_eq!(
1117 decoded.len(),
1118 expected.len(),
1119 "Length mismatch for {}",
1120 fixture
1121 );
1122 assert_eq!(decoded, expected, "Data mismatch for {}", fixture);
1123 }
1124 }
1125
1126 #[test]
1129 fn test_ape_decoder_info() {
1130 let reader = open_ape("sine_16s_c2000.ape");
1131 let decoder = ApeDecoder::new(reader).unwrap();
1132 let info = decoder.info();
1133 assert_eq!(info.sample_rate, 44100);
1134 assert_eq!(info.channels, 2);
1135 assert_eq!(info.bits_per_sample, 16);
1136 assert_eq!(info.total_samples, 44100);
1137 assert_eq!(info.compression_level, 2000);
1138 assert_eq!(info.block_align, 4);
1139 }
1140
1141 #[test]
1142 fn test_decode_frame_by_frame() {
1143 let reader = open_ape("sine_16s_c2000.ape");
1144 let mut decoder = ApeDecoder::new(reader).unwrap();
1145 let expected = load_reference_pcm("sine_16s_c2000.wav");
1146
1147 let mut all_pcm = Vec::new();
1148 for frame_idx in 0..decoder.total_frames() {
1149 let frame_pcm = decoder.decode_frame(frame_idx).unwrap();
1150 all_pcm.extend_from_slice(&frame_pcm);
1151 }
1152
1153 assert_eq!(all_pcm, expected);
1154 }
1155
1156 #[test]
1157 fn test_decode_multiframe_frame_by_frame() {
1158 let reader = open_ape("multiframe_16s_c2000.ape");
1159 let mut decoder = ApeDecoder::new(reader).unwrap();
1160 let expected = load_reference_pcm("multiframe_16s_c2000.wav");
1161
1162 assert!(decoder.total_frames() > 1, "Expected multiple frames");
1163
1164 let mut all_pcm = Vec::new();
1165 for frame_idx in 0..decoder.total_frames() {
1166 let frame_pcm = decoder.decode_frame(frame_idx).unwrap();
1167 assert!(!frame_pcm.is_empty());
1168 all_pcm.extend_from_slice(&frame_pcm);
1169 }
1170
1171 assert_eq!(all_pcm, expected);
1172 }
1173
1174 #[test]
1175 fn test_frames_iterator() {
1176 let reader = open_ape("sine_16s_c2000.ape");
1177 let mut decoder = ApeDecoder::new(reader).unwrap();
1178 let expected = load_reference_pcm("sine_16s_c2000.wav");
1179
1180 let all_pcm: Vec<u8> = decoder
1181 .frames()
1182 .collect::<Result<Vec<_>, _>>()
1183 .unwrap()
1184 .concat();
1185
1186 assert_eq!(all_pcm, expected);
1187 }
1188
1189 #[test]
1190 fn test_seek_sample_level() {
1191 let reader = open_ape("multiframe_16s_c2000.ape");
1192 let mut decoder = ApeDecoder::new(reader).unwrap();
1193 let bpf = decoder.info().blocks_per_frame as u64;
1194
1195 let r = decoder.seek(0).unwrap();
1197 assert_eq!(r.frame_index, 0);
1198 assert_eq!(r.skip_samples, 0);
1199 assert_eq!(r.actual_sample, 0);
1200
1201 let r = decoder.seek(100).unwrap();
1203 assert_eq!(r.frame_index, 0);
1204 assert_eq!(r.skip_samples, 100);
1205 assert_eq!(r.actual_sample, 100);
1206
1207 let r = decoder.seek(bpf).unwrap();
1209 assert_eq!(r.frame_index, 1);
1210 assert_eq!(r.skip_samples, 0);
1211 assert_eq!(r.actual_sample, bpf);
1212
1213 let r = decoder.seek(bpf + 100).unwrap();
1215 assert_eq!(r.frame_index, 1);
1216 assert_eq!(r.skip_samples, 100);
1217 assert_eq!(r.actual_sample, bpf + 100);
1218
1219 let r = decoder.seek(u64::MAX).unwrap();
1221 assert_eq!(r.actual_sample, decoder.info().total_samples - 1);
1222 }
1223
1224 #[test]
1225 fn test_decode_from_mid_frame() {
1226 let reader = open_ape("sine_16s_c2000.ape");
1227 let mut decoder = ApeDecoder::new(reader).unwrap();
1228 let block_align = decoder.info().block_align as usize;
1229
1230 let full_frame = decoder.decode_frame(0).unwrap();
1232
1233 let partial = decoder.decode_from(100).unwrap();
1235
1236 let skip = 100 * block_align;
1238 assert_eq!(partial, &full_frame[skip..]);
1239 }
1240
1241 #[test]
1242 fn test_expanded_metadata() {
1243 let reader = open_ape("sine_16s_c2000.ape");
1244 let decoder = ApeDecoder::new(reader).unwrap();
1245 let info = decoder.info();
1246
1247 assert_eq!(info.bytes_per_sample, 2);
1248 assert_eq!(info.source_format, SourceFormat::Wav);
1249 assert!(!info.is_big_endian);
1250 assert!(!info.is_floating_point);
1251 assert!(!info.is_signed_8bit);
1252 assert!(info.average_bitrate_kbps > 0);
1253 assert!(info.decompressed_bitrate_kbps > 0);
1254 assert!(info.file_size_bytes > 0);
1255 assert_eq!(info.format_flags & 0x0200, 0); }
1257
1258 #[test]
1259 fn test_wav_header_data() {
1260 let reader = open_ape("sine_16s_c2000.ape");
1261 let decoder = ApeDecoder::new(reader).unwrap();
1262
1263 let header = decoder.wav_header_data();
1264 if let Some(data) = header {
1266 assert!(data.len() >= 12);
1267 assert_eq!(&data[0..4], b"RIFF");
1269 }
1270 }
1271
1272 #[test]
1273 fn test_read_tag() {
1274 let reader = open_ape("sine_16s_c2000.ape");
1275 let mut decoder = ApeDecoder::new(reader).unwrap();
1276 let _tag = decoder.read_tag();
1278 }
1279
1280 #[test]
1281 fn test_decode_frame_out_of_bounds() {
1282 let reader = open_ape("sine_16s_c2000.ape");
1283 let mut decoder = ApeDecoder::new(reader).unwrap();
1284 let result = decoder.decode_frame(999);
1285 assert!(result.is_err());
1286 }
1287
1288 #[test]
1291 fn test_decode_with_progress() {
1292 let reader = open_ape("sine_16s_c2000.ape");
1293 let mut decoder = ApeDecoder::new(reader).unwrap();
1294 let expected = load_reference_pcm("sine_16s_c2000.wav");
1295
1296 let mut last_progress = 0.0f64;
1297 let decoded = decoder
1298 .decode_all_with(|p| {
1299 assert!(p >= last_progress, "progress must be monotonic");
1300 last_progress = p;
1301 true })
1303 .unwrap();
1304
1305 assert!((last_progress - 1.0).abs() < 0.01);
1306 assert_eq!(decoded, expected);
1307 }
1308
1309 #[test]
1310 fn test_decode_with_cancel() {
1311 let reader = open_ape("multiframe_16s_c2000.ape");
1312 let mut decoder = ApeDecoder::new(reader).unwrap();
1313
1314 let result = decoder.decode_all_with(|p| {
1315 p < 0.5 });
1317
1318 assert!(result.is_err());
1319 }
1320
1321 #[test]
1324 fn test_decode_range_full_file() {
1325 let reader = open_ape("sine_16s_c2000.ape");
1326 let mut decoder = ApeDecoder::new(reader).unwrap();
1327 let total = decoder.info().total_samples;
1328 let expected = load_reference_pcm("sine_16s_c2000.wav");
1329
1330 let decoded = decoder.decode_range(0, total).unwrap();
1331 assert_eq!(decoded, expected);
1332 }
1333
1334 #[test]
1335 fn test_decode_range_subset() {
1336 let reader = open_ape("sine_16s_c2000.ape");
1337 let mut decoder = ApeDecoder::new(reader).unwrap();
1338 let block_align = decoder.info().block_align as usize;
1339 let expected = load_reference_pcm("sine_16s_c2000.wav");
1340
1341 let decoded = decoder.decode_range(100, 200).unwrap();
1343 assert_eq!(decoded.len(), 100 * block_align);
1344 assert_eq!(decoded, &expected[100 * block_align..200 * block_align]);
1345 }
1346
1347 #[test]
1348 fn test_decode_range_empty() {
1349 let reader = open_ape("sine_16s_c2000.ape");
1350 let mut decoder = ApeDecoder::new(reader).unwrap();
1351
1352 let decoded = decoder.decode_range(100, 100).unwrap();
1353 assert!(decoded.is_empty());
1354
1355 let decoded = decoder.decode_range(200, 100).unwrap();
1356 assert!(decoded.is_empty());
1357 }
1358
1359 #[test]
1362 fn test_decode_parallel_matches_sequential() {
1363 let expected = load_reference_pcm("sine_16s_c2000.wav");
1364
1365 let reader = open_ape("sine_16s_c2000.ape");
1366 let mut decoder = ApeDecoder::new(reader).unwrap();
1367 let parallel = decoder.decode_all_parallel(4).unwrap();
1368
1369 assert_eq!(parallel, expected);
1370 }
1371
1372 #[test]
1373 fn test_decode_parallel_multiframe() {
1374 let expected = load_reference_pcm("multiframe_16s_c2000.wav");
1375
1376 let reader = open_ape("multiframe_16s_c2000.ape");
1377 let mut decoder = ApeDecoder::new(reader).unwrap();
1378 let parallel = decoder.decode_all_parallel(2).unwrap();
1379
1380 assert_eq!(parallel, expected);
1381 }
1382
1383 #[test]
1384 fn test_decode_parallel_single_thread() {
1385 let expected = load_reference_pcm("sine_16s_c2000.wav");
1386
1387 let reader = open_ape("sine_16s_c2000.ape");
1388 let mut decoder = ApeDecoder::new(reader).unwrap();
1389 let decoded = decoder.decode_all_parallel(1).unwrap();
1390
1391 assert_eq!(decoded, expected);
1392 }
1393
1394 #[test]
1395 fn test_decode_parallel_all_fixtures() {
1396 let fixtures = [
1397 "dc_offset_16s_c2000.ape",
1398 "identical_16s_c2000.ape",
1399 "impulse_16s_c2000.ape",
1400 "left_only_16s_c2000.ape",
1401 "multiframe_16s_c2000.ape",
1402 "noise_16s_c2000.ape",
1403 "short_16s_c2000.ape",
1404 "silence_16s_c2000.ape",
1405 "sine_16m_c2000.ape",
1406 "sine_16s_c1000.ape",
1407 "sine_16s_c2000.ape",
1408 "sine_16s_c3000.ape",
1409 "sine_16s_c4000.ape",
1410 "sine_16s_c5000.ape",
1411 "sine_24s_c2000.ape",
1412 "sine_32s_c2000.ape",
1413 "sine_8s_c2000.ape",
1414 ];
1415
1416 for fixture in &fixtures {
1417 let ref_name = fixture.replace(".ape", ".wav");
1418 let reader = open_ape(fixture);
1419 let mut decoder = ApeDecoder::new(reader).unwrap();
1420 let parallel = decoder
1421 .decode_all_parallel(2)
1422 .unwrap_or_else(|e| panic!("Parallel decode failed for {}: {:?}", fixture, e));
1423 let expected = load_reference_pcm(&ref_name);
1424 assert_eq!(parallel, expected, "Parallel mismatch for {}", fixture);
1425 }
1426 }
1427
1428 #[test]
1431 fn test_decode_truncated_file() {
1432 let data = vec![0u8; 10];
1434 let mut cursor = std::io::Cursor::new(data);
1435 let result = decode(&mut cursor);
1436 assert!(result.is_err());
1437 }
1438
1439 #[test]
1440 fn test_decode_wrong_magic() {
1441 let mut data = vec![0u8; 200];
1443 data[0..4].copy_from_slice(b"NOPE");
1444 let mut cursor = std::io::Cursor::new(data);
1445 let result = decode(&mut cursor);
1446 assert!(result.is_err());
1447 }
1448
1449 #[test]
1450 fn test_decode_empty_file() {
1451 let data = vec![];
1452 let mut cursor = std::io::Cursor::new(data);
1453 let result = decode(&mut cursor);
1454 assert!(result.is_err());
1455 }
1456
1457 #[test]
1458 fn test_decoder_new_truncated() {
1459 let data = vec![0u8; 50]; let cursor = std::io::Cursor::new(data);
1461 let result = ApeDecoder::new(cursor);
1462 assert!(result.is_err());
1463 }
1464
1465 #[test]
1468 fn test_float_transform_roundtrip() {
1469 let original: u32 = 0x3F800000; let transformed = super::float_transform_sample(original);
1472 let restored = super::float_transform_sample(transformed);
1473 assert_eq!(restored, original);
1474 }
1475
1476 #[test]
1477 fn test_float_transform_zero() {
1478 let transformed = super::float_transform_sample(0);
1479 let restored = super::float_transform_sample(transformed);
1480 assert_eq!(restored, 0);
1481 }
1482
1483 #[test]
1484 fn test_byte_swap_16bit() {
1485 let mut data = vec![0x01, 0x02, 0x03, 0x04];
1486 super::byte_swap_samples(&mut data, 2);
1487 assert_eq!(data, vec![0x02, 0x01, 0x04, 0x03]);
1488 }
1489
1490 #[test]
1491 fn test_byte_swap_24bit() {
1492 let mut data = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06];
1493 super::byte_swap_samples(&mut data, 3);
1494 assert_eq!(data, vec![0x03, 0x02, 0x01, 0x06, 0x05, 0x04]);
1495 }
1496
1497 #[test]
1498 fn test_byte_swap_32bit() {
1499 let mut data = vec![0x01, 0x02, 0x03, 0x04];
1500 super::byte_swap_samples(&mut data, 4);
1501 assert_eq!(data, vec![0x04, 0x03, 0x02, 0x01]);
1502 }
1503
1504 #[test]
1507 fn test_verify_md5_all_fixtures() {
1508 let fixtures = [
1509 "dc_offset_16s_c2000.ape",
1510 "identical_16s_c2000.ape",
1511 "impulse_16s_c2000.ape",
1512 "left_only_16s_c2000.ape",
1513 "multiframe_16s_c2000.ape",
1514 "noise_16s_c2000.ape",
1515 "short_16s_c2000.ape",
1516 "silence_16s_c2000.ape",
1517 "sine_16m_c2000.ape",
1518 "sine_16s_c1000.ape",
1519 "sine_16s_c2000.ape",
1520 "sine_16s_c3000.ape",
1521 "sine_16s_c4000.ape",
1522 "sine_16s_c5000.ape",
1523 "sine_24s_c2000.ape",
1524 "sine_32s_c2000.ape",
1525 "sine_8s_c2000.ape",
1526 ];
1527
1528 for fixture in &fixtures {
1529 let reader = open_ape(fixture);
1530 let mut decoder = ApeDecoder::new(reader).unwrap();
1531 let result = decoder
1532 .verify_md5()
1533 .unwrap_or_else(|e| panic!("MD5 verify failed for {}: {:?}", fixture, e));
1534 assert!(result, "MD5 mismatch for {}", fixture);
1535 }
1536 }
1537
1538 #[test]
1539 fn test_stored_md5_nonzero() {
1540 let reader = open_ape("sine_16s_c2000.ape");
1541 let decoder = ApeDecoder::new(reader).unwrap();
1542 let md5 = decoder.stored_md5();
1543 assert_ne!(md5, &[0u8; 16], "MD5 should not be all zeros");
1545 }
1546
1547 #[test]
1550 fn test_generate_wav_header() {
1551 let reader = open_ape("sine_16s_c2000.ape");
1552 let decoder = ApeDecoder::new(reader).unwrap();
1553 let header = decoder.info().generate_wav_header();
1554
1555 assert_eq!(header.len(), 44);
1557
1558 assert_eq!(&header[0..4], b"RIFF");
1560 assert_eq!(&header[8..12], b"WAVE");
1561 assert_eq!(&header[12..16], b"fmt ");
1562 assert_eq!(&header[36..40], b"data");
1563
1564 let channels = u16::from_le_bytes([header[22], header[23]]);
1566 let sample_rate = u32::from_le_bytes([header[24], header[25], header[26], header[27]]);
1567 let bits = u16::from_le_bytes([header[34], header[35]]);
1568 assert_eq!(channels, 2);
1569 assert_eq!(sample_rate, 44100);
1570 assert_eq!(bits, 16);
1571
1572 let data_size = u32::from_le_bytes([header[40], header[41], header[42], header[43]]);
1574 let expected = decoder.info().total_samples as u32 * decoder.info().block_align as u32;
1575 assert_eq!(data_size, expected);
1576 }
1577
1578 #[test]
1579 fn test_generate_wav_header_matches_stored() {
1580 let reader = open_ape("sine_16s_c2000.ape");
1581 let decoder = ApeDecoder::new(reader).unwrap();
1582
1583 let generated = decoder.info().generate_wav_header();
1584 if let Some(stored) = decoder.wav_header_data() {
1585 if stored.len() == 44 {
1587 assert_eq!(&generated[22..24], &stored[22..24]); assert_eq!(&generated[24..28], &stored[24..28]); assert_eq!(&generated[34..36], &stored[34..36]); }
1592 }
1593 }
1594}