use crate::error::{Error, Result};
#[cfg(all(not(feature = "std"), feature = "serde"))]
use alloc::string::String;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum TagClass {
Universal = 0b00,
Application = 0b01,
ContextSpecific = 0b10,
Private = 0b11,
}
impl TagClass {
#[inline(always)]
pub fn from_byte(byte: u8) -> Self {
match (byte >> 6) & 0b11 {
0b00 => TagClass::Universal,
0b01 => TagClass::Application,
0b10 => TagClass::ContextSpecific,
0b11 => TagClass::Private,
_ => unreachable!(),
}
}
pub fn to_byte(self) -> u8 {
(self as u8) << 6
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Tag {
class: TagClass,
constructed: bool,
number: u32,
}
impl Tag {
pub const fn new(class: TagClass, constructed: bool, number: u32) -> Self {
Self {
class,
constructed,
number,
}
}
pub const fn universal(number: u32) -> Self {
Self::new(TagClass::Universal, false, number)
}
pub const fn universal_constructed(number: u32) -> Self {
Self::new(TagClass::Universal, true, number)
}
pub const fn context_specific(number: u32) -> Self {
Self::new(TagClass::ContextSpecific, false, number)
}
pub const fn context_specific_constructed(number: u32) -> Self {
Self::new(TagClass::ContextSpecific, true, number)
}
pub const fn application(number: u32) -> Self {
Self::new(TagClass::Application, false, number)
}
pub const fn class(&self) -> TagClass {
self.class
}
pub const fn is_constructed(&self) -> bool {
self.constructed
}
pub const fn number(&self) -> u32 {
self.number
}
pub fn encoded_len(&self) -> usize {
if self.number < 31 {
1
} else {
1 + self.number_encoded_len()
}
}
fn number_encoded_len(&self) -> usize {
if self.number == 0 {
1
} else {
let mut n = self.number;
let mut len = 0;
while n > 0 {
len += 1;
n >>= 7;
}
len
}
}
pub fn encode(&self, buffer: &mut Vec<u8>) -> Result<()> {
if self.number < 31 {
let byte = self.class.to_byte()
| if self.constructed { 0b00100000 } else { 0 }
| (self.number as u8);
buffer.push(byte);
} else {
let first_byte =
self.class.to_byte() | if self.constructed { 0b00100000 } else { 0 } | 0b00011111; buffer.push(first_byte);
let mut encoded = Vec::new();
let mut n = self.number;
while n > 0 {
encoded.push((n & 0x7F) as u8);
n >>= 7;
}
for (i, byte) in encoded.iter().rev().enumerate() {
if i < encoded.len() - 1 {
buffer.push(byte | 0x80);
} else {
buffer.push(*byte);
}
}
}
Ok(())
}
pub fn decode(bytes: &[u8], position: usize) -> Result<(Self, usize)> {
if bytes.is_empty() {
return Err(Error::UnexpectedEof { position });
}
let first_byte = bytes[0];
let class = TagClass::from_byte(first_byte);
let constructed = (first_byte & 0b00100000) != 0;
let number_bits = first_byte & 0b00011111;
if number_bits < 31 {
Ok((Tag::new(class, constructed, number_bits as u32), 1))
} else {
#[cfg(feature = "unchecked")]
{
Self::decode_high_tag_unchecked(bytes, class, constructed, first_byte, position)
}
#[cfg(not(feature = "unchecked"))]
{
Self::decode_high_tag_checked(bytes, class, constructed, first_byte, position)
}
}
}
#[cfg(not(feature = "unchecked"))]
#[cold]
#[inline(never)]
fn decode_high_tag_checked(
bytes: &[u8],
class: TagClass,
constructed: bool,
first_byte: u8,
position: usize,
) -> Result<(Self, usize)> {
let mut number: u32 = 0;
let mut bytes_read = 1;
loop {
if bytes_read >= bytes.len() {
return Err(Error::UnexpectedEof {
position: position + bytes_read,
});
}
let byte = bytes[bytes_read];
bytes_read += 1;
if number > (u32::MAX >> 7) {
return Err(Error::InvalidTag {
position,
byte: first_byte,
});
}
number = (number << 7) | ((byte & 0x7F) as u32);
if (byte & 0x80) == 0 {
break;
}
if bytes_read > 5 {
return Err(Error::InvalidTag {
position,
byte: first_byte,
});
}
}
Ok((Tag::new(class, constructed, number), bytes_read))
}
#[cfg(feature = "unchecked")]
#[cold]
#[inline(never)]
fn decode_high_tag_unchecked(
bytes: &[u8],
class: TagClass,
constructed: bool,
_first_byte: u8,
_position: usize,
) -> Result<(Self, usize)> {
let mut number: u32 = 0;
let mut bytes_read = 1;
loop {
let byte = bytes[bytes_read];
bytes_read += 1;
number = (number << 7) | ((byte & 0x7F) as u32);
if (byte & 0x80) == 0 {
break;
}
}
Ok((Tag::new(class, constructed, number), bytes_read))
}
}
pub const TAG_BOOLEAN: u32 = 1;
pub const TAG_INTEGER: u32 = 2;
pub const TAG_BIT_STRING: u32 = 3;
pub const TAG_OCTET_STRING: u32 = 4;
pub const TAG_NULL: u32 = 5;
pub const TAG_OBJECT_IDENTIFIER: u32 = 6;
pub const TAG_REAL: u32 = 9;
pub const TAG_ENUMERATED: u32 = 10;
pub const TAG_UTF8_STRING: u32 = 12;
pub const TAG_SEQUENCE: u32 = 16;
pub const TAG_SET: u32 = 17;
pub const TAG_PRINTABLE_STRING: u32 = 19;
pub const TAG_IA5_STRING: u32 = 22;
pub const TAG_UTC_TIME: u32 = 23;
pub const TAG_GENERALIZED_TIME: u32 = 24;
pub const TAG_VISIBLE_STRING: u32 = 26;
pub const TAG_GENERAL_STRING: u32 = 27;
pub const TAG_UNIVERSAL_STRING: u32 = 28;
pub const TAG_BMP_STRING: u32 = 30;
pub const TAG_NUMERIC_STRING: u32 = 18;
pub const TAG_TELETEX_STRING: u32 = 20;
#[cfg(feature = "serde")]
impl serde::Serialize for TagClass {
fn serialize<S: serde::Serializer>(&self, s: S) -> core::result::Result<S::Ok, S::Error> {
s.serialize_str(match self {
TagClass::Universal => "Universal",
TagClass::Application => "Application",
TagClass::ContextSpecific => "ContextSpecific",
TagClass::Private => "Private",
})
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for TagClass {
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> core::result::Result<Self, D::Error> {
struct V;
impl<'de> serde::de::Visitor<'de> for V {
type Value = TagClass;
fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(
f,
"one of \"Universal\", \"Application\", \"ContextSpecific\", \"Private\""
)
}
fn visit_str<E: serde::de::Error>(self, v: &str) -> core::result::Result<TagClass, E> {
match v {
"Universal" => Ok(TagClass::Universal),
"Application" => Ok(TagClass::Application),
"ContextSpecific" => Ok(TagClass::ContextSpecific),
"Private" => Ok(TagClass::Private),
_ => Err(E::unknown_variant(
v,
&["Universal", "Application", "ContextSpecific", "Private"],
)),
}
}
}
d.deserialize_str(V)
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for Tag {
fn serialize<S: serde::Serializer>(&self, s: S) -> core::result::Result<S::Ok, S::Error> {
use serde::ser::SerializeStruct;
let mut st = s.serialize_struct("Tag", 3)?;
st.serialize_field("class", &self.class())?;
st.serialize_field("constructed", &self.is_constructed())?;
st.serialize_field("number", &self.number())?;
st.end()
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for Tag {
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> core::result::Result<Self, D::Error> {
struct TagVisitor;
impl<'de> serde::de::Visitor<'de> for TagVisitor {
type Value = Tag;
fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "a Tag with class, constructed, and number fields")
}
fn visit_map<A: serde::de::MapAccess<'de>>(
self,
mut map: A,
) -> core::result::Result<Tag, A::Error> {
let mut class: Option<TagClass> = None;
let mut constructed: Option<bool> = None;
let mut number: Option<u32> = None;
while let Some(key) = map.next_key::<String>()? {
match key.as_str() {
"class" => class = Some(map.next_value()?),
"constructed" => constructed = Some(map.next_value()?),
"number" => number = Some(map.next_value()?),
_ => {
let _ = map.next_value::<serde::de::IgnoredAny>()?;
}
}
}
let class = class.ok_or_else(|| serde::de::Error::missing_field("class"))?;
let constructed =
constructed.ok_or_else(|| serde::de::Error::missing_field("constructed"))?;
let number = number.ok_or_else(|| serde::de::Error::missing_field("number"))?;
Ok(Tag::new(class, constructed, number))
}
}
d.deserialize_map(TagVisitor)
}
}