asn1_cereal/ber/
stream.rs

1//! A `SAXParser` inspired stream parser and encoder for ber streams.
2//!
3//! Given a struct that implements `StreamDecodee`, a `StreamDecoder` can be used to
4//! decode the stream, calling each function in the `StreamDecodee` trait as they
5//! are encountered.
6//!
7//! The `StreamEncoder` struct is also provided, which itself implements the
8//! `StreamDecodee` trait. This allows you to encode an ASN.1 stream using
9//! the `StreamDecodee` interface as the caller.
10
11use tag;
12use err;
13use byte;
14
15use std::cmp::Ordering;
16use std::io;
17
18/// This trait provides a `SAXParser` inspired interface for parsing ASN.1 streams.
19///
20/// If it were implemented, the `ParseResult` return types would be used to
21/// provide feedback on whether parsing of that element was successful.
22pub trait StreamDecodee {
23  /// This function is called when an ASN.1 tag is encountered. In other
24  /// words, at the start of an ASN.1 element.
25  fn start_element(&mut self, _: tag::Tag, _: tag::Len) -> ParseResult {
26    ParseResult::Ok
27  }
28
29  /// This function is called when an ASN.1 element has finished decoding.
30  /// Note that this is also called for all elements, even after a primitive()
31  /// call. For this reason, you may need to check the constructed flag in some
32  /// cases.
33  fn end_element(&mut self, _: tag::Tag, _: tag::Len) -> ParseResult {
34    ParseResult::Ok
35  }
36
37  // FIXME: Currently it's the function's responsibility to decode the element
38  // with the correct amounts of bytes. Without heap allocation, this might be
39  // the only way.
40  /// This function is called when a primitive element is encountered. Note that both
41  /// start_element and end_element are called before/after this function.
42  fn primitive<I: Iterator<Item=io::Result<u8>>>(&mut self, reader: &mut byte::ByteReader<I>,
43      len: tag::LenNum) -> ParseResult {
44    for _ in 0..len {
45      if let Err(e) = reader.read() {
46        return e.into();
47      }
48    }
49    ParseResult::Ok
50  }
51
52  /// This function would be called when a recoverable decode error occurs, however
53  /// currently nothing calls this.
54  fn warning(_: err::DecodeError) -> ParseResult {
55    ParseResult::Stop
56  }
57
58  /// This function would be called when a fatal decoding error occurs, however 
59  /// currently nothing calls this.
60  fn error(_: err::DecodeError) {
61  }
62}
63
64/// A decoder that calls into a struct implementing the `StreamDecodee` trait,
65/// similar to a `SAXParser`.
66pub struct StreamDecoder<'a, I: Iterator<Item=io::Result<u8>>, S: StreamDecodee + 'a> {
67  /// Internal reader with an included byte counter.
68  reader: byte::ByteReader<I>,
69  /// Object implementing StreamDecodee trait, functions are called when
70  /// specific things are found in the ASN.1 stream.
71  decodee: &'a mut S,
72}
73
74impl<'a, I: Iterator<Item=io::Result<u8>>, S: StreamDecodee> StreamDecoder<'a, I, S> {
75  pub fn new<R: Into<byte::ByteReader<I>>>(reader: R, decodee: &'a mut S) -> Self {
76    StreamDecoder {
77      reader: reader.into(),
78      decodee: decodee,
79    }
80  }
81
82  /// Decode an asn1 element.
83  pub fn decode(&mut self) -> Result<(), err::DecodeError> {
84    self._decode().and(Ok(()))
85  }
86
87  // FIXME: Convert explicit decoded_len to use diff of internal reader count.
88  /// Internal decode function.
89  fn _decode(&mut self) -> Result<(tag::Tag, tag::Len), err::DecodeError> {
90    // Decode tag.
91    let (tag, len) = try!(tag::read_taglen(&mut self.reader));
92    let post_tag_count: tag::LenNum  = self.reader.count;
93
94    // Call the decodee start element callback;
95    self.decodee.start_element(tag, len);
96
97
98    // If this type is constructed, decode child element..
99    if tag.constructed {
100      // Loop over child elements.
101      loop {
102        let decoded_len = self.reader.count - post_tag_count;
103        // Compare decoded length with length in tag.
104        // Put this first to handle zero-length elements.
105        match len.partial_cmp(&decoded_len) {
106          // Return an error when we've decoded too much.
107          Some(Ordering::Less) => return Err(err::DecodeError::GreaterLen),
108          // Finish loop when equal, we must be finished.
109          Some(Ordering::Equal) => break,
110          // Continue when we are still decoding, or using indefinite
111          // length encoding.
112          Some(Ordering::Greater) | None => {},
113        };
114
115        // Decode each child element.
116        let (child_tag, child_len) = try!(self._decode());
117
118        // If applicable, identify end of indefinite length encoding.
119        // When decoding indefinite length encoding, stop on '00 00'
120        // tag.
121        if child_len == tag::Len::Def(0) &&
122           child_tag.class == tag::Class::Universal &&
123           child_tag.tagnum == 0 {
124          break;
125        }
126      }
127    // Otherwise decode primitive value.
128    } else {
129      let len_num = try!(match len {
130        tag::Len::Def(l) => Ok(l),
131        tag::Len::Indef =>
132          Err(err::DecodeError::PrimIndef),
133      });
134
135      // Call decodee primitive decode callback.
136      self.decodee.primitive(&mut self.reader, len_num);
137
138      // Calculate decoded length.
139      let decoded_len = self.reader.count - post_tag_count;
140      // Ensure the exact amout of bytes was decoded.
141      match len.partial_cmp(&decoded_len) {
142        Some(Ordering::Less) => return Err(err::DecodeError::GreaterLen),
143        Some(Ordering::Greater) => return Err(err::DecodeError::SmallerLen),
144        _ => {},
145      }
146    }
147
148    // Call decodee end element callback.
149    self.decodee.end_element(tag, len);
150
151    // Return decoded + tag_len, which is total decoded length.
152    Ok((tag, len))
153  }
154}
155
156/// A stream encoder that implements `StreamDecodee`. Using this,
157/// a ASN.1 stream can be written using a `SAXParser` style interface.
158pub struct StreamEncoder<W: io::Write> {
159  writer: byte::ByteWriter<W>
160}
161
162impl<W: io::Write> StreamEncoder<W> {
163  pub fn new<T: Into<byte::ByteWriter<W>>>(writer: T) -> Self {
164    StreamEncoder {
165      writer: writer.into(),
166    }
167  }
168}
169
170impl<W: io::Write> StreamDecodee for StreamEncoder<W> {
171  fn start_element(&mut self, tag: tag::Tag, len: tag::Len) -> ParseResult {
172    if let Err(e) = tag::write_taglen(tag, len, &mut self.writer) {
173      e.into()
174    } else {
175      ParseResult::Ok
176    }
177  }
178
179  fn end_element(&mut self, _: tag::Tag, _: tag::Len) -> ParseResult {
180    ParseResult::Ok
181  }
182
183  fn primitive<I: Iterator<Item=io::Result<u8>>>(&mut self, reader: &mut byte::ByteReader<I>,
184      len: tag::LenNum) -> ParseResult {
185    for _ in 0..len {
186      // Read a byte and write a byte.
187      match reader.read() {
188        Ok(byte) => if let Err(e) = self.writer.write_byte(byte) {
189          return e.into()
190        },
191        Err(e) => return e.into(),
192      };
193    }
194    ParseResult::Ok
195  }
196}
197
198
199// FIXME: This seems to have two mixed meanings, perhaps split it?
200/// The result of parsing after a callback on a `StreamDecodee`.
201///
202/// If it were implemented, this would provide feedback to the Decoder/Parser.
203pub enum ParseResult {
204  /// Everything went okay.
205  Ok,
206  /// Decoding should stop.
207  Stop,
208  /// Decoding should skip next element.
209  Skip,
210  /// An error occured decoding an element.
211  DecodeError(err::DecodeError),
212  /// An error occured encoding an element.
213  EncodeError(err::EncodeError),
214  /// An IO error occured.
215  IO(io::Error),
216}
217
218impl From<err::DecodeError> for ParseResult {
219  fn from(err: err::DecodeError) -> Self {
220    ParseResult::DecodeError(err)
221  }
222}
223
224impl From<err::EncodeError> for ParseResult {
225  fn from(err: err::EncodeError) -> Self {
226    ParseResult::EncodeError(err)
227  }
228}
229
230impl From<io::Error> for ParseResult {
231  fn from(err: io::Error) -> Self {
232    ParseResult::IO(err)
233  }
234}