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)
314 .checked_mul(self.info.block_align as usize)
315 .ok_or(ApeError::InvalidFormat("total PCM size overflow"))?;
316 if total_pcm_bytes > 2 * 1024 * 1024 * 1024 {
318 return Err(ApeError::InvalidFormat("total PCM size exceeds 2 GB"));
319 }
320 let mut pcm_output = Vec::with_capacity(total_pcm_bytes);
321
322 for frame_idx in 0..self.info.total_frames {
323 let frame_pcm = self.decode_frame(frame_idx)?;
324 pcm_output.extend_from_slice(&frame_pcm);
325 }
326
327 Ok(pcm_output)
328 }
329
330 pub fn decode_all_with<F: FnMut(f64) -> bool>(
335 &mut self,
336 mut on_progress: F,
337 ) -> ApeResult<Vec<u8>> {
338 let total = self.info.total_frames as f64;
339 let total_pcm_bytes = (self.info.total_samples as usize)
340 .checked_mul(self.info.block_align as usize)
341 .ok_or(ApeError::InvalidFormat("total PCM size overflow"))?;
342 if total_pcm_bytes > 2 * 1024 * 1024 * 1024 {
343 return Err(ApeError::InvalidFormat("total PCM size exceeds 2 GB"));
344 }
345 let mut pcm_output = Vec::with_capacity(total_pcm_bytes);
346
347 for frame_idx in 0..self.info.total_frames {
348 let frame_pcm = self.decode_frame(frame_idx)?;
349 pcm_output.extend_from_slice(&frame_pcm);
350
351 if !on_progress((frame_idx + 1) as f64 / total) {
352 return Err(ApeError::DecodingError("cancelled"));
353 }
354 }
355
356 Ok(pcm_output)
357 }
358
359 pub fn decode_all_parallel(&mut self, thread_count: usize) -> ApeResult<Vec<u8>> {
367 if thread_count <= 1 {
368 return self.decode_all();
369 }
370
371 let total_frames = self.info.total_frames;
372 let version = self.info.version as i32;
373 let channels = self.info.channels;
374 let bits = self.info.bits_per_sample;
375 let compression = self.info.compression_level as u32;
376 let block_align = self.info.block_align as usize;
377
378 let mut frame_data_list: Vec<(Vec<u8>, u32, usize)> =
380 Vec::with_capacity(total_frames as usize);
381 for frame_idx in 0..total_frames {
382 let data = self.read_frame_data(frame_idx)?;
383 let seek_remainder = self.seek_remainder(frame_idx);
384 let frame_blocks = self.file_info.frame_block_count(frame_idx) as usize;
385 frame_data_list.push((data, seek_remainder, frame_blocks));
386 }
387
388 let chunk_size = (total_frames as usize + thread_count - 1) / thread_count;
390 let chunks: Vec<Vec<(usize, Vec<u8>, u32, usize)>> = frame_data_list
391 .into_iter()
392 .enumerate()
393 .collect::<Vec<_>>()
394 .chunks(chunk_size)
395 .map(|chunk| {
396 chunk
397 .iter()
398 .map(|(i, (data, sr, fb))| (*i, data.clone(), *sr, *fb))
399 .collect()
400 })
401 .collect();
402
403 let mut handles = Vec::new();
404 for chunk in chunks {
405 let v = version;
406 let ch = channels;
407 let b = bits;
408 let comp = compression;
409 let ba = block_align;
410
411 handles.push(std::thread::spawn(
412 move || -> ApeResult<Vec<(usize, Vec<u8>)>> {
413 let mut results = Vec::with_capacity(chunk.len());
414
415 let mut predictors: Vec<Predictor3950> =
417 (0..ch).map(|_| Predictor3950::new(comp, v, b)).collect();
418 let mut entropy_states: Vec<EntropyState> =
419 (0..ch).map(|_| EntropyState::new()).collect();
420 let mut range_coder = RangeCoder::new();
421
422 for (frame_idx, frame_data, seek_remainder, frame_blocks) in chunk {
423 let pcm = if b >= 32 {
424 let mut preds32: Vec<Predictor3950_32> =
425 (0..ch).map(|_| Predictor3950_32::new(comp, v)).collect();
426 try_decode_frame_32(
427 &frame_data,
428 seek_remainder,
429 frame_blocks,
430 v,
431 ch,
432 b,
433 ba,
434 &mut preds32,
435 &mut entropy_states,
436 &mut range_coder,
437 )?
438 } else {
439 try_decode_frame_16(
440 &frame_data,
441 seek_remainder,
442 frame_blocks,
443 v,
444 ch,
445 b,
446 ba,
447 &mut predictors,
448 &mut entropy_states,
449 &mut range_coder,
450 )?
451 };
452 results.push((frame_idx, pcm));
453 }
454 Ok(results)
455 },
456 ));
457 }
458
459 let mut all_results: Vec<(usize, Vec<u8>)> = Vec::with_capacity(total_frames as usize);
461 for handle in handles {
462 let chunk_results = handle
463 .join()
464 .map_err(|_| ApeError::DecodingError("thread panicked"))??;
465 all_results.extend(chunk_results);
466 }
467 all_results.sort_by_key(|(idx, _)| *idx);
468
469 let total_pcm = self.info.total_samples as usize * block_align;
470 let mut pcm_output = Vec::with_capacity(total_pcm);
471 for (_, pcm) in all_results {
472 pcm_output.extend_from_slice(&pcm);
473 }
474
475 Ok(pcm_output)
476 }
477
478 pub fn decode_range(&mut self, start_sample: u64, end_sample: u64) -> ApeResult<Vec<u8>> {
484 let start = start_sample.min(self.info.total_samples);
485 let end = end_sample.min(self.info.total_samples);
486 if start >= end {
487 return Ok(Vec::new());
488 }
489
490 let bpf = self.info.blocks_per_frame as u64;
491 let block_align = self.info.block_align as usize;
492 let first_frame = (start / bpf) as u32;
493 let last_frame = ((end - 1) / bpf).min(self.info.total_frames as u64 - 1) as u32;
494
495 let range_samples = (end - start) as usize;
496 let mut pcm_output = Vec::with_capacity(range_samples * block_align);
497
498 for frame_idx in first_frame..=last_frame {
499 let frame_pcm = self.decode_frame(frame_idx)?;
500 let frame_start_sample = frame_idx as u64 * bpf;
501 let frame_end_sample = frame_start_sample + self.info.frame_samples(frame_idx) as u64;
502
503 let overlap_start = start.max(frame_start_sample) - frame_start_sample;
505 let overlap_end = end.min(frame_end_sample) - frame_start_sample;
506
507 let byte_start = overlap_start as usize * block_align;
508 let byte_end = overlap_end as usize * block_align;
509
510 if byte_end <= frame_pcm.len() {
511 pcm_output.extend_from_slice(&frame_pcm[byte_start..byte_end]);
512 }
513 }
514
515 Ok(pcm_output)
516 }
517
518 pub fn seek(&mut self, sample: u64) -> ApeResult<SeekResult> {
522 if self.info.total_frames == 0 {
523 return Ok(SeekResult {
524 frame_index: 0,
525 skip_samples: 0,
526 actual_sample: 0,
527 });
528 }
529 let sample = sample.min(self.info.total_samples.saturating_sub(1));
530 let frame_index = (sample / self.info.blocks_per_frame as u64) as u32;
531 let frame_index = frame_index.min(self.info.total_frames - 1);
532 let frame_start = frame_index as u64 * self.info.blocks_per_frame as u64;
533 let skip_samples = (sample - frame_start) as u32;
534
535 Ok(SeekResult {
536 frame_index,
537 skip_samples,
538 actual_sample: sample,
539 })
540 }
541
542 pub fn decode_from(&mut self, sample: u64) -> ApeResult<Vec<u8>> {
545 let pos = self.seek(sample)?;
546 let frame_pcm = self.decode_frame(pos.frame_index)?;
547 let skip_bytes = pos.skip_samples as usize * self.info.block_align as usize;
548 Ok(frame_pcm[skip_bytes..].to_vec())
549 }
550
551 pub fn wav_header_data(&self) -> Option<&[u8]> {
554 if self.file_info.wav_header_data.is_empty() {
555 None
556 } else {
557 Some(&self.file_info.wav_header_data)
558 }
559 }
560
561 pub fn wav_terminating_bytes(&self) -> u32 {
563 self.file_info.terminating_data_bytes
564 }
565
566 pub fn read_tag(&mut self) -> ApeResult<Option<ApeTag>> {
569 tag::read_tag(&mut self.reader)
570 }
571
572 pub fn read_id3v2_tag(&mut self) -> ApeResult<Option<Id3v2Tag>> {
575 id3v2::read_id3v2(&mut self.reader)
576 }
577
578 pub fn stored_md5(&self) -> &[u8; 16] {
580 &self.file_info.descriptor.md5
581 }
582
583 pub fn verify_md5(&mut self) -> ApeResult<bool> {
590 use md5::{Digest, Md5};
591
592 let desc = &self.file_info.descriptor;
593
594 if desc.version < 3980 {
596 return Err(ApeError::UnsupportedVersion(desc.version));
597 }
598
599 if desc.md5 == [0u8; 16] {
601 return Ok(true); }
603
604 let junk = self.file_info.junk_header_bytes as u64;
605 let desc_bytes = desc.descriptor_bytes as u64;
606 let header_bytes = desc.header_bytes as u64;
607 let seek_table_bytes = desc.seek_table_bytes as u64;
608 let header_data_bytes = desc.header_data_bytes as u64;
609 let frame_data_bytes = self.file_info.ape_frame_data_bytes;
610 let term_bytes = desc.terminating_data_bytes as u64;
611
612 let mut hasher = Md5::new();
613
614 let header_data_pos = junk + desc_bytes + header_bytes + seek_table_bytes;
616 self.reader.seek(SeekFrom::Start(header_data_pos))?;
617 copy_to_hasher(&mut self.reader, &mut hasher, header_data_bytes)?;
618
619 copy_to_hasher(&mut self.reader, &mut hasher, frame_data_bytes + term_bytes)?;
622
623 let header_pos = junk + desc_bytes;
625 self.reader.seek(SeekFrom::Start(header_pos))?;
626 copy_to_hasher(&mut self.reader, &mut hasher, header_bytes)?;
627
628 copy_to_hasher(&mut self.reader, &mut hasher, seek_table_bytes)?;
631
632 let computed: [u8; 16] = hasher.finalize().into();
634 Ok(computed == desc.md5)
635 }
636
637 pub fn frames(&mut self) -> FrameIterator<'_, R> {
639 FrameIterator {
640 decoder: self,
641 current_frame: 0,
642 }
643 }
644
645 fn seek_remainder(&self, frame_idx: u32) -> u32 {
648 let seek_byte = self.file_info.seek_byte(frame_idx);
649 let seek_byte_0 = self.file_info.seek_byte(0);
650 ((seek_byte - seek_byte_0) % 4) as u32
651 }
652
653 fn read_frame_data(&mut self, frame_idx: u32) -> ApeResult<Vec<u8>> {
654 let seek_byte = self.file_info.seek_byte(frame_idx);
655 let seek_remainder = self.seek_remainder(frame_idx);
656 let frame_bytes = self.file_info.frame_byte_count(frame_idx);
657 if frame_bytes > 64 * 1024 * 1024 {
658 return Err(ApeError::InvalidFormat("frame data exceeds 64 MB"));
659 }
660 let read_bytes = (frame_bytes as u32 + seek_remainder + 4) as usize;
661
662 self.reader
663 .seek(SeekFrom::Start(seek_byte - seek_remainder as u64))?;
664 let mut frame_data = vec![0u8; read_bytes];
665 let bytes_read = self.reader.read(&mut frame_data)?;
666 if bytes_read < read_bytes.saturating_sub(4) {
667 return Err(ApeError::DecodingError("short read on frame data"));
668 }
669 frame_data.truncate(bytes_read);
670 Ok(frame_data)
671 }
672}
673
674pub struct FrameIterator<'a, R: Read + Seek> {
676 decoder: &'a mut ApeDecoder<R>,
677 current_frame: u32,
678}
679
680impl<'a, R: Read + Seek> Iterator for FrameIterator<'a, R> {
681 type Item = ApeResult<Vec<u8>>;
682
683 fn next(&mut self) -> Option<Self::Item> {
684 if self.current_frame >= self.decoder.info.total_frames {
685 return None;
686 }
687 let frame_idx = self.current_frame;
688 self.current_frame += 1;
689 Some(self.decoder.decode_frame(frame_idx))
690 }
691
692 fn size_hint(&self) -> (usize, Option<usize>) {
693 let remaining = (self.decoder.info.total_frames - self.current_frame) as usize;
694 (remaining, Some(remaining))
695 }
696}
697
698pub fn decode<R: Read + Seek>(reader: &mut R) -> ApeResult<Vec<u8>> {
700 let mut decoder = ApeDecoder::new_from_ref(reader)?;
704 decoder.decode_all()
705}
706
707impl<R: Read + Seek> ApeDecoder<R> {
708 fn new_from_ref<'a>(reader: &'a mut R) -> ApeResult<ApeDecoder<&'a mut R>> {
709 ApeDecoder::new(reader)
710 }
711}
712
713fn try_decode_frame_16(
718 frame_data: &[u8],
719 seek_remainder: u32,
720 frame_blocks: usize,
721 version: i32,
722 channels: u16,
723 bits: u16,
724 block_align: usize,
725 predictors: &mut [Predictor3950],
726 entropy_states: &mut [EntropyState],
727 range_coder: &mut RangeCoder,
728) -> ApeResult<Vec<u8>> {
729 let mut br = BitReader::from_frame_bytes(frame_data, seek_remainder * 8);
730
731 let mut stored_crc = br.decode_value_x_bits(32);
733 let mut special_codes: i32 = 0;
734 if version > 3820 {
735 if stored_crc & 0x80000000 != 0 {
736 special_codes = br.decode_value_x_bits(32) as i32;
737 }
738 stored_crc &= 0x7FFFFFFF;
739 }
740
741 for p in predictors.iter_mut() {
742 p.flush();
743 }
744 for s in entropy_states.iter_mut() {
745 s.flush();
746 }
747 range_coder.flush_bit_array(&mut br);
748
749 let mut last_x: i32 = 0;
750 let pcm_size = frame_blocks.checked_mul(block_align).ok_or(ApeError::InvalidFormat("frame too large"))?;
751 if pcm_size > 64 * 1024 * 1024 {
752 return Err(ApeError::InvalidFormat("frame PCM size exceeds 64 MB"));
753 }
754 let mut pcm_output = Vec::with_capacity(pcm_size);
755
756 let decode_result: ApeResult<()> = (|| {
757 if channels == 2 {
758 if (special_codes & SPECIAL_FRAME_LEFT_SILENCE) != 0
759 && (special_codes & SPECIAL_FRAME_RIGHT_SILENCE) != 0
760 {
761 for _ in 0..frame_blocks {
762 unprepare::unprepare(&[0, 0], channels, bits, &mut pcm_output)?;
763 }
764 } else if (special_codes & SPECIAL_FRAME_PSEUDO_STEREO) != 0 {
765 for _ in 0..frame_blocks {
766 let val = entropy_states[0].decode_value_range(range_coder, &mut br)?;
767 let x = predictors[0].decompress_value(val, 0);
768 unprepare::unprepare(&[x, 0], channels, bits, &mut pcm_output)?;
769 }
770 } else if version >= 3950 {
771 for _ in 0..frame_blocks {
772 let ny = entropy_states[1].decode_value_range(range_coder, &mut br)?;
773 let nx = entropy_states[0].decode_value_range(range_coder, &mut br)?;
774 let y = predictors[1].decompress_value(ny, last_x as i64);
775 let x = predictors[0].decompress_value(nx, y as i64);
776 last_x = x;
777 unprepare::unprepare(&[x, y], channels, bits, &mut pcm_output)?;
778 }
779 } else {
780 for _ in 0..frame_blocks {
781 let ex = entropy_states[0].decode_value_range(range_coder, &mut br)?;
782 let ey = entropy_states[1].decode_value_range(range_coder, &mut br)?;
783 let x = predictors[0].decompress_value(ex, 0);
784 let y = predictors[1].decompress_value(ey, 0);
785 unprepare::unprepare(&[x, y], channels, bits, &mut pcm_output)?;
786 }
787 }
788 } else if channels == 1 {
789 if (special_codes & SPECIAL_FRAME_MONO_SILENCE) != 0 {
790 for _ in 0..frame_blocks {
791 unprepare::unprepare(&[0], channels, bits, &mut pcm_output)?;
792 }
793 } else {
794 for _ in 0..frame_blocks {
795 let val = entropy_states[0].decode_value_range(range_coder, &mut br)?;
796 let decoded = predictors[0].decompress_value(val, 0);
797 unprepare::unprepare(&[decoded], channels, bits, &mut pcm_output)?;
798 }
799 }
800 } else {
801 let ch = channels as usize;
802 let mut values = vec![0i32; ch];
803 for _ in 0..frame_blocks {
804 for c in 0..ch {
805 let val = entropy_states[c].decode_value_range(range_coder, &mut br)?;
806 values[c] = predictors[c].decompress_value(val, 0);
807 }
808 unprepare::unprepare(&values, channels, bits, &mut pcm_output)?;
809 }
810 }
811 Ok(())
812 })();
813
814 decode_result?;
815
816 range_coder.finalize(&mut br);
818 let computed_crc = ape_crc(&pcm_output);
819 if computed_crc != stored_crc {
820 return Err(ApeError::InvalidChecksum);
821 }
822
823 apply_post_processing(&mut pcm_output, bits, channels);
825
826 Ok(pcm_output)
827}
828
829fn try_decode_frame_32(
830 frame_data: &[u8],
831 seek_remainder: u32,
832 frame_blocks: usize,
833 version: i32,
834 channels: u16,
835 bits: u16,
836 block_align: usize,
837 predictors: &mut [Predictor3950_32],
838 entropy_states: &mut [EntropyState],
839 range_coder: &mut RangeCoder,
840) -> ApeResult<Vec<u8>> {
841 let mut br = BitReader::from_frame_bytes(frame_data, seek_remainder * 8);
842
843 let mut stored_crc = br.decode_value_x_bits(32);
844 let mut special_codes: i32 = 0;
845 if version > 3820 {
846 if stored_crc & 0x80000000 != 0 {
847 special_codes = br.decode_value_x_bits(32) as i32;
848 }
849 stored_crc &= 0x7FFFFFFF;
850 }
851
852 for p in predictors.iter_mut() {
853 p.flush();
854 }
855 for s in entropy_states.iter_mut() {
856 s.flush();
857 }
858 range_coder.flush_bit_array(&mut br);
859
860 let mut last_x: i64 = 0;
861 let pcm_size = frame_blocks.checked_mul(block_align).ok_or(ApeError::InvalidFormat("frame too large"))?;
862 if pcm_size > 64 * 1024 * 1024 {
863 return Err(ApeError::InvalidFormat("frame PCM size exceeds 64 MB"));
864 }
865 let mut pcm_output = Vec::with_capacity(pcm_size);
866
867 if channels == 2 {
868 if (special_codes & SPECIAL_FRAME_LEFT_SILENCE) != 0
869 && (special_codes & SPECIAL_FRAME_RIGHT_SILENCE) != 0
870 {
871 for _ in 0..frame_blocks {
872 unprepare::unprepare(&[0, 0], channels, bits, &mut pcm_output)?;
873 }
874 } else if (special_codes & SPECIAL_FRAME_PSEUDO_STEREO) != 0 {
875 for _ in 0..frame_blocks {
876 let val = entropy_states[0].decode_value_range(range_coder, &mut br)?;
877 let x = predictors[0].decompress_value(val, 0);
878 unprepare::unprepare(&[x as i32, 0], channels, bits, &mut pcm_output)?;
879 }
880 } else {
881 for _ in 0..frame_blocks {
882 let ny = entropy_states[1].decode_value_range(range_coder, &mut br)?;
883 let nx = entropy_states[0].decode_value_range(range_coder, &mut br)?;
884 let y = predictors[1].decompress_value(ny, last_x);
885 let x = predictors[0].decompress_value(nx, y as i64);
886 last_x = x as i64;
887 unprepare::unprepare(&[x as i32, y as i32], channels, bits, &mut pcm_output)?;
888 }
889 }
890 } else if channels == 1 {
891 if (special_codes & SPECIAL_FRAME_MONO_SILENCE) != 0 {
892 for _ in 0..frame_blocks {
893 unprepare::unprepare(&[0], channels, bits, &mut pcm_output)?;
894 }
895 } else {
896 for _ in 0..frame_blocks {
897 let val = entropy_states[0].decode_value_range(range_coder, &mut br)?;
898 let decoded = predictors[0].decompress_value(val, 0);
899 unprepare::unprepare(&[decoded as i32], channels, bits, &mut pcm_output)?;
900 }
901 }
902 }
903
904 range_coder.finalize(&mut br);
905 let computed_crc = ape_crc(&pcm_output);
906 if computed_crc != stored_crc {
907 return Err(ApeError::InvalidChecksum);
908 }
909
910 apply_post_processing(&mut pcm_output, bits, channels);
912
913 Ok(pcm_output)
914}
915
916fn copy_to_hasher<R: Read>(reader: &mut R, hasher: &mut md5::Md5, mut n: u64) -> ApeResult<()> {
924 use md5::Digest;
925 let mut buf = [0u8; 16384];
926 while n > 0 {
927 let to_read = (n as usize).min(buf.len());
928 reader.read_exact(&mut buf[..to_read])?;
929 hasher.update(&buf[..to_read]);
930 n -= to_read as u64;
931 }
932 Ok(())
933}
934
935fn apply_post_processing(pcm: &mut [u8], bits: u16, _channels: u16) {
938 let _ = (pcm, bits);
954}
955
956#[allow(dead_code)]
961fn float_transform_sample(sample_in: u32) -> u32 {
962 let mut out: u32 = 0;
963 out |= sample_in & 0xC3FF_FFFF;
964 out |= !(sample_in & 0x3C00_0000) ^ 0xC3FF_FFFF;
965 if out & 0x8000_0000 != 0 {
966 out = !out | 0x8000_0000;
967 }
968 out
969}
970
971#[allow(dead_code)]
973fn byte_swap_samples(pcm: &mut [u8], bytes_per_sample: usize) {
974 match bytes_per_sample {
975 2 => {
976 for chunk in pcm.chunks_exact_mut(2) {
977 chunk.swap(0, 1);
978 }
979 }
980 3 => {
981 for chunk in pcm.chunks_exact_mut(3) {
982 chunk.swap(0, 2);
983 }
984 }
985 4 => {
986 for chunk in pcm.chunks_exact_mut(4) {
987 chunk.swap(0, 3);
988 chunk.swap(1, 2);
989 }
990 }
991 _ => {}
992 }
993}
994
995#[cfg(test)]
996mod tests {
997 use super::*;
998 use std::fs::File;
999 use std::io::BufReader;
1000 use std::path::PathBuf;
1001
1002 fn test_fixture_path(name: &str) -> PathBuf {
1003 PathBuf::from(env!("CARGO_MANIFEST_DIR"))
1004 .join("tests/fixtures")
1005 .join(name)
1006 }
1007
1008 fn load_reference_pcm(name: &str) -> Vec<u8> {
1009 let path = test_fixture_path(&format!("ref/{}", name));
1010 let data = std::fs::read(&path)
1011 .unwrap_or_else(|e| panic!("Failed to read {}: {}", path.display(), e));
1012 data[44..].to_vec()
1013 }
1014
1015 fn open_ape(name: &str) -> BufReader<File> {
1016 let path = test_fixture_path(&format!("ape/{}", name));
1017 let file = File::open(&path)
1018 .unwrap_or_else(|e| panic!("Failed to open {}: {}", path.display(), e));
1019 BufReader::new(file)
1020 }
1021
1022 fn decode_ape_file(name: &str) -> ApeResult<Vec<u8>> {
1023 let mut reader = open_ape(name);
1024 decode(&mut reader)
1025 }
1026
1027 #[test]
1030 fn test_decode_sine_16s_c1000() {
1031 let decoded = decode_ape_file("sine_16s_c1000.ape").unwrap();
1032 let expected = load_reference_pcm("sine_16s_c1000.wav");
1033 assert_eq!(decoded.len(), expected.len());
1034 assert_eq!(decoded, expected);
1035 }
1036
1037 #[test]
1038 fn test_decode_sine_16s_c2000() {
1039 let decoded = decode_ape_file("sine_16s_c2000.ape").unwrap();
1040 let expected = load_reference_pcm("sine_16s_c2000.wav");
1041 assert_eq!(decoded, expected);
1042 }
1043
1044 #[test]
1045 fn test_decode_silence_16s() {
1046 let decoded = decode_ape_file("silence_16s_c2000.ape").unwrap();
1047 let expected = load_reference_pcm("silence_16s_c2000.wav");
1048 assert_eq!(decoded, expected);
1049 }
1050
1051 #[test]
1052 fn test_decode_sine_16m() {
1053 let decoded = decode_ape_file("sine_16m_c2000.ape").unwrap();
1054 let expected = load_reference_pcm("sine_16m_c2000.wav");
1055 assert_eq!(decoded, expected);
1056 }
1057
1058 #[test]
1059 fn test_decode_short_16s() {
1060 let decoded = decode_ape_file("short_16s_c2000.ape").unwrap();
1061 let expected = load_reference_pcm("short_16s_c2000.wav");
1062 assert_eq!(decoded, expected);
1063 }
1064
1065 #[test]
1066 fn test_decode_all_compression_levels() {
1067 for level in &["c1000", "c2000", "c3000", "c4000", "c5000"] {
1068 let name = format!("sine_16s_{}.ape", level);
1069 let ref_name = format!("sine_16s_{}.wav", level);
1070 let decoded = decode_ape_file(&name).unwrap_or_else(|e| panic!("{}: {:?}", name, e));
1071 let expected = load_reference_pcm(&ref_name);
1072 assert_eq!(decoded, expected, "Mismatch for {}", name);
1073 }
1074 }
1075
1076 #[test]
1077 fn test_decode_8bit() {
1078 let decoded = decode_ape_file("sine_8s_c2000.ape").unwrap();
1079 let expected = load_reference_pcm("sine_8s_c2000.wav");
1080 assert_eq!(decoded, expected);
1081 }
1082
1083 #[test]
1084 fn test_decode_24bit() {
1085 let decoded = decode_ape_file("sine_24s_c2000.ape").unwrap();
1086 let expected = load_reference_pcm("sine_24s_c2000.wav");
1087 assert_eq!(decoded, expected);
1088 }
1089
1090 #[test]
1091 fn test_decode_32bit() {
1092 let decoded = decode_ape_file("sine_32s_c2000.ape").unwrap();
1093 let expected = load_reference_pcm("sine_32s_c2000.wav");
1094 assert_eq!(decoded, expected);
1095 }
1096
1097 #[test]
1098 fn test_decode_multiframe() {
1099 let decoded = decode_ape_file("multiframe_16s_c2000.ape").unwrap();
1100 let expected = load_reference_pcm("multiframe_16s_c2000.wav");
1101 assert_eq!(decoded, expected);
1102 }
1103
1104 #[test]
1105 fn test_decode_identical_channels() {
1106 let decoded = decode_ape_file("identical_16s_c2000.ape").unwrap();
1107 let expected = load_reference_pcm("identical_16s_c2000.wav");
1108 assert_eq!(decoded, expected);
1109 }
1110
1111 #[test]
1112 fn test_decode_all_fixtures() {
1113 let fixtures = [
1114 "dc_offset_16s_c2000.ape",
1115 "identical_16s_c2000.ape",
1116 "impulse_16s_c2000.ape",
1117 "left_only_16s_c2000.ape",
1118 "multiframe_16s_c2000.ape",
1119 "noise_16s_c2000.ape",
1120 "short_16s_c2000.ape",
1121 "silence_16s_c2000.ape",
1122 "sine_16m_c2000.ape",
1123 "sine_16s_c1000.ape",
1124 "sine_16s_c2000.ape",
1125 "sine_16s_c3000.ape",
1126 "sine_16s_c4000.ape",
1127 "sine_16s_c5000.ape",
1128 "sine_24s_c2000.ape",
1129 "sine_32s_c2000.ape",
1130 "sine_8s_c2000.ape",
1131 ];
1132
1133 for fixture in &fixtures {
1134 let ref_name = fixture.replace(".ape", ".wav");
1135 let decoded = decode_ape_file(fixture)
1136 .unwrap_or_else(|e| panic!("Failed to decode {}: {:?}", fixture, e));
1137 let expected = load_reference_pcm(&ref_name);
1138 assert_eq!(
1139 decoded.len(),
1140 expected.len(),
1141 "Length mismatch for {}",
1142 fixture
1143 );
1144 assert_eq!(decoded, expected, "Data mismatch for {}", fixture);
1145 }
1146 }
1147
1148 #[test]
1151 fn test_ape_decoder_info() {
1152 let reader = open_ape("sine_16s_c2000.ape");
1153 let decoder = ApeDecoder::new(reader).unwrap();
1154 let info = decoder.info();
1155 assert_eq!(info.sample_rate, 44100);
1156 assert_eq!(info.channels, 2);
1157 assert_eq!(info.bits_per_sample, 16);
1158 assert_eq!(info.total_samples, 44100);
1159 assert_eq!(info.compression_level, 2000);
1160 assert_eq!(info.block_align, 4);
1161 }
1162
1163 #[test]
1164 fn test_decode_frame_by_frame() {
1165 let reader = open_ape("sine_16s_c2000.ape");
1166 let mut decoder = ApeDecoder::new(reader).unwrap();
1167 let expected = load_reference_pcm("sine_16s_c2000.wav");
1168
1169 let mut all_pcm = Vec::new();
1170 for frame_idx in 0..decoder.total_frames() {
1171 let frame_pcm = decoder.decode_frame(frame_idx).unwrap();
1172 all_pcm.extend_from_slice(&frame_pcm);
1173 }
1174
1175 assert_eq!(all_pcm, expected);
1176 }
1177
1178 #[test]
1179 fn test_decode_multiframe_frame_by_frame() {
1180 let reader = open_ape("multiframe_16s_c2000.ape");
1181 let mut decoder = ApeDecoder::new(reader).unwrap();
1182 let expected = load_reference_pcm("multiframe_16s_c2000.wav");
1183
1184 assert!(decoder.total_frames() > 1, "Expected multiple frames");
1185
1186 let mut all_pcm = Vec::new();
1187 for frame_idx in 0..decoder.total_frames() {
1188 let frame_pcm = decoder.decode_frame(frame_idx).unwrap();
1189 assert!(!frame_pcm.is_empty());
1190 all_pcm.extend_from_slice(&frame_pcm);
1191 }
1192
1193 assert_eq!(all_pcm, expected);
1194 }
1195
1196 #[test]
1197 fn test_frames_iterator() {
1198 let reader = open_ape("sine_16s_c2000.ape");
1199 let mut decoder = ApeDecoder::new(reader).unwrap();
1200 let expected = load_reference_pcm("sine_16s_c2000.wav");
1201
1202 let all_pcm: Vec<u8> = decoder
1203 .frames()
1204 .collect::<Result<Vec<_>, _>>()
1205 .unwrap()
1206 .concat();
1207
1208 assert_eq!(all_pcm, expected);
1209 }
1210
1211 #[test]
1212 fn test_seek_sample_level() {
1213 let reader = open_ape("multiframe_16s_c2000.ape");
1214 let mut decoder = ApeDecoder::new(reader).unwrap();
1215 let bpf = decoder.info().blocks_per_frame as u64;
1216
1217 let r = decoder.seek(0).unwrap();
1219 assert_eq!(r.frame_index, 0);
1220 assert_eq!(r.skip_samples, 0);
1221 assert_eq!(r.actual_sample, 0);
1222
1223 let r = decoder.seek(100).unwrap();
1225 assert_eq!(r.frame_index, 0);
1226 assert_eq!(r.skip_samples, 100);
1227 assert_eq!(r.actual_sample, 100);
1228
1229 let r = decoder.seek(bpf).unwrap();
1231 assert_eq!(r.frame_index, 1);
1232 assert_eq!(r.skip_samples, 0);
1233 assert_eq!(r.actual_sample, bpf);
1234
1235 let r = decoder.seek(bpf + 100).unwrap();
1237 assert_eq!(r.frame_index, 1);
1238 assert_eq!(r.skip_samples, 100);
1239 assert_eq!(r.actual_sample, bpf + 100);
1240
1241 let r = decoder.seek(u64::MAX).unwrap();
1243 assert_eq!(r.actual_sample, decoder.info().total_samples - 1);
1244 }
1245
1246 #[test]
1247 fn test_decode_from_mid_frame() {
1248 let reader = open_ape("sine_16s_c2000.ape");
1249 let mut decoder = ApeDecoder::new(reader).unwrap();
1250 let block_align = decoder.info().block_align as usize;
1251
1252 let full_frame = decoder.decode_frame(0).unwrap();
1254
1255 let partial = decoder.decode_from(100).unwrap();
1257
1258 let skip = 100 * block_align;
1260 assert_eq!(partial, &full_frame[skip..]);
1261 }
1262
1263 #[test]
1264 fn test_expanded_metadata() {
1265 let reader = open_ape("sine_16s_c2000.ape");
1266 let decoder = ApeDecoder::new(reader).unwrap();
1267 let info = decoder.info();
1268
1269 assert_eq!(info.bytes_per_sample, 2);
1270 assert_eq!(info.source_format, SourceFormat::Wav);
1271 assert!(!info.is_big_endian);
1272 assert!(!info.is_floating_point);
1273 assert!(!info.is_signed_8bit);
1274 assert!(info.average_bitrate_kbps > 0);
1275 assert!(info.decompressed_bitrate_kbps > 0);
1276 assert!(info.file_size_bytes > 0);
1277 assert_eq!(info.format_flags & 0x0200, 0); }
1279
1280 #[test]
1281 fn test_wav_header_data() {
1282 let reader = open_ape("sine_16s_c2000.ape");
1283 let decoder = ApeDecoder::new(reader).unwrap();
1284
1285 let header = decoder.wav_header_data();
1286 if let Some(data) = header {
1288 assert!(data.len() >= 12);
1289 assert_eq!(&data[0..4], b"RIFF");
1291 }
1292 }
1293
1294 #[test]
1295 fn test_read_tag() {
1296 let reader = open_ape("sine_16s_c2000.ape");
1297 let mut decoder = ApeDecoder::new(reader).unwrap();
1298 let _tag = decoder.read_tag();
1300 }
1301
1302 #[test]
1303 fn test_decode_frame_out_of_bounds() {
1304 let reader = open_ape("sine_16s_c2000.ape");
1305 let mut decoder = ApeDecoder::new(reader).unwrap();
1306 let result = decoder.decode_frame(999);
1307 assert!(result.is_err());
1308 }
1309
1310 #[test]
1313 fn test_decode_with_progress() {
1314 let reader = open_ape("sine_16s_c2000.ape");
1315 let mut decoder = ApeDecoder::new(reader).unwrap();
1316 let expected = load_reference_pcm("sine_16s_c2000.wav");
1317
1318 let mut last_progress = 0.0f64;
1319 let decoded = decoder
1320 .decode_all_with(|p| {
1321 assert!(p >= last_progress, "progress must be monotonic");
1322 last_progress = p;
1323 true })
1325 .unwrap();
1326
1327 assert!((last_progress - 1.0).abs() < 0.01);
1328 assert_eq!(decoded, expected);
1329 }
1330
1331 #[test]
1332 fn test_decode_with_cancel() {
1333 let reader = open_ape("multiframe_16s_c2000.ape");
1334 let mut decoder = ApeDecoder::new(reader).unwrap();
1335
1336 let result = decoder.decode_all_with(|p| {
1337 p < 0.5 });
1339
1340 assert!(result.is_err());
1341 }
1342
1343 #[test]
1346 fn test_decode_range_full_file() {
1347 let reader = open_ape("sine_16s_c2000.ape");
1348 let mut decoder = ApeDecoder::new(reader).unwrap();
1349 let total = decoder.info().total_samples;
1350 let expected = load_reference_pcm("sine_16s_c2000.wav");
1351
1352 let decoded = decoder.decode_range(0, total).unwrap();
1353 assert_eq!(decoded, expected);
1354 }
1355
1356 #[test]
1357 fn test_decode_range_subset() {
1358 let reader = open_ape("sine_16s_c2000.ape");
1359 let mut decoder = ApeDecoder::new(reader).unwrap();
1360 let block_align = decoder.info().block_align as usize;
1361 let expected = load_reference_pcm("sine_16s_c2000.wav");
1362
1363 let decoded = decoder.decode_range(100, 200).unwrap();
1365 assert_eq!(decoded.len(), 100 * block_align);
1366 assert_eq!(decoded, &expected[100 * block_align..200 * block_align]);
1367 }
1368
1369 #[test]
1370 fn test_decode_range_empty() {
1371 let reader = open_ape("sine_16s_c2000.ape");
1372 let mut decoder = ApeDecoder::new(reader).unwrap();
1373
1374 let decoded = decoder.decode_range(100, 100).unwrap();
1375 assert!(decoded.is_empty());
1376
1377 let decoded = decoder.decode_range(200, 100).unwrap();
1378 assert!(decoded.is_empty());
1379 }
1380
1381 #[test]
1384 fn test_decode_parallel_matches_sequential() {
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 parallel = decoder.decode_all_parallel(4).unwrap();
1390
1391 assert_eq!(parallel, expected);
1392 }
1393
1394 #[test]
1395 fn test_decode_parallel_multiframe() {
1396 let expected = load_reference_pcm("multiframe_16s_c2000.wav");
1397
1398 let reader = open_ape("multiframe_16s_c2000.ape");
1399 let mut decoder = ApeDecoder::new(reader).unwrap();
1400 let parallel = decoder.decode_all_parallel(2).unwrap();
1401
1402 assert_eq!(parallel, expected);
1403 }
1404
1405 #[test]
1406 fn test_decode_parallel_single_thread() {
1407 let expected = load_reference_pcm("sine_16s_c2000.wav");
1408
1409 let reader = open_ape("sine_16s_c2000.ape");
1410 let mut decoder = ApeDecoder::new(reader).unwrap();
1411 let decoded = decoder.decode_all_parallel(1).unwrap();
1412
1413 assert_eq!(decoded, expected);
1414 }
1415
1416 #[test]
1417 fn test_decode_parallel_all_fixtures() {
1418 let fixtures = [
1419 "dc_offset_16s_c2000.ape",
1420 "identical_16s_c2000.ape",
1421 "impulse_16s_c2000.ape",
1422 "left_only_16s_c2000.ape",
1423 "multiframe_16s_c2000.ape",
1424 "noise_16s_c2000.ape",
1425 "short_16s_c2000.ape",
1426 "silence_16s_c2000.ape",
1427 "sine_16m_c2000.ape",
1428 "sine_16s_c1000.ape",
1429 "sine_16s_c2000.ape",
1430 "sine_16s_c3000.ape",
1431 "sine_16s_c4000.ape",
1432 "sine_16s_c5000.ape",
1433 "sine_24s_c2000.ape",
1434 "sine_32s_c2000.ape",
1435 "sine_8s_c2000.ape",
1436 ];
1437
1438 for fixture in &fixtures {
1439 let ref_name = fixture.replace(".ape", ".wav");
1440 let reader = open_ape(fixture);
1441 let mut decoder = ApeDecoder::new(reader).unwrap();
1442 let parallel = decoder
1443 .decode_all_parallel(2)
1444 .unwrap_or_else(|e| panic!("Parallel decode failed for {}: {:?}", fixture, e));
1445 let expected = load_reference_pcm(&ref_name);
1446 assert_eq!(parallel, expected, "Parallel mismatch for {}", fixture);
1447 }
1448 }
1449
1450 #[test]
1453 fn test_decode_truncated_file() {
1454 let data = vec![0u8; 10];
1456 let mut cursor = std::io::Cursor::new(data);
1457 let result = decode(&mut cursor);
1458 assert!(result.is_err());
1459 }
1460
1461 #[test]
1462 fn test_decode_wrong_magic() {
1463 let mut data = vec![0u8; 200];
1465 data[0..4].copy_from_slice(b"NOPE");
1466 let mut cursor = std::io::Cursor::new(data);
1467 let result = decode(&mut cursor);
1468 assert!(result.is_err());
1469 }
1470
1471 #[test]
1472 fn test_decode_empty_file() {
1473 let data = vec![];
1474 let mut cursor = std::io::Cursor::new(data);
1475 let result = decode(&mut cursor);
1476 assert!(result.is_err());
1477 }
1478
1479 #[test]
1480 fn test_decoder_new_truncated() {
1481 let data = vec![0u8; 50]; let cursor = std::io::Cursor::new(data);
1483 let result = ApeDecoder::new(cursor);
1484 assert!(result.is_err());
1485 }
1486
1487 #[test]
1490 fn test_float_transform_roundtrip() {
1491 let original: u32 = 0x3F800000; let transformed = super::float_transform_sample(original);
1494 let restored = super::float_transform_sample(transformed);
1495 assert_eq!(restored, original);
1496 }
1497
1498 #[test]
1499 fn test_float_transform_zero() {
1500 let transformed = super::float_transform_sample(0);
1501 let restored = super::float_transform_sample(transformed);
1502 assert_eq!(restored, 0);
1503 }
1504
1505 #[test]
1506 fn test_byte_swap_16bit() {
1507 let mut data = vec![0x01, 0x02, 0x03, 0x04];
1508 super::byte_swap_samples(&mut data, 2);
1509 assert_eq!(data, vec![0x02, 0x01, 0x04, 0x03]);
1510 }
1511
1512 #[test]
1513 fn test_byte_swap_24bit() {
1514 let mut data = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06];
1515 super::byte_swap_samples(&mut data, 3);
1516 assert_eq!(data, vec![0x03, 0x02, 0x01, 0x06, 0x05, 0x04]);
1517 }
1518
1519 #[test]
1520 fn test_byte_swap_32bit() {
1521 let mut data = vec![0x01, 0x02, 0x03, 0x04];
1522 super::byte_swap_samples(&mut data, 4);
1523 assert_eq!(data, vec![0x04, 0x03, 0x02, 0x01]);
1524 }
1525
1526 #[test]
1529 fn test_verify_md5_all_fixtures() {
1530 let fixtures = [
1531 "dc_offset_16s_c2000.ape",
1532 "identical_16s_c2000.ape",
1533 "impulse_16s_c2000.ape",
1534 "left_only_16s_c2000.ape",
1535 "multiframe_16s_c2000.ape",
1536 "noise_16s_c2000.ape",
1537 "short_16s_c2000.ape",
1538 "silence_16s_c2000.ape",
1539 "sine_16m_c2000.ape",
1540 "sine_16s_c1000.ape",
1541 "sine_16s_c2000.ape",
1542 "sine_16s_c3000.ape",
1543 "sine_16s_c4000.ape",
1544 "sine_16s_c5000.ape",
1545 "sine_24s_c2000.ape",
1546 "sine_32s_c2000.ape",
1547 "sine_8s_c2000.ape",
1548 ];
1549
1550 for fixture in &fixtures {
1551 let reader = open_ape(fixture);
1552 let mut decoder = ApeDecoder::new(reader).unwrap();
1553 let result = decoder
1554 .verify_md5()
1555 .unwrap_or_else(|e| panic!("MD5 verify failed for {}: {:?}", fixture, e));
1556 assert!(result, "MD5 mismatch for {}", fixture);
1557 }
1558 }
1559
1560 #[test]
1561 fn test_stored_md5_nonzero() {
1562 let reader = open_ape("sine_16s_c2000.ape");
1563 let decoder = ApeDecoder::new(reader).unwrap();
1564 let md5 = decoder.stored_md5();
1565 assert_ne!(md5, &[0u8; 16], "MD5 should not be all zeros");
1567 }
1568
1569 #[test]
1572 fn test_generate_wav_header() {
1573 let reader = open_ape("sine_16s_c2000.ape");
1574 let decoder = ApeDecoder::new(reader).unwrap();
1575 let header = decoder.info().generate_wav_header();
1576
1577 assert_eq!(header.len(), 44);
1579
1580 assert_eq!(&header[0..4], b"RIFF");
1582 assert_eq!(&header[8..12], b"WAVE");
1583 assert_eq!(&header[12..16], b"fmt ");
1584 assert_eq!(&header[36..40], b"data");
1585
1586 let channels = u16::from_le_bytes([header[22], header[23]]);
1588 let sample_rate = u32::from_le_bytes([header[24], header[25], header[26], header[27]]);
1589 let bits = u16::from_le_bytes([header[34], header[35]]);
1590 assert_eq!(channels, 2);
1591 assert_eq!(sample_rate, 44100);
1592 assert_eq!(bits, 16);
1593
1594 let data_size = u32::from_le_bytes([header[40], header[41], header[42], header[43]]);
1596 let expected = decoder.info().total_samples as u32 * decoder.info().block_align as u32;
1597 assert_eq!(data_size, expected);
1598 }
1599
1600 #[test]
1601 fn test_generate_wav_header_matches_stored() {
1602 let reader = open_ape("sine_16s_c2000.ape");
1603 let decoder = ApeDecoder::new(reader).unwrap();
1604
1605 let generated = decoder.info().generate_wav_header();
1606 if let Some(stored) = decoder.wav_header_data() {
1607 if stored.len() == 44 {
1609 assert_eq!(&generated[22..24], &stored[22..24]); assert_eq!(&generated[24..28], &stored[24..28]); assert_eq!(&generated[34..36], &stored[34..36]); }
1614 }
1615 }
1616}