use std::cell::Cell;
use std::io;
use std::io::{ErrorKind, Read};
use log::trace;
use thiserror::Error;
use huffman_codeword_lengths::VorbisCodebookNumberFrequenciesDecorator;
use huffman_tree::{
TryFromCodewordLengthsListError, VorbisHuffmanTree, VorbisHuffmanTreeWalkerError
};
use vorbis_bitpack::BitpackReader;
mod huffman_codeword_lengths;
mod huffman_tree;
#[derive(Debug, Error)]
#[allow(variant_size_differences)] pub enum VorbisCodebookError {
#[error("Codebook {codebook_number} is invalid: {__error}")]
InvalidCodebookCodewords {
codebook_number: u16,
#[doc(hidden)]
__error: TryFromCodewordLengthsListError
},
#[error("Codebook {codebook_number} entry decode error: {__error}")]
CodebookTreeWalkError {
codebook_number: u16,
#[doc(hidden)]
__error: VorbisHuffmanTreeWalkerError
},
#[error("Codebook {codebook_number} entry decode error: end of packet while decoding entry")]
EofWhileDecodingEntry {
codebook_number: u16
},
#[error("I/O error decoding codebook entry: {0}")]
IoError(#[from] io::Error)
}
pub(super) struct VorbisCodebook {
pub(super) codebook_number: u16,
huffman_tree: VorbisHuffmanTree,
entry_decode_frequencies_or_lengths: Cell<Vec<u64>>,
recording_decode_frequencies: bool
}
impl VorbisCodebook {
pub(super) fn new<T: AsRef<[u8]>>(
codebook_number: u16,
codeword_lengths: T
) -> Result<Self, VorbisCodebookError> {
Ok(Self {
codebook_number,
entry_decode_frequencies_or_lengths: Cell::new(vec![
0;
codeword_lengths.as_ref().len()
]),
huffman_tree: VorbisHuffmanTree::try_from_codeword_lengths(codeword_lengths).map_err(
|error| VorbisCodebookError::InvalidCodebookCodewords {
codebook_number,
__error: error
}
)?,
recording_decode_frequencies: true
})
}
pub(super) fn decode_entry_number<R: Read>(
&self,
bitpack_reader: &mut BitpackReader<R>
) -> Result<u32, VorbisCodebookError> {
self.huffman_tree.with_walker(|mut walker| {
loop {
if let Some(entry) = walker
.walk(
bitpack_reader.read_flag().map_err(|err| {
if err.kind() == ErrorKind::UnexpectedEof {
VorbisCodebookError::EofWhileDecodingEntry {
codebook_number: self.codebook_number
}
} else {
err.into()
}
})?
)
.map_err(|error| VorbisCodebookError::CodebookTreeWalkError {
codebook_number: self.codebook_number,
__error: error
})? {
if self.recording_decode_frequencies {
let mut entry_decode_frequencies =
self.entry_decode_frequencies_or_lengths.take();
entry_decode_frequencies[entry.number as usize] =
entry_decode_frequencies[entry.number as usize].saturating_add(1);
self.entry_decode_frequencies_or_lengths
.set(entry_decode_frequencies);
}
trace!(
"Reading entry {} using codebook {}",
entry.number,
self.codebook_number
);
return Ok(entry.number);
}
}
})
}
pub(super) fn optimal_codeword_lengths(&mut self) -> &[u64] {
if self.recording_decode_frequencies {
self.recording_decode_frequencies = false;
VorbisCodebookNumberFrequenciesDecorator::new(
self.entry_decode_frequencies_or_lengths.get_mut()
)
.into_huffman_codeword_lengths()
} else {
self.entry_decode_frequencies_or_lengths.get_mut()
}
}
pub(super) fn optimal_codewords(&mut self) -> Vec<Option<(u32, u8)>> {
VorbisHuffmanTree::try_codewords_from_codeword_lengths(self.optimal_codeword_lengths())
.unwrap()
}
}