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,
}
}
}