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
751 .checked_mul(block_align)
752 .ok_or(ApeError::InvalidFormat("frame too large"))?;
753 if pcm_size > 64 * 1024 * 1024 {
754 return Err(ApeError::InvalidFormat("frame PCM size exceeds 64 MB"));
755 }
756 let mut pcm_output = Vec::with_capacity(pcm_size);
757
758 let decode_result: ApeResult<()> = (|| {
759 if channels == 2 {
760 if (special_codes & SPECIAL_FRAME_LEFT_SILENCE) != 0
761 && (special_codes & SPECIAL_FRAME_RIGHT_SILENCE) != 0
762 {
763 for _ in 0..frame_blocks {
764 unprepare::unprepare(&[0, 0], channels, bits, &mut pcm_output)?;
765 }
766 } else if (special_codes & SPECIAL_FRAME_PSEUDO_STEREO) != 0 {
767 for _ in 0..frame_blocks {
768 let val = entropy_states[0].decode_value_range(range_coder, &mut br)?;
769 let x = predictors[0].decompress_value(val, 0);
770 unprepare::unprepare(&[x, 0], channels, bits, &mut pcm_output)?;
771 }
772 } else if version >= 3950 {
773 for _ in 0..frame_blocks {
774 let ny = entropy_states[1].decode_value_range(range_coder, &mut br)?;
775 let nx = entropy_states[0].decode_value_range(range_coder, &mut br)?;
776 let y = predictors[1].decompress_value(ny, last_x as i64);
777 let x = predictors[0].decompress_value(nx, y as i64);
778 last_x = x;
779 unprepare::unprepare(&[x, y], channels, bits, &mut pcm_output)?;
780 }
781 } else {
782 for _ in 0..frame_blocks {
783 let ex = entropy_states[0].decode_value_range(range_coder, &mut br)?;
784 let ey = entropy_states[1].decode_value_range(range_coder, &mut br)?;
785 let x = predictors[0].decompress_value(ex, 0);
786 let y = predictors[1].decompress_value(ey, 0);
787 unprepare::unprepare(&[x, y], channels, bits, &mut pcm_output)?;
788 }
789 }
790 } else if channels == 1 {
791 if (special_codes & SPECIAL_FRAME_MONO_SILENCE) != 0 {
792 for _ in 0..frame_blocks {
793 unprepare::unprepare(&[0], channels, bits, &mut pcm_output)?;
794 }
795 } else {
796 for _ in 0..frame_blocks {
797 let val = entropy_states[0].decode_value_range(range_coder, &mut br)?;
798 let decoded = predictors[0].decompress_value(val, 0);
799 unprepare::unprepare(&[decoded], channels, bits, &mut pcm_output)?;
800 }
801 }
802 } else {
803 let ch = channels as usize;
804 let mut values = vec![0i32; ch];
805 for _ in 0..frame_blocks {
806 for c in 0..ch {
807 let val = entropy_states[c].decode_value_range(range_coder, &mut br)?;
808 values[c] = predictors[c].decompress_value(val, 0);
809 }
810 unprepare::unprepare(&values, channels, bits, &mut pcm_output)?;
811 }
812 }
813 Ok(())
814 })();
815
816 decode_result?;
817
818 range_coder.finalize(&mut br);
820 let computed_crc = ape_crc(&pcm_output);
821 if computed_crc != stored_crc {
822 return Err(ApeError::InvalidChecksum);
823 }
824
825 apply_post_processing(&mut pcm_output, bits, channels);
827
828 Ok(pcm_output)
829}
830
831fn try_decode_frame_32(
832 frame_data: &[u8],
833 seek_remainder: u32,
834 frame_blocks: usize,
835 version: i32,
836 channels: u16,
837 bits: u16,
838 block_align: usize,
839 predictors: &mut [Predictor3950_32],
840 entropy_states: &mut [EntropyState],
841 range_coder: &mut RangeCoder,
842) -> ApeResult<Vec<u8>> {
843 let mut br = BitReader::from_frame_bytes(frame_data, seek_remainder * 8);
844
845 let mut stored_crc = br.decode_value_x_bits(32);
846 let mut special_codes: i32 = 0;
847 if version > 3820 {
848 if stored_crc & 0x80000000 != 0 {
849 special_codes = br.decode_value_x_bits(32) as i32;
850 }
851 stored_crc &= 0x7FFFFFFF;
852 }
853
854 for p in predictors.iter_mut() {
855 p.flush();
856 }
857 for s in entropy_states.iter_mut() {
858 s.flush();
859 }
860 range_coder.flush_bit_array(&mut br);
861
862 let mut last_x: i64 = 0;
863 let pcm_size = frame_blocks
864 .checked_mul(block_align)
865 .ok_or(ApeError::InvalidFormat("frame too large"))?;
866 if pcm_size > 64 * 1024 * 1024 {
867 return Err(ApeError::InvalidFormat("frame PCM size exceeds 64 MB"));
868 }
869 let mut pcm_output = Vec::with_capacity(pcm_size);
870
871 if channels == 2 {
872 if (special_codes & SPECIAL_FRAME_LEFT_SILENCE) != 0
873 && (special_codes & SPECIAL_FRAME_RIGHT_SILENCE) != 0
874 {
875 for _ in 0..frame_blocks {
876 unprepare::unprepare(&[0, 0], channels, bits, &mut pcm_output)?;
877 }
878 } else if (special_codes & SPECIAL_FRAME_PSEUDO_STEREO) != 0 {
879 for _ in 0..frame_blocks {
880 let val = entropy_states[0].decode_value_range(range_coder, &mut br)?;
881 let x = predictors[0].decompress_value(val, 0);
882 unprepare::unprepare(&[x as i32, 0], channels, bits, &mut pcm_output)?;
883 }
884 } else {
885 for _ in 0..frame_blocks {
886 let ny = entropy_states[1].decode_value_range(range_coder, &mut br)?;
887 let nx = entropy_states[0].decode_value_range(range_coder, &mut br)?;
888 let y = predictors[1].decompress_value(ny, last_x);
889 let x = predictors[0].decompress_value(nx, y as i64);
890 last_x = x as i64;
891 unprepare::unprepare(&[x as i32, y as i32], channels, bits, &mut pcm_output)?;
892 }
893 }
894 } else if channels == 1 {
895 if (special_codes & SPECIAL_FRAME_MONO_SILENCE) != 0 {
896 for _ in 0..frame_blocks {
897 unprepare::unprepare(&[0], channels, bits, &mut pcm_output)?;
898 }
899 } else {
900 for _ in 0..frame_blocks {
901 let val = entropy_states[0].decode_value_range(range_coder, &mut br)?;
902 let decoded = predictors[0].decompress_value(val, 0);
903 unprepare::unprepare(&[decoded as i32], channels, bits, &mut pcm_output)?;
904 }
905 }
906 }
907
908 range_coder.finalize(&mut br);
909 let computed_crc = ape_crc(&pcm_output);
910 if computed_crc != stored_crc {
911 return Err(ApeError::InvalidChecksum);
912 }
913
914 apply_post_processing(&mut pcm_output, bits, channels);
916
917 Ok(pcm_output)
918}
919
920fn copy_to_hasher<R: Read>(reader: &mut R, hasher: &mut md5::Md5, mut n: u64) -> ApeResult<()> {
928 use md5::Digest;
929 let mut buf = [0u8; 16384];
930 while n > 0 {
931 let to_read = (n as usize).min(buf.len());
932 reader.read_exact(&mut buf[..to_read])?;
933 hasher.update(&buf[..to_read]);
934 n -= to_read as u64;
935 }
936 Ok(())
937}
938
939fn apply_post_processing(pcm: &mut [u8], bits: u16, _channels: u16) {
942 let _ = (pcm, bits);
958}
959
960#[allow(dead_code)]
965fn float_transform_sample(sample_in: u32) -> u32 {
966 let mut out: u32 = 0;
967 out |= sample_in & 0xC3FF_FFFF;
968 out |= !(sample_in & 0x3C00_0000) ^ 0xC3FF_FFFF;
969 if out & 0x8000_0000 != 0 {
970 out = !out | 0x8000_0000;
971 }
972 out
973}
974
975#[allow(dead_code)]
977fn byte_swap_samples(pcm: &mut [u8], bytes_per_sample: usize) {
978 match bytes_per_sample {
979 2 => {
980 for chunk in pcm.chunks_exact_mut(2) {
981 chunk.swap(0, 1);
982 }
983 }
984 3 => {
985 for chunk in pcm.chunks_exact_mut(3) {
986 chunk.swap(0, 2);
987 }
988 }
989 4 => {
990 for chunk in pcm.chunks_exact_mut(4) {
991 chunk.swap(0, 3);
992 chunk.swap(1, 2);
993 }
994 }
995 _ => {}
996 }
997}
998
999#[cfg(test)]
1000mod tests {
1001 use super::*;
1002 use std::fs::File;
1003 use std::io::BufReader;
1004 use std::path::PathBuf;
1005
1006 fn test_fixture_path(name: &str) -> PathBuf {
1007 PathBuf::from(env!("CARGO_MANIFEST_DIR"))
1008 .join("tests/fixtures")
1009 .join(name)
1010 }
1011
1012 fn load_reference_pcm(name: &str) -> Vec<u8> {
1013 let path = test_fixture_path(&format!("ref/{}", name));
1014 let data = std::fs::read(&path)
1015 .unwrap_or_else(|e| panic!("Failed to read {}: {}", path.display(), e));
1016 data[44..].to_vec()
1017 }
1018
1019 fn open_ape(name: &str) -> BufReader<File> {
1020 let path = test_fixture_path(&format!("ape/{}", name));
1021 let file = File::open(&path)
1022 .unwrap_or_else(|e| panic!("Failed to open {}: {}", path.display(), e));
1023 BufReader::new(file)
1024 }
1025
1026 fn decode_ape_file(name: &str) -> ApeResult<Vec<u8>> {
1027 let mut reader = open_ape(name);
1028 decode(&mut reader)
1029 }
1030
1031 #[test]
1034 fn test_decode_sine_16s_c1000() {
1035 let decoded = decode_ape_file("sine_16s_c1000.ape").unwrap();
1036 let expected = load_reference_pcm("sine_16s_c1000.wav");
1037 assert_eq!(decoded.len(), expected.len());
1038 assert_eq!(decoded, expected);
1039 }
1040
1041 #[test]
1042 fn test_decode_sine_16s_c2000() {
1043 let decoded = decode_ape_file("sine_16s_c2000.ape").unwrap();
1044 let expected = load_reference_pcm("sine_16s_c2000.wav");
1045 assert_eq!(decoded, expected);
1046 }
1047
1048 #[test]
1049 fn test_decode_silence_16s() {
1050 let decoded = decode_ape_file("silence_16s_c2000.ape").unwrap();
1051 let expected = load_reference_pcm("silence_16s_c2000.wav");
1052 assert_eq!(decoded, expected);
1053 }
1054
1055 #[test]
1056 fn test_decode_sine_16m() {
1057 let decoded = decode_ape_file("sine_16m_c2000.ape").unwrap();
1058 let expected = load_reference_pcm("sine_16m_c2000.wav");
1059 assert_eq!(decoded, expected);
1060 }
1061
1062 #[test]
1063 fn test_decode_short_16s() {
1064 let decoded = decode_ape_file("short_16s_c2000.ape").unwrap();
1065 let expected = load_reference_pcm("short_16s_c2000.wav");
1066 assert_eq!(decoded, expected);
1067 }
1068
1069 #[test]
1070 fn test_decode_all_compression_levels() {
1071 for level in &["c1000", "c2000", "c3000", "c4000", "c5000"] {
1072 let name = format!("sine_16s_{}.ape", level);
1073 let ref_name = format!("sine_16s_{}.wav", level);
1074 let decoded = decode_ape_file(&name).unwrap_or_else(|e| panic!("{}: {:?}", name, e));
1075 let expected = load_reference_pcm(&ref_name);
1076 assert_eq!(decoded, expected, "Mismatch for {}", name);
1077 }
1078 }
1079
1080 #[test]
1081 fn test_decode_8bit() {
1082 let decoded = decode_ape_file("sine_8s_c2000.ape").unwrap();
1083 let expected = load_reference_pcm("sine_8s_c2000.wav");
1084 assert_eq!(decoded, expected);
1085 }
1086
1087 #[test]
1088 fn test_decode_24bit() {
1089 let decoded = decode_ape_file("sine_24s_c2000.ape").unwrap();
1090 let expected = load_reference_pcm("sine_24s_c2000.wav");
1091 assert_eq!(decoded, expected);
1092 }
1093
1094 #[test]
1095 fn test_decode_32bit() {
1096 let decoded = decode_ape_file("sine_32s_c2000.ape").unwrap();
1097 let expected = load_reference_pcm("sine_32s_c2000.wav");
1098 assert_eq!(decoded, expected);
1099 }
1100
1101 #[test]
1102 fn test_decode_multiframe() {
1103 let decoded = decode_ape_file("multiframe_16s_c2000.ape").unwrap();
1104 let expected = load_reference_pcm("multiframe_16s_c2000.wav");
1105 assert_eq!(decoded, expected);
1106 }
1107
1108 #[test]
1109 fn test_decode_identical_channels() {
1110 let decoded = decode_ape_file("identical_16s_c2000.ape").unwrap();
1111 let expected = load_reference_pcm("identical_16s_c2000.wav");
1112 assert_eq!(decoded, expected);
1113 }
1114
1115 #[test]
1116 fn test_decode_all_fixtures() {
1117 let fixtures = [
1118 "dc_offset_16s_c2000.ape",
1119 "identical_16s_c2000.ape",
1120 "impulse_16s_c2000.ape",
1121 "left_only_16s_c2000.ape",
1122 "multiframe_16s_c2000.ape",
1123 "noise_16s_c2000.ape",
1124 "short_16s_c2000.ape",
1125 "silence_16s_c2000.ape",
1126 "sine_16m_c2000.ape",
1127 "sine_16s_c1000.ape",
1128 "sine_16s_c2000.ape",
1129 "sine_16s_c3000.ape",
1130 "sine_16s_c4000.ape",
1131 "sine_16s_c5000.ape",
1132 "sine_24s_c2000.ape",
1133 "sine_32s_c2000.ape",
1134 "sine_8s_c2000.ape",
1135 ];
1136
1137 for fixture in &fixtures {
1138 let ref_name = fixture.replace(".ape", ".wav");
1139 let decoded = decode_ape_file(fixture)
1140 .unwrap_or_else(|e| panic!("Failed to decode {}: {:?}", fixture, e));
1141 let expected = load_reference_pcm(&ref_name);
1142 assert_eq!(
1143 decoded.len(),
1144 expected.len(),
1145 "Length mismatch for {}",
1146 fixture
1147 );
1148 assert_eq!(decoded, expected, "Data mismatch for {}", fixture);
1149 }
1150 }
1151
1152 #[test]
1155 fn test_ape_decoder_info() {
1156 let reader = open_ape("sine_16s_c2000.ape");
1157 let decoder = ApeDecoder::new(reader).unwrap();
1158 let info = decoder.info();
1159 assert_eq!(info.sample_rate, 44100);
1160 assert_eq!(info.channels, 2);
1161 assert_eq!(info.bits_per_sample, 16);
1162 assert_eq!(info.total_samples, 44100);
1163 assert_eq!(info.compression_level, 2000);
1164 assert_eq!(info.block_align, 4);
1165 }
1166
1167 #[test]
1168 fn test_decode_frame_by_frame() {
1169 let reader = open_ape("sine_16s_c2000.ape");
1170 let mut decoder = ApeDecoder::new(reader).unwrap();
1171 let expected = load_reference_pcm("sine_16s_c2000.wav");
1172
1173 let mut all_pcm = Vec::new();
1174 for frame_idx in 0..decoder.total_frames() {
1175 let frame_pcm = decoder.decode_frame(frame_idx).unwrap();
1176 all_pcm.extend_from_slice(&frame_pcm);
1177 }
1178
1179 assert_eq!(all_pcm, expected);
1180 }
1181
1182 #[test]
1183 fn test_decode_multiframe_frame_by_frame() {
1184 let reader = open_ape("multiframe_16s_c2000.ape");
1185 let mut decoder = ApeDecoder::new(reader).unwrap();
1186 let expected = load_reference_pcm("multiframe_16s_c2000.wav");
1187
1188 assert!(decoder.total_frames() > 1, "Expected multiple frames");
1189
1190 let mut all_pcm = Vec::new();
1191 for frame_idx in 0..decoder.total_frames() {
1192 let frame_pcm = decoder.decode_frame(frame_idx).unwrap();
1193 assert!(!frame_pcm.is_empty());
1194 all_pcm.extend_from_slice(&frame_pcm);
1195 }
1196
1197 assert_eq!(all_pcm, expected);
1198 }
1199
1200 #[test]
1201 fn test_frames_iterator() {
1202 let reader = open_ape("sine_16s_c2000.ape");
1203 let mut decoder = ApeDecoder::new(reader).unwrap();
1204 let expected = load_reference_pcm("sine_16s_c2000.wav");
1205
1206 let all_pcm: Vec<u8> = decoder
1207 .frames()
1208 .collect::<Result<Vec<_>, _>>()
1209 .unwrap()
1210 .concat();
1211
1212 assert_eq!(all_pcm, expected);
1213 }
1214
1215 #[test]
1216 fn test_seek_sample_level() {
1217 let reader = open_ape("multiframe_16s_c2000.ape");
1218 let mut decoder = ApeDecoder::new(reader).unwrap();
1219 let bpf = decoder.info().blocks_per_frame as u64;
1220
1221 let r = decoder.seek(0).unwrap();
1223 assert_eq!(r.frame_index, 0);
1224 assert_eq!(r.skip_samples, 0);
1225 assert_eq!(r.actual_sample, 0);
1226
1227 let r = decoder.seek(100).unwrap();
1229 assert_eq!(r.frame_index, 0);
1230 assert_eq!(r.skip_samples, 100);
1231 assert_eq!(r.actual_sample, 100);
1232
1233 let r = decoder.seek(bpf).unwrap();
1235 assert_eq!(r.frame_index, 1);
1236 assert_eq!(r.skip_samples, 0);
1237 assert_eq!(r.actual_sample, bpf);
1238
1239 let r = decoder.seek(bpf + 100).unwrap();
1241 assert_eq!(r.frame_index, 1);
1242 assert_eq!(r.skip_samples, 100);
1243 assert_eq!(r.actual_sample, bpf + 100);
1244
1245 let r = decoder.seek(u64::MAX).unwrap();
1247 assert_eq!(r.actual_sample, decoder.info().total_samples - 1);
1248 }
1249
1250 #[test]
1251 fn test_decode_from_mid_frame() {
1252 let reader = open_ape("sine_16s_c2000.ape");
1253 let mut decoder = ApeDecoder::new(reader).unwrap();
1254 let block_align = decoder.info().block_align as usize;
1255
1256 let full_frame = decoder.decode_frame(0).unwrap();
1258
1259 let partial = decoder.decode_from(100).unwrap();
1261
1262 let skip = 100 * block_align;
1264 assert_eq!(partial, &full_frame[skip..]);
1265 }
1266
1267 #[test]
1268 fn test_expanded_metadata() {
1269 let reader = open_ape("sine_16s_c2000.ape");
1270 let decoder = ApeDecoder::new(reader).unwrap();
1271 let info = decoder.info();
1272
1273 assert_eq!(info.bytes_per_sample, 2);
1274 assert_eq!(info.source_format, SourceFormat::Wav);
1275 assert!(!info.is_big_endian);
1276 assert!(!info.is_floating_point);
1277 assert!(!info.is_signed_8bit);
1278 assert!(info.average_bitrate_kbps > 0);
1279 assert!(info.decompressed_bitrate_kbps > 0);
1280 assert!(info.file_size_bytes > 0);
1281 assert_eq!(info.format_flags & 0x0200, 0); }
1283
1284 #[test]
1285 fn test_wav_header_data() {
1286 let reader = open_ape("sine_16s_c2000.ape");
1287 let decoder = ApeDecoder::new(reader).unwrap();
1288
1289 let header = decoder.wav_header_data();
1290 if let Some(data) = header {
1292 assert!(data.len() >= 12);
1293 assert_eq!(&data[0..4], b"RIFF");
1295 }
1296 }
1297
1298 #[test]
1299 fn test_read_tag() {
1300 let reader = open_ape("sine_16s_c2000.ape");
1301 let mut decoder = ApeDecoder::new(reader).unwrap();
1302 let _tag = decoder.read_tag();
1304 }
1305
1306 #[test]
1307 fn test_decode_frame_out_of_bounds() {
1308 let reader = open_ape("sine_16s_c2000.ape");
1309 let mut decoder = ApeDecoder::new(reader).unwrap();
1310 let result = decoder.decode_frame(999);
1311 assert!(result.is_err());
1312 }
1313
1314 #[test]
1317 fn test_decode_with_progress() {
1318 let reader = open_ape("sine_16s_c2000.ape");
1319 let mut decoder = ApeDecoder::new(reader).unwrap();
1320 let expected = load_reference_pcm("sine_16s_c2000.wav");
1321
1322 let mut last_progress = 0.0f64;
1323 let decoded = decoder
1324 .decode_all_with(|p| {
1325 assert!(p >= last_progress, "progress must be monotonic");
1326 last_progress = p;
1327 true })
1329 .unwrap();
1330
1331 assert!((last_progress - 1.0).abs() < 0.01);
1332 assert_eq!(decoded, expected);
1333 }
1334
1335 #[test]
1336 fn test_decode_with_cancel() {
1337 let reader = open_ape("multiframe_16s_c2000.ape");
1338 let mut decoder = ApeDecoder::new(reader).unwrap();
1339
1340 let result = decoder.decode_all_with(|p| {
1341 p < 0.5 });
1343
1344 assert!(result.is_err());
1345 }
1346
1347 #[test]
1350 fn test_decode_range_full_file() {
1351 let reader = open_ape("sine_16s_c2000.ape");
1352 let mut decoder = ApeDecoder::new(reader).unwrap();
1353 let total = decoder.info().total_samples;
1354 let expected = load_reference_pcm("sine_16s_c2000.wav");
1355
1356 let decoded = decoder.decode_range(0, total).unwrap();
1357 assert_eq!(decoded, expected);
1358 }
1359
1360 #[test]
1361 fn test_decode_range_subset() {
1362 let reader = open_ape("sine_16s_c2000.ape");
1363 let mut decoder = ApeDecoder::new(reader).unwrap();
1364 let block_align = decoder.info().block_align as usize;
1365 let expected = load_reference_pcm("sine_16s_c2000.wav");
1366
1367 let decoded = decoder.decode_range(100, 200).unwrap();
1369 assert_eq!(decoded.len(), 100 * block_align);
1370 assert_eq!(decoded, &expected[100 * block_align..200 * block_align]);
1371 }
1372
1373 #[test]
1374 fn test_decode_range_empty() {
1375 let reader = open_ape("sine_16s_c2000.ape");
1376 let mut decoder = ApeDecoder::new(reader).unwrap();
1377
1378 let decoded = decoder.decode_range(100, 100).unwrap();
1379 assert!(decoded.is_empty());
1380
1381 let decoded = decoder.decode_range(200, 100).unwrap();
1382 assert!(decoded.is_empty());
1383 }
1384
1385 #[test]
1388 fn test_decode_parallel_matches_sequential() {
1389 let expected = load_reference_pcm("sine_16s_c2000.wav");
1390
1391 let reader = open_ape("sine_16s_c2000.ape");
1392 let mut decoder = ApeDecoder::new(reader).unwrap();
1393 let parallel = decoder.decode_all_parallel(4).unwrap();
1394
1395 assert_eq!(parallel, expected);
1396 }
1397
1398 #[test]
1399 fn test_decode_parallel_multiframe() {
1400 let expected = load_reference_pcm("multiframe_16s_c2000.wav");
1401
1402 let reader = open_ape("multiframe_16s_c2000.ape");
1403 let mut decoder = ApeDecoder::new(reader).unwrap();
1404 let parallel = decoder.decode_all_parallel(2).unwrap();
1405
1406 assert_eq!(parallel, expected);
1407 }
1408
1409 #[test]
1410 fn test_decode_parallel_single_thread() {
1411 let expected = load_reference_pcm("sine_16s_c2000.wav");
1412
1413 let reader = open_ape("sine_16s_c2000.ape");
1414 let mut decoder = ApeDecoder::new(reader).unwrap();
1415 let decoded = decoder.decode_all_parallel(1).unwrap();
1416
1417 assert_eq!(decoded, expected);
1418 }
1419
1420 #[test]
1421 fn test_decode_parallel_all_fixtures() {
1422 let fixtures = [
1423 "dc_offset_16s_c2000.ape",
1424 "identical_16s_c2000.ape",
1425 "impulse_16s_c2000.ape",
1426 "left_only_16s_c2000.ape",
1427 "multiframe_16s_c2000.ape",
1428 "noise_16s_c2000.ape",
1429 "short_16s_c2000.ape",
1430 "silence_16s_c2000.ape",
1431 "sine_16m_c2000.ape",
1432 "sine_16s_c1000.ape",
1433 "sine_16s_c2000.ape",
1434 "sine_16s_c3000.ape",
1435 "sine_16s_c4000.ape",
1436 "sine_16s_c5000.ape",
1437 "sine_24s_c2000.ape",
1438 "sine_32s_c2000.ape",
1439 "sine_8s_c2000.ape",
1440 ];
1441
1442 for fixture in &fixtures {
1443 let ref_name = fixture.replace(".ape", ".wav");
1444 let reader = open_ape(fixture);
1445 let mut decoder = ApeDecoder::new(reader).unwrap();
1446 let parallel = decoder
1447 .decode_all_parallel(2)
1448 .unwrap_or_else(|e| panic!("Parallel decode failed for {}: {:?}", fixture, e));
1449 let expected = load_reference_pcm(&ref_name);
1450 assert_eq!(parallel, expected, "Parallel mismatch for {}", fixture);
1451 }
1452 }
1453
1454 #[test]
1457 fn test_decode_truncated_file() {
1458 let data = vec![0u8; 10];
1460 let mut cursor = std::io::Cursor::new(data);
1461 let result = decode(&mut cursor);
1462 assert!(result.is_err());
1463 }
1464
1465 #[test]
1466 fn test_decode_wrong_magic() {
1467 let mut data = vec![0u8; 200];
1469 data[0..4].copy_from_slice(b"NOPE");
1470 let mut cursor = std::io::Cursor::new(data);
1471 let result = decode(&mut cursor);
1472 assert!(result.is_err());
1473 }
1474
1475 #[test]
1476 fn test_decode_empty_file() {
1477 let data = vec![];
1478 let mut cursor = std::io::Cursor::new(data);
1479 let result = decode(&mut cursor);
1480 assert!(result.is_err());
1481 }
1482
1483 #[test]
1484 fn test_decoder_new_truncated() {
1485 let data = vec![0u8; 50]; let cursor = std::io::Cursor::new(data);
1487 let result = ApeDecoder::new(cursor);
1488 assert!(result.is_err());
1489 }
1490
1491 #[test]
1494 fn test_float_transform_roundtrip() {
1495 let original: u32 = 0x3F800000; let transformed = super::float_transform_sample(original);
1498 let restored = super::float_transform_sample(transformed);
1499 assert_eq!(restored, original);
1500 }
1501
1502 #[test]
1503 fn test_float_transform_zero() {
1504 let transformed = super::float_transform_sample(0);
1505 let restored = super::float_transform_sample(transformed);
1506 assert_eq!(restored, 0);
1507 }
1508
1509 #[test]
1510 fn test_byte_swap_16bit() {
1511 let mut data = vec![0x01, 0x02, 0x03, 0x04];
1512 super::byte_swap_samples(&mut data, 2);
1513 assert_eq!(data, vec![0x02, 0x01, 0x04, 0x03]);
1514 }
1515
1516 #[test]
1517 fn test_byte_swap_24bit() {
1518 let mut data = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06];
1519 super::byte_swap_samples(&mut data, 3);
1520 assert_eq!(data, vec![0x03, 0x02, 0x01, 0x06, 0x05, 0x04]);
1521 }
1522
1523 #[test]
1524 fn test_byte_swap_32bit() {
1525 let mut data = vec![0x01, 0x02, 0x03, 0x04];
1526 super::byte_swap_samples(&mut data, 4);
1527 assert_eq!(data, vec![0x04, 0x03, 0x02, 0x01]);
1528 }
1529
1530 #[test]
1533 fn test_verify_md5_all_fixtures() {
1534 let fixtures = [
1535 "dc_offset_16s_c2000.ape",
1536 "identical_16s_c2000.ape",
1537 "impulse_16s_c2000.ape",
1538 "left_only_16s_c2000.ape",
1539 "multiframe_16s_c2000.ape",
1540 "noise_16s_c2000.ape",
1541 "short_16s_c2000.ape",
1542 "silence_16s_c2000.ape",
1543 "sine_16m_c2000.ape",
1544 "sine_16s_c1000.ape",
1545 "sine_16s_c2000.ape",
1546 "sine_16s_c3000.ape",
1547 "sine_16s_c4000.ape",
1548 "sine_16s_c5000.ape",
1549 "sine_24s_c2000.ape",
1550 "sine_32s_c2000.ape",
1551 "sine_8s_c2000.ape",
1552 ];
1553
1554 for fixture in &fixtures {
1555 let reader = open_ape(fixture);
1556 let mut decoder = ApeDecoder::new(reader).unwrap();
1557 let result = decoder
1558 .verify_md5()
1559 .unwrap_or_else(|e| panic!("MD5 verify failed for {}: {:?}", fixture, e));
1560 assert!(result, "MD5 mismatch for {}", fixture);
1561 }
1562 }
1563
1564 #[test]
1565 fn test_stored_md5_nonzero() {
1566 let reader = open_ape("sine_16s_c2000.ape");
1567 let decoder = ApeDecoder::new(reader).unwrap();
1568 let md5 = decoder.stored_md5();
1569 assert_ne!(md5, &[0u8; 16], "MD5 should not be all zeros");
1571 }
1572
1573 #[test]
1576 fn test_generate_wav_header() {
1577 let reader = open_ape("sine_16s_c2000.ape");
1578 let decoder = ApeDecoder::new(reader).unwrap();
1579 let header = decoder.info().generate_wav_header();
1580
1581 assert_eq!(header.len(), 44);
1583
1584 assert_eq!(&header[0..4], b"RIFF");
1586 assert_eq!(&header[8..12], b"WAVE");
1587 assert_eq!(&header[12..16], b"fmt ");
1588 assert_eq!(&header[36..40], b"data");
1589
1590 let channels = u16::from_le_bytes([header[22], header[23]]);
1592 let sample_rate = u32::from_le_bytes([header[24], header[25], header[26], header[27]]);
1593 let bits = u16::from_le_bytes([header[34], header[35]]);
1594 assert_eq!(channels, 2);
1595 assert_eq!(sample_rate, 44100);
1596 assert_eq!(bits, 16);
1597
1598 let data_size = u32::from_le_bytes([header[40], header[41], header[42], header[43]]);
1600 let expected = decoder.info().total_samples as u32 * decoder.info().block_align as u32;
1601 assert_eq!(data_size, expected);
1602 }
1603
1604 #[test]
1605 fn test_generate_wav_header_matches_stored() {
1606 let reader = open_ape("sine_16s_c2000.ape");
1607 let decoder = ApeDecoder::new(reader).unwrap();
1608
1609 let generated = decoder.info().generate_wav_header();
1610 if let Some(stored) = decoder.wav_header_data() {
1611 if stored.len() == 44 {
1613 assert_eq!(&generated[22..24], &stored[22..24]); assert_eq!(&generated[24..28], &stored[24..28]); assert_eq!(&generated[34..36], &stored[34..36]); }
1618 }
1619 }
1620}