use bytes::Bytes;
use smallvec::SmallVec;
use crate::captured::Captured;
use crate::int::{Integer, Unsigned};
use crate::length::Length;
use crate::mode::Mode;
use crate::tag::Tag;
use super::error::Error;
use super::source::{CaptureSource, LimitedSource, Source};
pub enum Content<'a, S: 'a> {
Primitive(Primitive<'a, S>),
Constructed(Constructed<'a, S>)
}
impl<'a, S: Source + 'a> Content<'a, S> {
fn exhausted(self) -> Result<(), S::Err> {
match self {
Content::Primitive(inner) => inner.exhausted(),
Content::Constructed(mut inner) => inner.exhausted()
}
}
pub fn mode(&self) -> Mode {
match *self {
Content::Primitive(ref inner) => inner.mode(),
Content::Constructed(ref inner) => inner.mode()
}
}
pub fn is_primitive(&self) -> bool {
match *self {
Content::Primitive(_) => true,
Content::Constructed(_) => false,
}
}
pub fn is_constructed(&self) -> bool {
match *self {
Content::Primitive(_) => false,
Content::Constructed(_) => true,
}
}
pub fn as_primitive(&mut self) -> Result<&mut Primitive<'a, S>, S::Err> {
match *self {
Content::Primitive(ref mut inner) => Ok(inner),
Content::Constructed(_) => {
xerr!(Err(Error::Malformed.into()))
}
}
}
pub fn as_constructed(
&mut self
) -> Result<&mut Constructed<'a, S>, S::Err> {
match *self {
Content::Primitive(_) => {
xerr!(Err(Error::Malformed.into()))
}
Content::Constructed(ref mut inner) => Ok(inner),
}
}
}
#[allow(clippy::wrong_self_convention)]
impl<'a, S: Source + 'a> Content<'a, S> {
pub fn to_u8(&mut self) -> Result<u8, S::Err> {
if let Content::Primitive(ref mut prim) = *self {
prim.to_u8()
}
else {
xerr!(Err(Error::Malformed.into()))
}
}
pub fn skip_u8_if(&mut self, expected: u8) -> Result<(), S::Err> {
let res = self.to_u8()?;
if res == expected {
Ok(())
}
else {
xerr!(Err(Error::Malformed.into()))
}
}
pub fn to_u16(&mut self) -> Result<u16, S::Err> {
if let Content::Primitive(ref mut prim) = *self {
prim.to_u16()
}
else {
xerr!(Err(Error::Malformed.into()))
}
}
pub fn to_u32(&mut self) -> Result<u32, S::Err> {
if let Content::Primitive(ref mut prim) = *self {
prim.to_u32()
}
else {
xerr!(Err(Error::Malformed.into()))
}
}
pub fn to_u64(&mut self) -> Result<u64, S::Err> {
if let Content::Primitive(ref mut prim) = *self {
prim.to_u64()
}
else {
xerr!(Err(Error::Malformed.into()))
}
}
pub fn to_null(&mut self) -> Result<(), S::Err> {
if let Content::Primitive(ref mut prim) = *self {
prim.to_null()
}
else {
xerr!(Err(Error::Malformed.into()))
}
}
}
pub struct Primitive<'a, S: 'a> {
source: &'a mut LimitedSource<S>,
mode: Mode,
}
impl<'a, S: 'a> Primitive<'a, S> {
fn new(source: &'a mut LimitedSource<S>, mode: Mode) -> Self {
Primitive { source, mode }
}
pub fn mode(&self) -> Mode {
self.mode
}
pub fn set_mode(&mut self, mode: Mode) {
self.mode = mode
}
}
#[allow(clippy::wrong_self_convention)]
impl<'a, S: Source + 'a> Primitive<'a, S> {
pub fn to_bool(&mut self) -> Result<bool, S::Err> {
let res = self.take_u8()?;
if self.mode != Mode::Ber {
match res {
0 => Ok(false),
0xFF => Ok(true),
_ => {
xerr!(Err(Error::Malformed.into()))
}
}
}
else {
Ok(res != 0)
}
}
pub fn to_i8(&mut self) -> Result<i8, S::Err> {
Integer::i8_from_primitive(self)
}
pub fn to_i16(&mut self) -> Result<i16, S::Err> {
Integer::i16_from_primitive(self)
}
pub fn to_i32(&mut self) -> Result<i32, S::Err> {
Integer::i32_from_primitive(self)
}
pub fn to_i64(&mut self) -> Result<i64, S::Err> {
Integer::i64_from_primitive(self)
}
pub fn to_i128(&mut self) -> Result<i128, S::Err> {
Integer::i128_from_primitive(self)
}
pub fn to_u8(&mut self) -> Result<u8, S::Err> {
Unsigned::u8_from_primitive(self)
}
pub fn to_u16(&mut self) -> Result<u16, S::Err> {
Unsigned::u16_from_primitive(self)
}
pub fn to_u32(&mut self) -> Result<u32, S::Err> {
Unsigned::u32_from_primitive(self)
}
pub fn to_u64(&mut self) -> Result<u64, S::Err> {
Unsigned::u64_from_primitive(self)
}
pub fn to_u128(&mut self) -> Result<u64, S::Err> {
Unsigned::u64_from_primitive(self)
}
pub fn to_null(&mut self) -> Result<(), S::Err> {
Ok(())
}
}
impl<'a, S: Source + 'a> Primitive<'a, S> {
pub fn remaining(&self) -> usize {
self.source.limit().unwrap()
}
pub fn skip_all(&mut self) -> Result<(), S::Err> {
self.source.skip_all()
}
pub fn take_all(&mut self) -> Result<Bytes, S::Err> {
self.source.take_all()
}
pub fn slice_all(&mut self) -> Result<&[u8], S::Err> {
let remaining = self.remaining();
self.source.request(remaining)?;
Ok(&self.source.slice()[..remaining])
}
fn exhausted(self) -> Result<(), S::Err> {
self.source.exhausted()
}
}
impl<'a> Primitive<'a, &'a [u8]> {
pub fn decode_slice<F, T>(
source: &'a [u8],
mode: Mode,
op: F
) -> Result<T, Error>
where F: FnOnce(&mut Primitive<&[u8]>) -> Result<T, Error> {
let mut lim = LimitedSource::new(source);
lim.set_limit(Some(source.len()));
let mut prim = Primitive::new(&mut lim, mode);
let res = op(&mut prim)?;
prim.exhausted()?;
Ok(res)
}
}
impl<'a, S: Source + 'a> Source for Primitive<'a, S> {
type Err = S::Err;
fn request(&mut self, len: usize) -> Result<usize, Self::Err> {
self.source.request(len)
}
fn advance(&mut self, len: usize) -> Result<(), Self::Err> {
self.source.advance(len)
}
fn slice(&self) -> &[u8] {
self.source.slice()
}
fn bytes(&self, start: usize, end: usize) -> Bytes {
self.source.bytes(start, end)
}
}
#[derive(Debug)]
pub struct Constructed<'a, S: 'a> {
source: &'a mut LimitedSource<S>,
state: State,
mode: Mode,
}
impl<'a, S: Source + 'a> Constructed<'a, S> {
fn new(
source: &'a mut LimitedSource<S>,
state: State,
mode: Mode
) -> Self {
Constructed { source, state, mode }
}
pub fn decode<F, T>(source: S, mode: Mode, op: F) -> Result<T, S::Err>
where F: FnOnce(&mut Constructed<S>) -> Result<T, S::Err> {
let mut source = LimitedSource::new(source);
let mut cons = Constructed::new(&mut source, State::Unbounded, mode);
let res = op(&mut cons)?;
cons.exhausted()?;
Ok(res)
}
pub fn mode(&self) -> Mode {
self.mode
}
pub fn set_mode(&mut self, mode: Mode) {
self.mode = mode
}
}
impl<'a, S: Source + 'a> Constructed<'a, S> {
fn exhausted(&mut self) -> Result<(), S::Err> {
match self.state {
State::Done => Ok(()),
State::Definite => {
self.source.exhausted()
}
State::Indefinite => {
let (tag, constructed) = Tag::take_from(self.source)?;
if tag != Tag::END_OF_VALUE || constructed
|| !Length::take_from(self.source, self.mode)?.is_zero()
{
xerr!(Err(Error::Malformed.into()))
}
else {
Ok(())
}
}
State::Unbounded => Ok(())
}
}
fn is_exhausted(&self) -> bool {
match self.state {
State::Definite => {
self.source.limit().unwrap() == 0
}
State::Indefinite => false,
State::Done => true,
State::Unbounded => false,
}
}
fn process_next_value<F, T>(
&mut self,
expected: Option<Tag>,
op: F
) -> Result<Option<T>, S::Err>
where F: FnOnce(Tag, &mut Content<S>) -> Result<T, S::Err> {
if self.is_exhausted() {
return Ok(None)
}
let (tag, constructed) = if let Some(expected) = expected {
(
expected,
match expected.take_from_if(self.source)? {
Some(compressed) => compressed,
None => return Ok(None)
}
)
}
else {
Tag::take_from(self.source)?
};
let length = Length::take_from(self.source, self.mode)?;
if tag == Tag::END_OF_VALUE {
if let State::Indefinite = self.state {
if constructed {
xerr!(return Err(Error::Malformed.into()))
}
if !length.is_zero() {
xerr!(return Err(Error::Malformed.into()))
}
self.state = State::Done;
return Ok(None)
}
else {
xerr!(return Err(Error::Malformed.into()))
}
}
match length {
Length::Definite(len) => {
let old_limit = self.source.limit_further(Some(len));
let res = {
let mut content = if constructed {
if self.mode == Mode::Cer {
xerr!(return Err(Error::Malformed.into()))
}
Content::Constructed(
Constructed::new(
self.source, State::Definite, self.mode
)
)
}
else {
Content::Primitive(
Primitive::new(self.source, self.mode)
)
};
let res = op(tag, &mut content)?;
content.exhausted()?;
res
};
self.source.set_limit(old_limit.map(|x| x - len));
Ok(Some(res))
}
Length::Indefinite => {
if !constructed || self.mode == Mode::Der {
xerr!(return Err(Error::Malformed.into()))
}
let mut content = Content::Constructed(
Constructed::new(self.source, State::Indefinite, self.mode)
);
let res = op(tag, &mut content)?;
content.exhausted()?;
Ok(Some(res))
}
}
}
}
impl<'a, S: Source + 'a> Constructed<'a, S> {
pub fn take_value<F, T>(&mut self, op: F) -> Result<T, S::Err>
where F: FnOnce(Tag, &mut Content<S>) -> Result<T, S::Err> {
match self.process_next_value(None, op)? {
Some(res) => Ok(res),
None => {
xerr!(Err(Error::Malformed.into()))
}
}
}
pub fn take_opt_value<F, T>(&mut self, op: F) -> Result<Option<T>, S::Err>
where F: FnOnce(Tag, &mut Content<S>) -> Result<T, S::Err> {
self.process_next_value(None, op)
}
pub fn take_value_if<F, T>(
&mut self,
expected: Tag,
op: F
) -> Result<T, S::Err>
where F: FnOnce(&mut Content<S>) -> Result<T, S::Err> {
let res = self.process_next_value(Some(expected), |_, content| {
op(content)
})?;
match res {
Some(res) => Ok(res),
None => {
xerr!(Err(Error::Malformed.into()))
}
}
}
pub fn take_opt_value_if<F, T>(
&mut self,
expected: Tag,
op: F
) -> Result<Option<T>, S::Err>
where F: FnOnce(&mut Content<S>) -> Result<T, S::Err> {
self.process_next_value(Some(expected), |_, content| op(content))
}
pub fn take_constructed<F, T>(&mut self, op: F) -> Result<T, S::Err>
where F: FnOnce(Tag, &mut Constructed<S>) -> Result<T, S::Err> {
match self.take_opt_constructed(op)? {
Some(res) => Ok(res),
None => {
xerr!(Err(Error::Malformed.into()))
}
}
}
pub fn take_opt_constructed<F, T>(
&mut self,
op: F
) -> Result<Option<T>, S::Err>
where F: FnOnce(Tag, &mut Constructed<S>) -> Result<T, S::Err> {
self.process_next_value(None, |tag, content| {
op(tag, content.as_constructed()?)
})
}
pub fn take_constructed_if<F, T>(
&mut self,
expected: Tag,
op: F
) -> Result<T, S::Err>
where F: FnOnce(&mut Constructed<S>) -> Result<T, S::Err> {
match self.take_opt_constructed_if(expected, op)? {
Some(res) => Ok(res),
None => {
xerr!(Err(Error::Malformed.into()))
}
}
}
pub fn take_opt_constructed_if<F, T>(
&mut self,
expected: Tag,
op: F
) -> Result<Option<T>, S::Err>
where F: FnOnce(&mut Constructed<S>) -> Result<T, S::Err> {
self.process_next_value(Some(expected), |_, content| {
op(content.as_constructed()?)
})
}
pub fn take_primitive<F, T>(&mut self, op: F) -> Result<T, S::Err>
where F: FnOnce(Tag, &mut Primitive<S>) -> Result<T, S::Err> {
match self.take_opt_primitive(op)? {
Some(res) => Ok(res),
None => {
xerr!(Err(Error::Malformed.into()))
}
}
}
pub fn take_opt_primitive<F, T>(
&mut self,
op: F
) -> Result<Option<T>, S::Err>
where F: FnOnce(Tag, &mut Primitive<S>) -> Result<T, S::Err> {
self.process_next_value(None, |tag, content| {
op(tag, content.as_primitive()?)
})
}
pub fn take_primitive_if<F, T>(
&mut self,
expected: Tag,
op: F
) -> Result<T, S::Err>
where F: FnOnce(&mut Primitive<S>) -> Result<T, S::Err> {
match self.take_opt_primitive_if(expected, op)? {
Some(res) => Ok(res),
None => {
xerr!(Err(Error::Malformed.into()))
}
}
}
pub fn take_opt_primitive_if<F, T>(
&mut self,
expected: Tag,
op: F
) -> Result<Option<T>, S::Err>
where F: FnOnce(&mut Primitive<S>) -> Result<T, S::Err> {
self.process_next_value(Some(expected), |_, content| {
op(content.as_primitive()?)
})
}
pub fn capture<F>(&mut self, op: F) -> Result<Captured, S::Err>
where
F: FnOnce(
&mut Constructed<CaptureSource<LimitedSource<S>>>
) -> Result<(), S::Err>
{
let limit = self.source.limit();
let mut source = LimitedSource::new(CaptureSource::new(self.source));
source.set_limit(limit);
{
let mut constructed = Constructed::new(
&mut source, self.state, self.mode
);
op(&mut constructed)?;
self.state = constructed.state;
}
Ok(Captured::new(source.unwrap().into_bytes(), self.mode))
}
pub fn capture_one(&mut self) -> Result<Captured, S::Err> {
self.capture(|cons| {
match cons.skip_one()? {
Some(()) => Ok(()),
None => {
xerr!(Err(Error::Malformed.into()))
}
}
})
}
pub fn capture_all(&mut self) -> Result<Captured, S::Err> {
self.capture(|cons| cons.skip_all())
}
pub fn skip_opt<F>(&mut self, mut op: F) -> Result<Option<()>, S::Err>
where F: FnMut(Tag, bool, usize) -> Result<(), S::Err> {
if self.is_exhausted() {
return Ok(None)
}
let mut stack = SmallVec::<[Option<Option<usize>>; 4]>::new();
loop {
let (tag, constructed) = Tag::take_from(self.source)?;
let length = Length::take_from(self.source, self.mode)?;
if !constructed {
if tag == Tag::END_OF_VALUE {
if length != Length::Definite(0) {
xerr!(return Err(Error::Malformed.into()))
}
match stack.pop() {
Some(None) => { }
None => {
if self.state == State::Indefinite {
self.state = State::Done;
return Ok(None)
}
else {
xerr!(return Err(Error::Malformed.into()))
}
}
_ => xerr!(return Err(Error::Malformed.into()))
}
}
else {
if let Length::Definite(len) = length {
op(tag, constructed, stack.len())?;
self.source.advance(len)?;
}
else {
xerr!(return Err(Error::Malformed.into()));
}
}
}
else if let Length::Definite(len) = length {
op(tag, constructed, stack.len())?;
stack.push(Some(match self.source.limit() {
Some(limit) => {
match limit.checked_sub(len) {
Some(len) => Some(len),
None => {
xerr!(return Err(Error::Malformed.into()));
}
}
}
None => None,
}));
self.source.set_limit(Some(len));
}
else {
op(tag, constructed, stack.len())?;
stack.push(None);
continue;
}
loop {
if stack.is_empty() {
return Ok(Some(()))
}
else if self.source.limit() == Some(0) {
match stack.pop() {
Some(Some(limit)) => {
self.source.set_limit(limit)
}
Some(None) => {
xerr!(return Err(Error::Malformed.into()));
}
None => unreachable!(),
}
}
else {
break;
}
}
}
}
pub fn skip<F>(&mut self, op: F) -> Result<(), S::Err>
where F: FnMut(Tag, bool, usize) -> Result<(), S::Err> {
if self.skip_opt(op)? == None {
xerr!(Err(Error::Malformed.into()))
}
else {
Ok(())
}
}
pub fn skip_all(&mut self) -> Result<(), S::Err> {
while let Some(()) = self.skip_one()? { }
Ok(())
}
pub fn skip_one(&mut self) -> Result<Option<()>, S::Err> {
if self.is_exhausted() {
Ok(None)
}
else {
self.skip(|_, _, _| Ok(()))?;
Ok(Some(()))
}
}
}
impl<'a, S: Source + 'a> Constructed<'a, S> {
pub fn take_bool(&mut self) -> Result<bool, S::Err> {
self.take_primitive_if(Tag::BOOLEAN, |prim| prim.to_bool())
}
pub fn take_opt_bool(&mut self) -> Result<Option<bool>, S::Err> {
self.take_opt_primitive_if(Tag::BOOLEAN, |prim| prim.to_bool())
}
pub fn take_null(&mut self) -> Result<(), S::Err> {
self.take_primitive_if(Tag::NULL, |_| Ok(())).map(|_| ())
}
pub fn take_opt_null(&mut self) -> Result<(), S::Err> {
self.take_opt_primitive_if(Tag::NULL, |_| Ok(())).map(|_| ())
}
pub fn take_u8(&mut self) -> Result<u8, S::Err> {
self.take_primitive_if(Tag::INTEGER, |prim| prim.to_u8())
}
pub fn take_opt_u8(&mut self) -> Result<Option<u8>, S::Err> {
self.take_opt_primitive_if(Tag::INTEGER, |prim| prim.to_u8())
}
pub fn skip_u8_if(&mut self, expected: u8) -> Result<(), S::Err> {
self.take_primitive_if(Tag::INTEGER, |prim| {
let got = prim.take_u8()?;
if got != expected {
xerr!(Err(Error::Malformed.into()))
}
else {
Ok(())
}
})
}
pub fn skip_opt_u8_if(&mut self, expected: u8) -> Result<(), S::Err> {
self.take_opt_primitive_if(Tag::INTEGER, |prim| {
let got = prim.take_u8()?;
if got != expected {
xerr!(Err(Error::Malformed.into()))
}
else {
Ok(())
}
}).map(|_| ())
}
pub fn take_u16(&mut self) -> Result<u16, S::Err> {
self.take_primitive_if(Tag::INTEGER, |prim| prim.to_u16())
}
pub fn take_opt_u16(&mut self) -> Result<Option<u16>, S::Err> {
self.take_opt_primitive_if(Tag::INTEGER, |prim| prim.to_u16())
}
pub fn take_u32(&mut self) -> Result<u32, S::Err> {
self.take_primitive_if(Tag::INTEGER, |prim| prim.to_u32())
}
pub fn take_opt_u32(&mut self) -> Result<Option<u32>, S::Err> {
self.take_opt_primitive_if(Tag::INTEGER, |prim| prim.to_u32())
}
pub fn take_u64(&mut self) -> Result<u64, S::Err> {
self.take_primitive_if(Tag::INTEGER, |prim| prim.to_u64())
}
pub fn take_opt_u64(&mut self) -> Result<Option<u64>, S::Err> {
self.take_opt_primitive_if(Tag::INTEGER, |prim| prim.to_u64())
}
pub fn take_sequence<F, T>(&mut self, op: F) -> Result<T, S::Err>
where F: FnOnce(&mut Constructed<S>) -> Result<T, S::Err> {
self.take_constructed_if(Tag::SEQUENCE, op)
}
pub fn take_opt_sequence<F, T>(
&mut self,
op: F
) -> Result<Option<T>, S::Err>
where F: FnOnce(&mut Constructed<S>) -> Result<T, S::Err> {
self.take_opt_constructed_if(Tag::SEQUENCE, op)
}
pub fn take_set<F, T>(&mut self, op: F) -> Result<T, S::Err>
where F: FnOnce(&mut Constructed<S>) -> Result<T, S::Err> {
self.take_constructed_if(Tag::SET, op)
}
pub fn take_opt_set<F, T>(&mut self, op: F) -> Result<Option<T>, S::Err>
where F: FnOnce(&mut Constructed<S>) -> Result<T, S::Err> {
self.take_opt_constructed_if(Tag::SET, op)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum State {
Definite,
Indefinite,
Done,
Unbounded,
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn constructed_skip() {
Constructed::decode(
b"\x02\x01\x00\x02\x01\x00".as_ref(), Mode::Ber, |cons| {
cons.skip(|_, _, _| Ok(())).unwrap();
cons.skip(|_, _, _| Ok(())).unwrap();
Ok(())
}
).unwrap();
Constructed::decode(
b"\x30\x06\x02\x01\x00\x02\x01\x00\x02\x01\x00".as_ref(),
Mode::Ber,
|cons| {
cons.skip(|_, _, _| Ok(())).unwrap();
cons.skip(|_, _, _| Ok(())).unwrap();
Ok(())
}
).unwrap();
Constructed::decode(
b"\x30\x08\
\x30\x06\
\x02\x01\x00\x02\x01\x00\
\x02\x01\x00".as_ref(),
Mode::Ber,
|cons| {
cons.skip(|_, _, _| Ok(())).unwrap();
cons.skip(|_, _, _| Ok(())).unwrap();
Ok(())
}
).unwrap();
Constructed::decode(
b"\x30\x0A\
\x30\x80\
\x02\x01\x00\x02\x01\x00\
\0\0".as_ref(),
Mode::Ber,
|cons| {
cons.skip(|_, _, _| Ok(())).unwrap();
Ok(())
}
).unwrap();
}
}