mod value;
pub(crate) use value::read_into;
use crate::Session;
use crate::arena::{Arena, Children, Integer, Name, NodeId};
use crate::byte_machine::{Decoder, Step};
use crate::bytes::{Form, is_space};
use crate::error::{Error, ErrorKind, Limit, ReadFailure, Syntax};
use crate::object::Value;
use crate::range::{RangeReader, RangeSource};
use crate::source::{Location, Source};
use structured_asn1::memory::{OwnedVec, Work};
#[derive(Clone, Copy)]
enum Container {
Array,
Dictionary,
}
pub(crate) enum NumberKind {
Integer,
Real { fractional: bool },
}
#[derive(Clone, Copy)]
struct Frame {
node: NodeId,
kind: Container,
start: u64,
children: Children,
}
pub async fn read<'s, S: RangeSource, W: Work>(
source: &S,
session: &'s Session,
operation: &W,
offset: u64,
) -> Result<Value<'s, S::Document, S::Generation>, ReadFailure<S::Error>> {
let reader = RangeReader::new(source, session, operation)?;
let stamp = reader.stamp();
if offset > stamp.length {
return Err(Error {
kind: ErrorKind::Foreign,
location: location(0, stamp.length),
}
.into());
}
let work = reader.execution();
let mut cursor = Cursor { reader, at: offset };
let (arena, root) = read_into(&mut cursor, session, Arena::new(&work).into_owned()).await?;
Ok(Value {
arena,
root,
session,
stamp,
end: cursor.at,
})
}
pub(crate) struct Cursor<'q, S: RangeSource> {
pub(crate) reader: RangeReader<'q, S>,
pub(crate) at: u64,
}
impl<S: RangeSource> Cursor<'_, S> {
pub(crate) fn location(&self, start: u64, length: u64) -> Location {
self.reader.location(start, length)
}
pub(crate) fn failure(&self, code: Syntax, at: u64) -> ReadFailure<S::Error> {
Error {
kind: ErrorKind::Syntax(code),
location: self.location(at, 0),
}
.into()
}
pub(crate) async fn peek(&mut self) -> Result<Option<u8>, ReadFailure<S::Error>> {
Ok(self.reader.byte_at(self.at).await?)
}
pub(crate) async fn take(&mut self) -> Result<Option<u8>, ReadFailure<S::Error>> {
let byte = self.peek().await?;
if byte.is_some() {
self.at += 1;
}
Ok(byte)
}
pub(crate) async fn skip(&mut self) -> Result<(), ReadFailure<S::Error>> {
loop {
let Some(byte) = self.peek().await? else {
return Ok(());
};
if is_space(byte) {
self.at += 1;
continue;
}
if byte != b'%' {
return Ok(());
}
self.at += 1;
let mut terminated = false;
while let Some(byte) = self.take().await? {
if byte == b'\r' || byte == b'\n' {
terminated = true;
break;
}
}
if !terminated && self.at < self.reader.stamp().length {
return Err(self.failure(Syntax::End, self.at));
}
}
}
pub(crate) async fn keyword(&mut self, expected: &[u8]) -> Result<(), ReadFailure<S::Error>> {
let start = self.at;
for &byte in expected {
if self.take().await? != Some(byte) {
return Err(self.failure(Syntax::Token, start));
}
}
if let Some(next) = self.peek().await?
&& !boundary(next)
{
return Err(self.failure(Syntax::Token, self.at));
}
Ok(())
}
pub(crate) async fn looking(&mut self, expected: &[u8]) -> Result<bool, ReadFailure<S::Error>> {
let start = self.at;
for (index, &byte) in expected.iter().enumerate() {
let Some(at) = start.checked_add(index as u64) else {
return Ok(false);
};
if self.reader.byte_at(at).await? != Some(byte) {
return Ok(false);
}
}
Ok(true)
}
pub(crate) async fn natural(&mut self) -> Result<u64, ReadFailure<S::Error>> {
let at = self.at;
let (integer, real) = self.number().await?;
if !matches!(real, NumberKind::Integer) || integer.negative {
return Err(self.failure(Syntax::Number, at));
}
integer.magnitude.ok_or_else(|| {
Error {
kind: ErrorKind::Unsupported(crate::error::Unsupported::NumericRange),
location: self.location(at, self.at - at),
}
.into()
})
}
pub(crate) async fn space(&mut self) -> Result<(), ReadFailure<S::Error>> {
while self.peek().await?.is_some_and(is_space) {
self.at += 1;
}
Ok(())
}
async fn name<W: Work>(
&mut self,
names: &mut OwnedVec<u8, W>,
) -> Result<Name, ReadFailure<S::Error>> {
let start = names.len();
self.at += 1; let mut decoder = Decoder::new(Form::Name);
loop {
let input = match self.peek().await? {
Some(byte) if !boundary(byte) => Some(byte),
_ => None,
};
match decoder.step(input) {
Step::More => {
debug_assert!(input.is_some());
self.at += 1;
}
Step::Byte { value, consumed } => {
if consumed {
self.at += 1;
}
names
.try_push(value)
.map_err(|cause| refused(cause, self.location(self.at, 0)))?;
}
Step::End => break,
Step::Malformed => return Err(self.failure(Syntax::Name, self.at)),
}
}
Ok(Name {
start,
length: names.len() - start,
})
}
async fn literal(
&mut self,
session: &Session,
outer_depth: u64,
) -> Result<(), ReadFailure<S::Error>> {
let start = self.at;
self.at += 1;
let mut depth = 1;
let mut escaped = false;
check_depth(session, outer_depth + depth, self.location(start, 1))?;
while let Some(byte) = self.take().await? {
if escaped {
escaped = false;
continue;
}
match byte {
b'\\' => escaped = true,
b'(' => {
depth += 1;
check_depth(session, outer_depth + depth, self.location(self.at - 1, 1))?;
}
b')' => {
depth -= 1;
if depth == 0 {
return Ok(());
}
}
_ => {}
}
}
Err(self.failure(Syntax::String, self.at))
}
async fn hexadecimal(&mut self) -> Result<(), ReadFailure<S::Error>> {
let mut decoder = Decoder::new(Form::Hexadecimal);
loop {
let Some(byte) = self.take().await? else {
return Err(self.failure(Syntax::String, self.at));
};
if byte == b'>' {
match decoder.step(None) {
Step::End | Step::Byte { .. } => return Ok(()),
_ => return Err(self.failure(Syntax::String, self.at - 1)),
}
}
if matches!(decoder.step(Some(byte)), Step::Malformed) {
return Err(self.failure(Syntax::String, self.at - 1));
}
}
}
pub(crate) async fn number(&mut self) -> Result<(Integer, NumberKind), ReadFailure<S::Error>> {
let start = self.at;
let negative = self.peek().await? == Some(b'-');
if matches!(self.peek().await?, Some(b'+' | b'-')) {
self.at += 1;
}
let mut magnitude = Some(0_u64);
let mut real = false;
let mut fractional = false;
let mut digits = 0_u64;
while let Some(byte) = self.peek().await? {
if byte.is_ascii_digit() {
if real {
fractional |= byte != b'0';
} else {
magnitude = magnitude.and_then(|value| {
value
.checked_mul(10)
.and_then(|value| value.checked_add(u64::from(byte - b'0')))
});
}
digits += 1;
self.at += 1;
continue;
}
if byte == b'.' && !real {
real = true;
self.at += 1;
continue;
}
if boundary(byte) {
break;
}
return Err(self.failure(Syntax::Number, self.at));
}
if digits == 0 {
return Err(self.failure(Syntax::Number, start));
}
Ok((
Integer {
negative,
magnitude,
},
if real {
NumberKind::Real { fractional }
} else {
NumberKind::Integer
},
))
}
async fn reference(
&mut self,
first: Integer,
) -> Result<Option<(u64, u16)>, ReadFailure<S::Error>> {
let after_first = self.at;
self.skip().await?;
if self.at == after_first || !matches!(self.peek().await?, Some(b'0'..=b'9')) {
return Ok(None);
}
let generation = match self.number().await {
Ok((integer, NumberKind::Integer)) => integer,
Ok(_) => return Ok(None),
Err(ReadFailure::Format(error)) if error.kind == ErrorKind::Syntax(Syntax::Number) => {
return Ok(None);
}
Err(error) => return Err(error),
};
let after_generation = self.at;
self.skip().await?;
if self.at == after_generation || self.peek().await? != Some(b'R') {
return Ok(None);
}
self.at += 1;
if let Some(next) = self.peek().await?
&& !boundary(next)
{
return Ok(None);
}
let (Some(number), Some(generation)) = (first.magnitude, generation.magnitude) else {
return Err(Error {
kind: ErrorKind::Unsupported(crate::error::Unsupported::NumericRange),
location: self.location(after_first, self.at - after_first),
}
.into());
};
let generation =
u16::try_from(generation).map_err(|_| self.failure(Syntax::Object, after_first))?;
Ok(Some((number, generation)))
}
}
fn boundary(byte: u8) -> bool {
is_space(byte)
|| matches!(
byte,
b'(' | b')' | b'<' | b'>' | b'[' | b']' | b'{' | b'}' | b'/' | b'%'
)
}
fn location(start: u64, length: u64) -> Location {
Location::new(Source::File, start, length).expect("bounded original object range")
}
fn refused(cause: structured_asn1::memory::MemoryError, location: Location) -> Error {
Error {
kind: ErrorKind::Resource(cause),
location,
}
}
fn check_depth(session: &Session, depth: u64, location: Location) -> crate::Result<()> {
if depth > u64::from(session.limits().processing.max_depth) {
return Err(Error {
kind: ErrorKind::Limit(Limit::Depth),
location,
});
}
Ok(())
}