extern crate alloc;
use alloc::{borrow::Cow, format, vec::Vec};
use facet_format::{
ContainerKind, DeserializeErrorKind, FormatParser, ParseError, ParseEvent, ParseEventKind,
SavePoint, ScalarValue,
};
use facet_reflect::Span;
const TAG_BOOLEAN: u8 = 0x01;
const TAG_INTEGER: u8 = 0x02;
const TAG_OCTET_STRING: u8 = 0x04;
const TAG_REAL: u8 = 0x09;
const TAG_UTF8STRING: u8 = 0x0C;
const CLASS_MASK: u8 = 0xC0;
const CLASS_UNIVERSAL: u8 = 0x00;
const CLASS_CONTEXT: u8 = 0x80;
const CONSTRUCTED_BIT: u8 = 0x20;
const REAL_INFINITY: u8 = 0b01000000;
const REAL_NEG_INFINITY: u8 = 0b01000001;
const REAL_NAN: u8 = 0b01000010;
const REAL_NEG_ZERO: u8 = 0b01000011;
const F64_MANTISSA_MASK: u64 = 0b1111111111111111111111111111111111111111111111111111;
pub struct Asn1Parser<'de> {
input: &'de [u8],
pos: usize,
stack: Vec<ContainerState>,
event_peek: Option<ParseEvent<'de>>,
field_indices: Vec<usize>,
pending_sequence: bool,
pending_struct_fields: Option<usize>,
pending_scalar_type: Option<facet_format::ScalarTypeHint>,
}
#[derive(Debug, Clone)]
struct ContainerState {
end: usize,
is_sequence: bool,
remaining_fields: usize,
awaiting_value: bool,
}
impl<'de> Asn1Parser<'de> {
pub const fn new(input: &'de [u8]) -> Self {
Self {
input,
pos: 0,
stack: Vec::new(),
event_peek: None,
field_indices: Vec::new(),
pending_sequence: false,
pending_struct_fields: None,
pending_scalar_type: None,
}
}
fn peek_byte(&self) -> Result<u8, ParseError> {
self.input.get(self.pos).copied().ok_or_else(|| {
ParseError::new(
Span::new(self.pos, 0),
DeserializeErrorKind::UnexpectedEof { expected: "byte" },
)
})
}
fn read_byte(&mut self) -> Result<u8, ParseError> {
let byte = self.peek_byte()?;
self.pos += 1;
Ok(byte)
}
fn read_length(&mut self) -> Result<usize, ParseError> {
let first = self.read_byte()?;
if first < 128 {
Ok(first as usize)
} else {
let num_bytes = (first & 0x7f) as usize;
if num_bytes == 0 {
return Err(ParseError::new(
Span::new(self.pos, 1),
DeserializeErrorKind::InvalidValue {
message: "indefinite length not supported".into(),
},
));
}
if num_bytes > 8 {
return Err(ParseError::new(
Span::new(self.pos, 1),
DeserializeErrorKind::InvalidValue {
message: "length too large".into(),
},
));
}
let mut len = 0usize;
for _ in 0..num_bytes {
len = len.checked_shl(8).ok_or_else(|| {
ParseError::new(
Span::new(self.pos, 1),
DeserializeErrorKind::InvalidValue {
message: "length overflow".into(),
},
)
})?;
len |= self.read_byte()? as usize;
}
Ok(len)
}
}
fn read_tl(&mut self) -> Result<(u8, usize), ParseError> {
let tag = self.read_byte()?;
let len = self.read_length()?;
let end = self.pos.checked_add(len).ok_or_else(|| {
ParseError::new(
Span::new(self.pos, 1),
DeserializeErrorKind::InvalidValue {
message: "content length overflow".into(),
},
)
})?;
if end > self.input.len() {
return Err(ParseError::new(
Span::new(self.pos, 0),
DeserializeErrorKind::UnexpectedEof {
expected: "content",
},
));
}
Ok((tag, end))
}
fn read_tlv(&mut self) -> Result<(u8, &'de [u8]), ParseError> {
let (tag, end) = self.read_tl()?;
let start = self.pos;
self.pos = end;
Ok((tag, &self.input[start..end]))
}
fn read_bool(&mut self) -> Result<bool, ParseError> {
let (tag, bytes) = self.read_tlv()?;
if tag != TAG_BOOLEAN {
return Err(ParseError::new(
Span::new(self.pos, 1),
DeserializeErrorKind::InvalidValue {
message: format!("unknown tag 0x{:02x}, expected BOOLEAN", tag).into(),
},
));
}
match bytes {
[0x00] => Ok(false),
[0xFF] => Ok(true),
[_] => Err(ParseError::new(
Span::new(self.pos, 1),
DeserializeErrorKind::InvalidValue {
message: "invalid boolean value".into(),
},
)),
_ => Err(ParseError::new(
Span::new(self.pos, bytes.len()),
DeserializeErrorKind::InvalidValue {
message: format!("length mismatch: expected 1, got {}", bytes.len()).into(),
},
)),
}
}
fn read_integer(&mut self) -> Result<i64, ParseError> {
let (tag, bytes) = self.read_tlv()?;
if tag != TAG_INTEGER {
return Err(ParseError::new(
Span::new(self.pos, 1),
DeserializeErrorKind::InvalidValue {
message: format!("unknown tag 0x{:02x}, expected INTEGER", tag).into(),
},
));
}
if bytes.is_empty() {
return Ok(0);
}
let mut value = bytes[0] as i8 as i64;
for &byte in &bytes[1..] {
value = (value << 8) | (byte as i64);
}
Ok(value)
}
fn read_real(&mut self) -> Result<f64, ParseError> {
let (tag, bytes) = self.read_tlv()?;
if tag != TAG_REAL {
return Err(ParseError::new(
Span::new(self.pos, 1),
DeserializeErrorKind::InvalidValue {
message: format!("unknown tag 0x{:02x}, expected REAL", tag).into(),
},
));
}
if bytes.is_empty() {
return Ok(0.0);
}
match bytes[0] {
REAL_INFINITY => Ok(f64::INFINITY),
REAL_NEG_INFINITY => Ok(f64::NEG_INFINITY),
REAL_NAN => Ok(f64::NAN),
REAL_NEG_ZERO => Ok(-0.0),
struct_byte => {
if struct_byte & 0b10111100 != 0b10000000 {
return Err(ParseError::new(
Span::new(self.pos, 1),
DeserializeErrorKind::InvalidValue {
message: "invalid real format".into(),
},
));
}
let sign_negative = (struct_byte >> 6 & 0b1) > 0;
let exponent_len = ((struct_byte & 0b11) + 1) as usize;
if bytes.len() < exponent_len + 2 {
return Err(ParseError::new(
Span::new(self.pos, bytes.len()),
DeserializeErrorKind::InvalidValue {
message: format!(
"length mismatch: expected {}, got {}",
exponent_len + 2,
bytes.len()
)
.into(),
},
));
}
let mut exponent = bytes[1] as i8 as i64;
for &byte in &bytes[2..1 + exponent_len] {
exponent = (exponent << 8) | (byte as u64 as i64);
}
if exponent > 1023 {
return Ok(if sign_negative {
f64::NEG_INFINITY
} else {
f64::INFINITY
});
}
let mut mantissa = 0u64;
for &byte in bytes[1 + exponent_len..].iter().take(7) {
mantissa = (mantissa << 8) | (byte as u64);
}
let mut normalization_factor = 52i64;
while mantissa & (0b1 << 52) == 0 && normalization_factor > 0 {
mantissa <<= 1;
normalization_factor -= 1;
}
exponent += normalization_factor + 1023;
Ok(f64::from_bits(
(sign_negative as u64) << 63
| ((exponent as u64) & 0b11111111111) << 52
| (mantissa & F64_MANTISSA_MASK),
))
}
}
}
fn read_string(&mut self) -> Result<&'de str, ParseError> {
let start_pos = self.pos;
let (tag, bytes) = self.read_tlv()?;
if tag != TAG_UTF8STRING {
return Err(ParseError::new(
Span::new(self.pos, 1),
DeserializeErrorKind::InvalidValue {
message: format!("unknown tag 0x{:02x}, expected UTF8STRING", tag).into(),
},
));
}
core::str::from_utf8(bytes).map_err(|_| {
let mut context = [0u8; 16];
let context_len = bytes.len().min(16);
context[..context_len].copy_from_slice(&bytes[..context_len]);
ParseError::new(
Span::new(start_pos, bytes.len()),
DeserializeErrorKind::InvalidUtf8 {
context,
context_len: context_len as u8,
},
)
})
}
fn read_octet_string(&mut self) -> Result<&'de [u8], ParseError> {
let (tag, bytes) = self.read_tlv()?;
if tag != TAG_OCTET_STRING {
return Err(ParseError::new(
Span::new(self.pos, 1),
DeserializeErrorKind::InvalidValue {
message: format!("unknown tag 0x{:02x}, expected OCTET STRING", tag).into(),
},
));
}
Ok(bytes)
}
fn finish_value(&mut self) {
if let Some(idx) = self.field_indices.last_mut() {
*idx += 1;
}
}
fn produce_event(&mut self) -> Result<Option<ParseEvent<'de>>, ParseError> {
if let Some(state) = self.stack.last()
&& self.pos >= state.end
{
let state = self.stack.pop().unwrap();
self.field_indices.pop();
if state.is_sequence {
return Ok(Some(self.event(ParseEventKind::StructEnd)));
} else {
return Ok(Some(self.event(ParseEventKind::SequenceEnd)));
}
}
if self.pos >= self.input.len() {
return Ok(None);
}
if let Some(state) = self.stack.last()
&& state.is_sequence
&& state.remaining_fields > 0
&& !state.awaiting_value
{
if let Some(state) = self.stack.last_mut() {
state.remaining_fields -= 1;
state.awaiting_value = true;
}
return Ok(Some(self.event(ParseEventKind::OrderedField)));
}
if let Some(state) = self.stack.last_mut() {
state.awaiting_value = false;
}
self.pending_scalar_type = None;
let tag = self.peek_byte()?;
let tag_class = tag & CLASS_MASK;
let is_constructed = (tag & CONSTRUCTED_BIT) != 0;
let tag_number = tag & 0x1F;
match (tag_class, is_constructed, tag_number) {
(CLASS_UNIVERSAL, true, 0x10) => {
let (_, end) = self.read_tl()?;
let as_array = self.pending_sequence;
self.pending_sequence = false;
let remaining_fields = self.pending_struct_fields.take().unwrap_or(0);
self.stack.push(ContainerState {
end,
is_sequence: !as_array, remaining_fields,
awaiting_value: false,
});
self.field_indices.push(0);
if as_array {
Ok(Some(self.event(ParseEventKind::SequenceStart(
ContainerKind::Array,
))))
} else {
Ok(Some(
self.event(ParseEventKind::StructStart(ContainerKind::Object)),
))
}
}
(CLASS_UNIVERSAL, false, 0x01) => {
let value = self.read_bool()?;
self.finish_value();
Ok(Some(
self.event(ParseEventKind::Scalar(ScalarValue::Bool(value))),
))
}
(CLASS_UNIVERSAL, false, 0x02) => {
let value = self.read_integer()?;
self.finish_value();
Ok(Some(
self.event(ParseEventKind::Scalar(ScalarValue::I64(value))),
))
}
(CLASS_UNIVERSAL, false, 0x04) => {
let bytes = self.read_octet_string()?;
self.finish_value();
Ok(Some(self.event(ParseEventKind::Scalar(
ScalarValue::Bytes(Cow::Borrowed(bytes)),
))))
}
(CLASS_UNIVERSAL, false, 0x05) => {
let _ = self.read_tlv()?;
self.finish_value();
Ok(Some(self.event(ParseEventKind::Scalar(ScalarValue::Null))))
}
(CLASS_UNIVERSAL, false, 0x09) => {
let value = self.read_real()?;
self.finish_value();
Ok(Some(
self.event(ParseEventKind::Scalar(ScalarValue::F64(value))),
))
}
(CLASS_UNIVERSAL, false, 0x0C) => {
let s = self.read_string()?;
self.finish_value();
Ok(Some(self.event(ParseEventKind::Scalar(ScalarValue::Str(
Cow::Borrowed(s),
)))))
}
(CLASS_CONTEXT, _, _) => {
let (_, end) = self.read_tl()?;
if is_constructed {
self.stack.push(ContainerState {
end,
is_sequence: true,
remaining_fields: 0,
awaiting_value: false,
});
self.field_indices.push(0);
Ok(Some(
self.event(ParseEventKind::StructStart(ContainerKind::Object)),
))
} else {
self.finish_value();
Ok(Some(self.event(ParseEventKind::Scalar(ScalarValue::U64(
tag_number as u64,
)))))
}
}
_ => {
let (_, end) = self.read_tl()?;
self.pos = end;
self.produce_event()
}
}
}
fn skip_value_internal(&mut self) -> Result<(), ParseError> {
let (_, end) = self.read_tl()?;
self.pos = end;
Ok(())
}
}
impl<'de> FormatParser<'de> for Asn1Parser<'de> {
fn next_event(&mut self) -> Result<Option<ParseEvent<'de>>, ParseError> {
if let Some(event) = self.event_peek.take() {
return Ok(Some(event));
}
self.produce_event()
}
fn peek_event(&mut self) -> Result<Option<ParseEvent<'de>>, ParseError> {
if let Some(event) = self.event_peek.clone() {
return Ok(Some(event));
}
let event = self.produce_event()?;
if let Some(ref e) = event {
self.event_peek = Some(e.clone());
}
Ok(event)
}
fn skip_value(&mut self) -> Result<(), ParseError> {
debug_assert!(
self.event_peek.is_none(),
"skip_value called while an event is buffered"
);
self.skip_value_internal()?;
self.finish_value();
Ok(())
}
fn current_span(&self) -> Option<Span> {
Some(Span::new(self.pos, 1))
}
fn save(&mut self) -> SavePoint {
unimplemented!("save/restore not supported for ASN.1 (positional format)")
}
fn restore(&mut self, _save_point: SavePoint) {
unimplemented!("save/restore not supported for ASN.1 (positional format)")
}
fn is_self_describing(&self) -> bool {
false
}
fn hint_struct_fields(&mut self, num_fields: usize) {
self.pending_struct_fields = Some(num_fields);
if self
.event_peek
.as_ref()
.is_some_and(|e| matches!(e.kind, ParseEventKind::OrderedField))
{
self.event_peek = None;
}
}
fn hint_scalar_type(&mut self, hint: facet_format::ScalarTypeHint) {
self.pending_scalar_type = Some(hint);
if self
.event_peek
.as_ref()
.is_some_and(|e| matches!(e.kind, ParseEventKind::OrderedField))
{
self.event_peek = None;
}
}
fn hint_sequence(&mut self) {
self.pending_sequence = true;
if self
.event_peek
.as_ref()
.is_some_and(|e| matches!(e.kind, ParseEventKind::StructStart(_)))
{
self.event_peek = None;
}
}
}
impl<'de> Asn1Parser<'de> {
#[inline]
fn event(&self, kind: ParseEventKind<'de>) -> ParseEvent<'de> {
ParseEvent::new(kind, Span::new(self.pos, 1))
}
}