use error::{Error, Result, fmt_err};
use input::ReadBytes;
use std::str;
use std::slice;
#[derive(Clone, Copy)]
struct MetadataBlockHeader {
is_last: bool,
block_type: u8,
length: u32,
}
#[derive(Clone, Copy, Debug)]
pub struct StreamInfo {
pub min_block_size: u16,
pub max_block_size: u16,
pub min_frame_size: Option<u32>,
pub max_frame_size: Option<u32>,
pub sample_rate: u32,
pub channels: u32,
pub bits_per_sample: u32,
pub samples: Option<u64>,
pub md5sum: [u8; 16],
}
#[derive(Clone, Copy)]
pub struct SeekPoint {
pub sample: u64,
pub offset: u64,
pub samples: u16,
}
pub struct SeekTable {
#[allow(dead_code)] seekpoints: Vec<SeekPoint>,
}
pub struct VorbisComment {
pub vendor: String,
pub comments: Vec<(String, usize)>,
}
pub enum MetadataBlock {
StreamInfo(StreamInfo),
Padding {
length: u32,
},
Application {
id: u32,
data: Vec<u8>,
},
SeekTable(SeekTable),
VorbisComment(VorbisComment),
CueSheet, Picture, Reserved,
}
pub struct Tags<'a> {
iter: slice::Iter<'a, (String, usize)>,
}
impl<'a> Tags<'a> {
#[inline]
pub fn new(comments: &'a [(String, usize)]) -> Tags<'a> {
Tags {
iter: comments.iter(),
}
}
}
impl<'a> Iterator for Tags<'a> {
type Item = (&'a str, &'a str);
#[inline]
fn next(&mut self) -> Option<(&'a str, &'a str)> {
return self.iter.next().map(|&(ref comment, sep_idx)| {
(&comment[..sep_idx], &comment[sep_idx+1..])
})
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<'a> ExactSizeIterator for Tags<'a> {}
pub struct GetTag<'a> {
vorbis_comments: &'a [(String, usize)],
needle: &'a str,
index: usize,
}
impl<'a> GetTag<'a> {
#[inline]
pub fn new(vorbis_comments: &'a [(String, usize)], needle: &'a str) -> GetTag<'a> {
GetTag {
vorbis_comments: vorbis_comments,
needle: needle,
index: 0,
}
}
}
impl<'a> Iterator for GetTag<'a> {
type Item = &'a str;
#[inline]
fn next(&mut self) -> Option<&'a str> {
#[allow(unused_imports)]
use std::ascii::AsciiExt;
while self.index < self.vorbis_comments.len() {
let (ref comment, sep_idx) = self.vorbis_comments[self.index];
self.index += 1;
if comment[..sep_idx].eq_ignore_ascii_case(self.needle) {
return Some(&comment[sep_idx + 1..])
}
}
return None
}
}
#[inline]
fn read_metadata_block_header<R: ReadBytes>(input: &mut R) -> Result<MetadataBlockHeader> {
let byte = try!(input.read_u8());
let is_last = (byte >> 7) == 1;
let block_type = byte & 0b0111_1111;
let length = try!(input.read_be_u24());
let header = MetadataBlockHeader {
is_last: is_last,
block_type: block_type,
length: length,
};
Ok(header)
}
#[inline]
pub fn read_metadata_block_with_header<R: ReadBytes>(input: &mut R)
-> Result<MetadataBlock> {
let header = try!(read_metadata_block_header(input));
read_metadata_block(input, header.block_type, header.length)
}
#[inline]
pub fn read_metadata_block<R: ReadBytes>(input: &mut R,
block_type: u8,
length: u32)
-> Result<MetadataBlock> {
match block_type {
0 => {
if length == 34 {
let streaminfo = try!(read_streaminfo_block(input));
Ok(MetadataBlock::StreamInfo(streaminfo))
} else {
fmt_err("invalid streaminfo metadata block length")
}
}
1 => {
try!(read_padding_block(input, length));
Ok(MetadataBlock::Padding { length: length })
}
2 => {
let (id, data) = try!(read_application_block(input, length));
Ok(MetadataBlock::Application {
id: id,
data: data,
})
}
3 => {
try!(input.skip(length));
Ok(MetadataBlock::Padding { length: length })
}
4 => {
let vorbis_comment = try!(read_vorbis_comment_block(input, length));
Ok(MetadataBlock::VorbisComment(vorbis_comment))
}
5 => {
try!(input.skip(length));
Ok(MetadataBlock::Padding { length: length })
}
6 => {
try!(input.skip(length));
Ok(MetadataBlock::Padding { length: length })
}
127 => {
fmt_err("invalid metadata block type")
}
_ => {
try!(input.skip(length));
Ok(MetadataBlock::Reserved)
}
}
}
fn read_streaminfo_block<R: ReadBytes>(input: &mut R) -> Result<StreamInfo> {
let min_block_size = try!(input.read_be_u16());
let max_block_size = try!(input.read_be_u16());
let min_frame_size = try!(input.read_be_u24());
let max_frame_size = try!(input.read_be_u24());
let sample_rate_msb = try!(input.read_be_u16());
let sample_rate_lsb = try!(input.read_u8());
let sample_rate = (sample_rate_msb as u32) << 4 | (sample_rate_lsb as u32) >> 4;
let n_channels_bps = sample_rate_lsb;
let n_channels = ((n_channels_bps >> 1) & 0b0000_0111) + 1;
let bps_msb = n_channels_bps & 1;
let bps_lsb_n_samples = try!(input.read_u8());
let bits_per_sample = (bps_msb << 4 | (bps_lsb_n_samples >> 4)) + 1;
let n_samples_msb = bps_lsb_n_samples & 0b0000_1111;
let n_samples_lsb = try!(input.read_be_u32());
let n_samples = (n_samples_msb as u64) << 32 | n_samples_lsb as u64;
let mut md5sum = [0u8; 16];
try!(input.read_into(&mut md5sum));
if min_block_size > max_block_size {
return fmt_err("inconsistent bounds, min block size > max block size");
}
if min_block_size < 16 {
return fmt_err("invalid block size, must be at least 16");
}
if min_frame_size > max_frame_size && max_frame_size != 0 {
return fmt_err("inconsistent bounds, min frame size > max frame size");
}
if sample_rate == 0 || sample_rate > 655350 {
return fmt_err("invalid sample rate");
}
let stream_info = StreamInfo {
min_block_size: min_block_size,
max_block_size: max_block_size,
min_frame_size: if min_frame_size == 0 {
None
} else {
Some(min_frame_size)
},
max_frame_size: if max_frame_size == 0 {
None
} else {
Some(max_frame_size)
},
sample_rate: sample_rate,
channels: n_channels as u32,
bits_per_sample: bits_per_sample as u32,
samples: if n_samples == 0 {
None
} else {
Some(n_samples)
},
md5sum: md5sum,
};
Ok(stream_info)
}
fn read_vorbis_comment_block<R: ReadBytes>(input: &mut R, length: u32) -> Result<VorbisComment> {
if length < 8 {
return fmt_err("Vorbis comment block is too short")
}
if length > 10 * 1024 * 1024 {
let msg = "Vorbis comment blocks larger than 10 MiB are not supported";
return Err(Error::Unsupported(msg))
}
let vendor_len = try!(input.read_le_u32());
if vendor_len > length - 8 { return fmt_err("vendor string too long") }
let mut vendor_bytes = Vec::with_capacity(vendor_len as usize);
unsafe { vendor_bytes.set_len(vendor_len as usize); }
try!(input.read_into(&mut vendor_bytes));
let vendor = try!(String::from_utf8(vendor_bytes));
let mut comments_len = try!(input.read_le_u32());
if comments_len >= length / 4 {
return fmt_err("too many entries for Vorbis comment block")
}
let mut comments = Vec::with_capacity(comments_len as usize);
let mut bytes_left = length - 8 - vendor_len;
while bytes_left >= 4 && comments.len() < comments_len as usize {
let comment_len = try!(input.read_le_u32());
bytes_left -= 4;
if comment_len > bytes_left {
return fmt_err("Vorbis comment too long for Vorbis comment block")
}
if comment_len == 0 {
comments_len -= 1;
continue;
}
let mut comment_bytes = Vec::with_capacity(comment_len as usize);
unsafe { comment_bytes.set_len(comment_len as usize); }
try!(input.read_into(&mut comment_bytes));
bytes_left -= comment_len;
if let Some(sep_index) = comment_bytes.iter().position(|&x| x == b'=') {
{
let name_bytes = &comment_bytes[..sep_index];
if name_bytes.iter().any(|&x| x < 0x20 || x > 0x7d) {
return fmt_err("Vorbis comment field name contains invalid byte")
}
}
let comment = try!(String::from_utf8(comment_bytes));
comments.push((comment, sep_index));
} else {
return fmt_err("Vorbis comment does not contain '='")
}
}
if bytes_left != 0 {
return fmt_err("Vorbis comment block has excess data")
}
if comments.len() != comments_len as usize {
return fmt_err("Vorbis comment block contains wrong number of entries")
}
let vorbis_comment = VorbisComment {
vendor: vendor,
comments: comments,
};
Ok(vorbis_comment)
}
fn read_padding_block<R: ReadBytes>(input: &mut R, length: u32) -> Result<()> {
Ok(try!(input.skip(length)))
}
fn read_application_block<R: ReadBytes>(input: &mut R, length: u32) -> Result<(u32, Vec<u8>)> {
if length < 4 {
return fmt_err("application block length must be at least 4 bytes")
}
if length > 10 * 1024 * 1024 {
let msg = "application blocks larger than 10 MiB are not supported";
return Err(Error::Unsupported(msg))
}
let id = try!(input.read_be_u32());
let mut data = Vec::with_capacity(length as usize - 4);
unsafe { data.set_len(length as usize - 4); }
try!(input.read_into(&mut data));
Ok((id, data))
}
pub struct MetadataBlockReader<R: ReadBytes> {
input: R,
done: bool,
}
pub type MetadataBlockResult = Result<MetadataBlock>;
impl<R: ReadBytes> MetadataBlockReader<R> {
pub fn new(input: R) -> MetadataBlockReader<R> {
MetadataBlockReader {
input: input,
done: false,
}
}
#[inline]
fn read_next(&mut self) -> MetadataBlockResult {
let header = try!(read_metadata_block_header(&mut self.input));
let block = try!(read_metadata_block(&mut self.input, header.block_type, header.length));
self.done = header.is_last;
Ok(block)
}
}
impl<R: ReadBytes> Iterator for MetadataBlockReader<R> {
type Item = MetadataBlockResult;
#[inline]
fn next(&mut self) -> Option<MetadataBlockResult> {
if self.done {
None
} else {
let block = self.read_next();
if !block.is_ok() {
self.done = true;
}
Some(block)
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
if self.done { (0, Some(0)) } else { (1, None) }
}
}