1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
//! Decoding BER-encoded data.
//!
//! _Note: This guide is still work in progress and will be extended._
//!
//! Data encoded in BER is a stream of nested values for which the length
//! may or may not be known. Primitive values, for which the length _is_
//! always known, contain a sequence of octets representing a value of
//! a certain type. Constructed values are a sequence of other values. These
//! values may either have a pre-determined length or a bounded by a special
//! value marking the end of the sequence. The overall stream of data can be
//! viewed as the content of a constructed value bounded by the end of the
//! stream.
//!
//! In the *ber* crate, the content of a value is parsed through functions.
//! These functions are given a mutable reference to the value’s content and
//! are tasked with reading and processing all the content of the value. It
//! does so by calling methods on the content value. Some of these methods
//! dive into nested values. They require their own parsing functions and
//! take them as function arguments such as closures.
//!
//! An example will make this concept more clear. Let’s say we have the
//! following ASN.1 specifiction:
//!
//! ```text
//! EncapsulatedContentInfo ::= SEQUENCE {
//! eContentType ContentType,
//! eContent [0] EXPLICIT OCTET STRING OPTIONAL
//! }
//!
//! ContentType ::= OBJECT IDENTIFIER
//! ```
//!
//! Using the types provided by the *ber* crate for object identifiers and
//! octet strings, this definition is easily mapped into a Rust struct:
//!
//! ```
//! use bcder::{Oid, OctetString};
//!
//! pub struct EncapsulatedContentInfo {
//! content_type: Oid,
//! content: Option<OctetString>,
//! }
//! ```
//!
//! By convention, the decoder function is called `take_from`. It looks like
//! this:
//!
//! ```
//! # use bcder::{Oid, OctetString};
//! use bcder::Tag;
//! use bcder::decode;
//!
//! # pub struct EncapsulatedContentInfo {
//! # content_type: Oid,
//! # content: Option<OctetString>,
//! # }
//! #
//! impl EncapsulatedContentInfo {
//! pub fn take_from<S: decode::Source>(
//! cons: &mut decode::Constructed<S>
//! ) -> Result<Self, S::Err> {
//! cons.take_sequence(|cons| {
//! Ok(EncapsulatedContentInfo {
//! content_type: Oid::take_from(cons)?,
//! content: cons.take_opt_constructed_if(Tag::CTX_0, |cons| {
//! OctetString::take_from(cons)
//! })?
//! })
//! })
//! }
//! }
//! ```
//!
//! _TODO: Elaborate._
//!
//!
//! Some types are used with an implicit tag, i.e., the encoding uses
//! a different tag than what would normally it would. For these types, a
//! function should be provided that only decodes the content. Depending on
//! the encoding used for the type, this function should be `from_primitive`,
//! `from_constructed`, or `from_content` for types that always use
//! primitive encoding, always constructed encoding, or can appear in both
//! encodings, respectively.
//!
//! As our example type always uses constructed encoding, its content
//! decoder would look like this:
//!
//! ```
//! # use bcder::{Oid, OctetString};
//! use bcder::Tag;
//! use bcder::decode;
//!
//! # pub struct EncapsulatedContentInfo {
//! # content_type: Oid,
//! # content: Option<OctetString>,
//! # }
//! #
//! impl EncapsulatedContentInfo {
//! pub fn from_constructed<S: decode::Source>(
//! cons: &mut decode::Constructed<S>
//! ) -> Result<Self, S::Err> {
//! Ok(EncapsulatedContentInfo {
//! content_type: Oid::take_from(cons)?,
//! content: cons.take_opt_constructed_if(Tag::CTX_0, |cons| {
//! OctetString::take_from(cons)
//! })?
//! })
//! }
//! }
//! ```
//!
//! _TODO: Elaborate._