use super::properties::{EncoderInfo, MpcSv8Properties, ReplayGain, StreamHeader};
use crate::config::ParsingMode;
use crate::musepack::error::MpcParseError;
use std::io::Read;
use crate::error::TooMuchDataError;
use byteorder::ReadBytesExt;
const STREAM_HEADER_KEY: [u8; 2] = *b"SH";
const REPLAYGAIN_KEY: [u8; 2] = *b"RG";
const ENCODER_INFO_KEY: [u8; 2] = *b"EI";
#[allow(dead_code)]
const AUDIO_PACKET_KEY: [u8; 2] = *b"AP";
const STREAM_END_KEY: [u8; 2] = *b"SE";
pub(crate) fn read_from<R>(
data: &mut R,
parse_mode: ParsingMode,
) -> Result<MpcSv8Properties, MpcParseError>
where
R: Read,
{
let mut packet_reader = PacketReader::new(data);
let mut stream_header = None;
let mut replay_gain = None;
let mut encoder_info = None;
let mut stream_length = 0;
let mut found_stream_end = false;
while let Ok((packet_id, packet_length)) = packet_reader.next() {
stream_length += packet_length;
match packet_id {
STREAM_HEADER_KEY => stream_header = Some(StreamHeader::read(&mut packet_reader)?),
REPLAYGAIN_KEY => replay_gain = Some(ReplayGain::read(&mut packet_reader)?),
ENCODER_INFO_KEY => encoder_info = Some(EncoderInfo::read(&mut packet_reader)?),
STREAM_END_KEY => {
found_stream_end = true;
break;
},
_ => {},
}
}
let stream_header = match stream_header {
Some(stream_header) => stream_header,
None => {
if parse_mode == ParsingMode::Strict {
return Err(MpcParseError::message(
"file is missing a Stream Header packet",
));
}
StreamHeader::default()
},
};
let replay_gain = match replay_gain {
Some(replay_gain) => replay_gain,
None => {
if parse_mode == ParsingMode::Strict {
return Err(MpcParseError::message(
"file is missing a ReplayGain packet",
));
}
ReplayGain::default()
},
};
if stream_length == 0 && parse_mode == ParsingMode::Strict {
return Err(MpcParseError::message("file is missing an Audio packet"));
}
if !found_stream_end && parse_mode == ParsingMode::Strict {
return Err(MpcParseError::message(
"file is missing a Stream End packet",
));
}
let properties =
super::properties::read(stream_length, stream_header, replay_gain, encoder_info)?;
Ok(properties)
}
pub struct PacketReader<R> {
reader: R,
capacity: u64,
}
impl<R: Read> PacketReader<R> {
fn new(reader: R) -> Self {
Self {
reader,
capacity: 0,
}
}
fn next(&mut self) -> Result<([u8; 2], u64), MpcParseError> {
std::io::copy(
&mut self.reader.by_ref().take(self.capacity),
&mut std::io::sink(),
)?;
let mut key = [0; 2];
self.reader.read_exact(&mut key)?;
if !key[0].is_ascii_uppercase() || !key[1].is_ascii_uppercase() {
return Err(MpcParseError::message(
"packet key contains characters that are out of the allowed range",
));
}
let (packet_size, packet_size_byte_count) = Self::read_size(&mut self.reader)?;
self.capacity = packet_size.saturating_sub(u64::from(2 + packet_size_byte_count));
Ok((key, self.capacity))
}
pub fn read_size(reader: &mut R) -> Result<(u64, u8), MpcParseError> {
let mut current;
let mut size = 0u64;
let mut bytes_read = 0;
loop {
current = reader.read_u8()?;
bytes_read += 1;
if bytes_read > 9 {
return Err(TooMuchDataError.into());
}
size = (size << 7) | u64::from(current & 0x7F);
if current & 0x80 == 0 {
break;
}
}
Ok((size, bytes_read))
}
}
impl<R: Read> Read for PacketReader<R> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let bytes_read = self.reader.by_ref().take(self.capacity).read(buf)?;
self.capacity = self.capacity.saturating_sub(bytes_read as u64);
Ok(bytes_read)
}
}