asn1_rs/from_ber.rs
1use core::convert::{TryFrom, TryInto};
2use core::fmt::Display;
3
4use nom::error::ParseError;
5use nom::Input as _;
6use nom::{Err, IResult};
7
8use crate::ber::{GetObjectContent, MAX_RECURSION};
9use crate::debug::macros::log_error;
10use crate::debug::trace_input;
11use crate::{Any, BerError, BerMode, DynTagged, Error, Header, Input, ParseResult};
12
13/// Base trait for BER object parsers
14///
15/// # Notes
16///
17/// *This trait might become deprecated soon! Instead of this one, implement trait [`BerParser`].*
18///
19/// Library authors should usually not directly implement this trait, but should prefer implementing the
20/// [`TryFrom<Any>`] trait,
21/// which offers greater flexibility and provides an equivalent `FromBer` implementation for free.
22///
23/// # Examples
24///
25/// ```
26/// use asn1_rs::{Any, Result, Tag};
27/// use std::convert::TryFrom;
28///
29/// // The type to be decoded
30/// #[derive(Clone, Copy, Debug, PartialEq, Eq)]
31/// pub struct MyType(pub u32);
32///
33/// impl<'a> TryFrom<Any<'a>> for MyType {
34/// type Error = asn1_rs::Error;
35///
36/// fn try_from(any: Any<'a>) -> Result<MyType> {
37/// any.tag().assert_eq(Tag::Integer)?;
38/// // for this fictive example, the type contains the number of characters
39/// let n = any.data.len() as u32;
40/// Ok(MyType(n))
41/// }
42/// }
43///
44/// // The above code provides a `FromBer` implementation for free.
45///
46/// // Example of parsing code:
47/// use asn1_rs::FromBer;
48///
49/// let input = &[2, 1, 2];
50/// // Objects can be parsed using `from_ber`, which returns the remaining bytes
51/// // and the parsed object:
52/// let (rem, my_type) = MyType::from_ber(input).expect("parsing failed");
53/// ```
54pub trait FromBer<'a, E = Error>: Sized {
55 /// Attempt to parse input bytes into a BER object
56 fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, E>;
57}
58
59impl<'a, T, E> FromBer<'a, E> for T
60where
61 T: TryFrom<Any<'a>, Error = E>,
62 E: From<Error>,
63{
64 fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, T, E> {
65 let (i, any) = Any::from_ber(bytes).map_err(Err::convert)?;
66 match any.try_into().map_err(Err::Error) {
67 Ok(result) => Ok((i, result)),
68 Err(err) => {
69 log_error!(
70 "≠ Conversion from Any to {} failed",
71 core::any::type_name::<T>()
72 );
73 Err(err)
74 }
75 }
76 }
77}
78
79/// Base trait for BER object parsers
80///
81/// Implementers should provide a definition for the following:
82/// - method [`from_ber_content`](BerParser::from_ber_content): Parse BER content, given a header and data
83/// - trait [`DynTagged`]
84///
85/// This trait can be automatically derived from a `struct` using the [`BerParserSequence`](crate::BerParserSequence)
86/// or [`BerParserSet`](crate::BerParserSet) custom derive attributes.
87pub trait BerParser<'i>
88where
89 Self: Sized,
90 Self: DynTagged,
91{
92 /// The Error type for parsing errors.
93 type Error: Display + ParseError<Input<'i>> + From<BerError<Input<'i>>>;
94
95 /// Attempt to parse a new BER object from data.
96 ///
97 /// Header tag must match expected tag
98 fn parse_ber(input: Input<'i>) -> IResult<Input<'i>, Self, Self::Error> {
99 trace_input("BerParser::parse_ber", |input| {
100 let (rem, header) = Header::parse_ber(input.clone()).map_err(Err::convert)?;
101 if !Self::accept_tag(header.tag) {
102 return Err(Err::Error(
103 // FIXME: expected Tag is `None`, so the error will not be helpful
104 BerError::unexpected_tag(input, None, header.tag).into(),
105 ));
106 }
107 let (rem, data) =
108 BerMode::get_object_content(&header, rem, MAX_RECURSION).map_err(Err::convert)?;
109 let (_, obj) = trace_input("BerParser::from_ber_content", |i| {
110 // wrap from_ber_content function to display better errors, if any
111 Self::from_ber_content(&header, i)
112 })(data)
113 .map_err(Err::convert)?;
114 Ok((rem, obj))
115 })(input)
116 }
117
118 /// Parse a new BER object from header and data.
119 ///
120 /// `input` length is guaranteed to match `header` length (definite or indefinite)
121 ///
122 /// Note: in this method, implementers should *not* check header tag (which can be
123 /// different from the usual object tag when using IMPLICIT tagging, for ex.).
124 fn from_ber_content(
125 header: &'_ Header<'i>,
126 input: Input<'i>,
127 ) -> IResult<Input<'i>, Self, Self::Error>;
128
129 fn parse_ber_optional(input: Input<'i>) -> IResult<Input<'i>, Option<Self>, Self::Error> {
130 if input.input_len() == 0 {
131 return Ok((input, None));
132 }
133 let (rem, header) = Header::parse_ber(input.clone()).map_err(Err::convert)?;
134 if !Self::accept_tag(header.tag) {
135 return Ok((input, None));
136 }
137 let (rem, data) =
138 BerMode::get_object_content(&header, rem, MAX_RECURSION).map_err(Err::convert)?;
139 let (_, obj) = Self::from_ber_content(&header, data).map_err(Err::convert)?;
140 Ok((rem, Some(obj)))
141 }
142
143 /// Parse object header (validating tag) and return header and content as `Input`
144 fn parse_ber_as_input(
145 input: Input<'i>,
146 ) -> IResult<Input<'i>, (Header<'i>, Input<'i>), Self::Error> {
147 trace_input("BerParser::parse_ber_as_input", |input| {
148 let (rem, header) = Header::parse_ber(input.clone()).map_err(Err::convert)?;
149 if !Self::accept_tag(header.tag) {
150 return Err(Err::Error(
151 // FIXME: expected Tag is `None`, so the error will not be helpful
152 BerError::unexpected_tag(input, None, header.tag).into(),
153 ));
154 }
155 let (rem, data) =
156 BerMode::get_object_content(&header, rem, MAX_RECURSION).map_err(Err::convert)?;
157
158 Ok((rem, (header, data)))
159 })(input)
160 }
161}
162
163// NOTE: function useful during transition to Input. Remove this after
164pub(crate) fn wrap_ber_parser<'i, F, T>(mut f: F) -> impl FnMut(&'i [u8]) -> ParseResult<'i, T>
165where
166 F: FnMut(Input<'i>) -> IResult<Input<'i>, T, BerError<Input<'i>>>,
167{
168 move |i: &[u8]| {
169 let input = Input::from_slice(i);
170 match f(input) {
171 Ok((rem, res)) => Ok((rem.into_bytes(), res)),
172 Err(e) => Err(Err::convert(e)),
173 }
174 }
175}