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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
// Copyright 2021-2024 Shin Yoshida
//
// "GPL-3.0-only"
//
// This is part of BSN1
//
// BSN1 is free software: you can redistribute it and/or modify it under the terms of the
// GNU General Public License as published by the Free Software Foundation, version 3.
//
// BSN1 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with this program. If
// not, see <https://www.gnu.org/licenses/>.

#![deny(missing_docs)]
#![doc = include_str!("../README.md")]

mod ber;
mod ber_ref;
mod buffer;
mod contents;
mod contents_ref;
mod der;
mod der_ref;
mod id_tags;
mod identifier;
mod identifier_ref;
mod length;
mod length_buffer;
mod misc;

pub use ber::Ber;
pub use ber_ref::BerRef;
pub use buffer::Buffer;
pub use contents::Contents;
pub use contents_ref::ContentsRef;
pub use der::Der;
pub use der_ref::DerRef;
pub use id_tags::{ClassTag, PCTag, TagNumber};
pub use identifier::Id;
pub use identifier_ref::IdRef;
pub use length::Length;
use length_buffer::LengthBuffer;
use std::fmt;

/// Errors for this crate.
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
    /// The bytes finish before the last octet.
    UnterminatedBytes,
    /// The bytes include some redundant octet(s).
    /// ('ASN.1' does not allow such bytes.)
    RedundantBytes,
    /// Over flow is occurred to parse bytes as a number.
    OverFlow,
    /// 'Indefinite length' is used where not allowed.
    /// (It is only for BER of some type, but not for DER, nor for CER.)
    IndefiniteLength,
    /// The contents of 'EOC' of the 'Indefinite Length BER' must be empty.
    BadEoc,
    /// The contents include (an) invalid octet(s) at the end.
    ExtraContentsOctet,
    /// The identifier does not match to that of data type when deserialized.
    UnmatchedId,
    /// Invarid as UTF-8.
    InvalidUtf8,
    /// The contents of DER BOOLEAN must be 0x00 or 0xFF.
    InvalidDerBooleanContents,
    /// The key-value pair is invalid.
    InvalidKeyValuePair,
    /// IO Error for serialization/deserialization.
    ///
    /// Note that this error cannot be compared with others.
    /// `PartialEq::eq` always returns `false` for this error.
    Io(std::io::Error),
    /// Wrapper of [`anyhow::Error`].
    ///
    /// Note that this error cannot be compared with others.
    /// `PartialEq::eq` always returns `false` for this error.
    Anyhow(anyhow::Error),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::UnterminatedBytes => f.write_str("The bytes finish before the last octet."),
            Self::RedundantBytes => f.write_str("The bytes include some redundant octet(s)."),
            Self::OverFlow => f.write_str("Over flow is occurred to parse bytes as a number."),
            Self::IndefiniteLength => f.write_str("'Indefinite Length' is used where not allowed."),
            Self::BadEoc => f.write_str("'Indefinite Length BER' includes a bad 'EOC.'"),
            Self::ExtraContentsOctet => {
                f.write_str("Contents include (an) invlid octet(s) at the end.")
            }
            Self::UnmatchedId => f.write_str("The identifier does not match to that of data type."),
            Self::InvalidUtf8 => f.write_str("Invalid as UTF-8."),
            Self::InvalidDerBooleanContents => {
                f.write_str("The contents of DER BOOLEAN must be 0x00 or 0xFF.")
            }
            Self::InvalidKeyValuePair => f.write_str("SEQUENCE of key-value pair is required."),
            Self::Io(err) => err.fmt(f),
            Self::Anyhow(err) => err.fmt(f),
        }
    }
}

impl std::error::Error for Error {}

impl PartialEq for Error {
    fn eq(&self, other: &Self) -> bool {
        match self {
            Self::UnterminatedBytes => matches!(other, Self::UnterminatedBytes),
            Self::RedundantBytes => matches!(other, Self::RedundantBytes),
            Self::OverFlow => matches!(other, Self::OverFlow),
            Self::IndefiniteLength => matches!(other, Self::IndefiniteLength),
            Self::BadEoc => matches!(other, Self::BadEoc),
            Self::ExtraContentsOctet => matches!(other, Self::ExtraContentsOctet),
            Self::UnmatchedId => matches!(other, Self::UnmatchedId),
            Self::InvalidUtf8 => matches!(other, Self::InvalidUtf8),
            Self::InvalidDerBooleanContents => matches!(other, Self::InvalidDerBooleanContents),
            Self::InvalidKeyValuePair => matches!(other, Self::InvalidKeyValuePair),
            Self::Io(_) => false,
            Self::Anyhow(_) => false,
        }
    }
}

impl From<std::io::Error> for Error {
    fn from(err: std::io::Error) -> Self {
        Self::Io(err)
    }
}

impl From<anyhow::Error> for Error {
    fn from(err: anyhow::Error) -> Self {
        Self::Anyhow(err)
    }
}

impl Error {
    /// Consumes `self`, converting it into an [`anyhow::Error`].
    ///
    /// If `self` matches `Error::Anyhow`, returns the inner value;
    /// otherwise, wraps `self` and returns.
    pub fn into_anyhow(self) -> anyhow::Error {
        match self {
            Self::Anyhow(err) => err,
            _ => anyhow::Error::new(self),
        }
    }

    /// Returns a reference to the inner [`anyhow::Error`] if `self` is `Error::Anyhow`;
    /// otherwise, returns `None`.
    pub fn as_anyhow(&self) -> Option<&anyhow::Error> {
        match self {
            Self::Anyhow(err) => Some(err),
            _ => None,
        }
    }

    /// Consumes `self`, wrapping it with `context`.
    pub fn context<C>(self, context: C) -> Self
    where
        C: fmt::Display + Send + Sync + 'static,
    {
        self.into_anyhow().context(context).into()
    }

    /// If `self` matches `Error::Anyhow`, returns a reference to the first `Self` type error
    /// in the chain; otherwise, returns `self`.
    pub fn root_cause(&self) -> &Self {
        match self {
            Self::Anyhow(err) => {
                let mut ret = self;
                for cause in err.chain() {
                    if let Some(e) = cause.downcast_ref::<Self>() {
                        ret = e;
                    } else {
                        break;
                    }
                }
                return ret;
            }
            _ => self,
        }
    }
}