use std::fmt;
use hex_slice::AsHex;
use std::marker;
pub trait Descriptor<'buf>: Sized {
fn from_bytes(buf: &'buf[u8]) -> Result<Self, DescriptorError>;
}
#[macro_export]
macro_rules! descriptor_enum {
(
$(#[$outer:meta])*
$name:ident {
$(
$(#[$inner:ident $($args:tt)*])*
$case_name:ident $($tags:pat)|* => $t:ident
),*,
}
) => {
$(#[$outer])*
pub enum $name<'buf> {
$(
$(#[$inner $($args)*])*
$case_name($t<'buf>),
)*
}
impl<'buf> $crate::descriptor::Descriptor<'buf> for $name<'buf> {
fn from_bytes(buf: &'buf[u8]) -> Result<Self, $crate::descriptor::DescriptorError> {
if buf.len() < 2 {
return Err($crate::descriptor::DescriptorError::BufferTooShort{ buflen: buf.len() })
}
let tag = buf[0];
let len = buf[1] as usize;
let tag_end = len + 2;
if tag_end > buf.len() {
return Err($crate::descriptor::DescriptorError::TagTooLongForBuffer{ taglen: len, buflen: buf.len() })
}
let payload = &buf[2..tag_end];
match tag {
$( $( $tags )|* => Ok($name::$case_name($t::new(tag, payload)?)), )*
_ => Err($crate::descriptor::DescriptorError::UnhandledTagValue(tag)),
}
}
}
}
}
pub struct UnknownDescriptor<'buf> {
pub tag: u8,
pub payload: &'buf[u8],
}
impl<'buf> UnknownDescriptor<'buf> {
pub fn new(tag: u8, payload: &'buf[u8]) -> Result<UnknownDescriptor<'buf>, DescriptorError> {
Ok(UnknownDescriptor {
tag,
payload,
})
}
}
impl<'buf> fmt::Debug for UnknownDescriptor<'buf> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
f.debug_struct("UnknownDescriptor")
.field("tag", &self.tag)
.field("len", &self.payload.len())
.finish()
}
}
descriptor_enum!{
#[derive(Debug)]
CoreDescriptors {
Reserved 0|1|36...63 => UnknownDescriptor,
VideoStream 2 => UnknownDescriptor,
AudioStream 3 => UnknownDescriptor,
Hierarchy 4 => UnknownDescriptor,
Registration 5 => RegistrationDescriptor,
DataStreamAlignment 6 => UnknownDescriptor,
TargetBackgroundGrid 7 => UnknownDescriptor,
VideoWindow 8 => UnknownDescriptor,
CA 9 => UnknownDescriptor,
ISO639Language 10 => UnknownDescriptor,
SystemClock 11 => UnknownDescriptor,
MultiplexBufferUtilization 12 => UnknownDescriptor,
Copyright 13 => UnknownDescriptor,
MaximumBitrate 14 => UnknownDescriptor,
PrivateDataIndicator 15 => UnknownDescriptor,
SmoothingBuffer 16 => UnknownDescriptor,
STD 17 => UnknownDescriptor,
IBP 18 => UnknownDescriptor,
IsoIec13818dash6 19...26 => UnknownDescriptor,
MPEG4Video 27 => UnknownDescriptor,
MPEG4Audio 28 => UnknownDescriptor,
IOD 29 => UnknownDescriptor,
SL 30 => UnknownDescriptor,
FMC 31 => UnknownDescriptor,
ExternalESID 32 => UnknownDescriptor,
MuxCode 33 => UnknownDescriptor,
FmxBufferSize 34 => UnknownDescriptor,
MultiplexBuffer 35 => UnknownDescriptor,
UserPrivate 64...255 => UnknownDescriptor,
}
}
pub struct DescriptorIter<'buf, Desc>
where
Desc: Descriptor<'buf>
{
buf: &'buf[u8],
phantom: marker::PhantomData<Desc>,
}
impl<'buf, Desc> DescriptorIter<'buf, Desc>
where
Desc: Descriptor<'buf>
{
pub fn new(buf: &'buf[u8]) -> DescriptorIter<'buf, Desc> {
DescriptorIter {
buf,
phantom: marker::PhantomData,
}
}
}
impl<'buf, Desc> Iterator for DescriptorIter<'buf, Desc>
where
Desc: Descriptor<'buf>
{
type Item = Result<Desc, DescriptorError>;
fn next(&mut self) -> Option<Self::Item> {
if self.buf.len() == 0 {
return None;
}
let tag = self.buf[0];
let len = self.buf[1] as usize;
let remaining_size = self.buf.len() - 2;
if len > remaining_size {
self.buf = &self.buf[0..0];
Some(Err(DescriptorError::NotEnoughData { tag, actual: remaining_size, expected: len }))
} else {
let (desc, rest) = self.buf.split_at(len+2);
self.buf = rest;
Some(Descriptor::from_bytes(desc))
}
}
}
#[derive(Debug,PartialEq)]
pub enum DescriptorError {
NotEnoughData { tag: u8, actual: usize, expected: usize },
TagTooLongForBuffer { taglen: usize, buflen: usize },
BufferTooShort { buflen: usize },
UnhandledTagValue(u8),
}
pub struct RegistrationDescriptor<'buf> {
pub buf: &'buf[u8],
}
impl<'buf> RegistrationDescriptor<'buf> {
pub const TAG: u8 = 5;
pub fn new(_tag: u8, buf: &'buf[u8]) -> Result<RegistrationDescriptor<'buf>, DescriptorError> {
if buf.len() < 4 {
Err(DescriptorError::NotEnoughData { tag: Self::TAG, actual: buf.len(), expected: 4 })
} else {
Ok(RegistrationDescriptor { buf })
}
}
pub fn format_identifier(&self) -> u32 {
u32::from(self.buf[0]) << 24
| u32::from(self.buf[1]) << 16
| u32::from(self.buf[2]) << 8
| u32::from(self.buf[3])
}
pub fn additional_identification_info(&self) -> &[u8] {
&self.buf[4..]
}
}
impl<'buf> fmt::Debug for RegistrationDescriptor<'buf> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(),fmt::Error> {
f.debug_struct("RegistrationDescriptor")
.field("format_identifier", &self.format_identifier())
.field("additional_identification_info", &format!("{:x}", self.additional_identification_info().as_hex()))
.finish()
}
}
#[cfg(test)]
mod test {
use data_encoding::hex;
use super::*;
#[test]
fn descriptor() {
let data = hex::decode(b"050443554549").unwrap();
let desc = CoreDescriptors::from_bytes(&data).unwrap();
assert_matches!(desc, CoreDescriptors::Registration(RegistrationDescriptor{ buf: b"CUEI" } ));
}
}