Skip to content

Commit

Permalink
Use Range to simplify Asn1Reader
Browse files Browse the repository at this point in the history
  • Loading branch information
ektrah committed May 4, 2024
1 parent 60c66fd commit e94a024
Showing 1 changed file with 26 additions and 69 deletions.
95 changes: 26 additions & 69 deletions src/Experimental/Asn1/Asn1Reader.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using NSec.Cryptography;

Expand All @@ -10,16 +9,16 @@ internal ref struct Asn1Reader
{
internal const int MaxDepth = 7;

private InlineSpanArray _stack;
private InlineRangeArray _stack;
private readonly ReadOnlySpan<byte> _buffer;
private int _depth;
private bool _failed;

public Asn1Reader(
ReadOnlySpan<byte> buffer)
{
_stack = new InlineSpanArray();
_stack[0] = new Span(buffer);
_stack = new InlineRangeArray();
_stack[0] = Range.All;

_buffer = buffer;
_depth = 0;
Expand All @@ -28,11 +27,11 @@ public Asn1Reader(

public readonly bool Success => !_failed;

public readonly bool SuccessComplete => !_failed && _depth == 0 && _stack[0].IsEmpty;
public readonly bool SuccessComplete => !_failed && _depth == 0 && _buffer[_stack[0]].IsEmpty;

public void BeginSequence()
{
Span span = Read(0x30);
Range range = Read(0x30);

if (_failed)
{
Expand All @@ -45,13 +44,13 @@ public void BeginSequence()
{
throw Error.InvalidOperation_InternalError(); // overflow
}
_stack[_depth] = span;
_stack[_depth] = range;
}
}

public ReadOnlySpan<byte> BitString()
{
ReadOnlySpan<byte> bytes = Read(0x03).ApplyTo(_buffer);
ReadOnlySpan<byte> bytes = _buffer[Read(0x03)];
ReadOnlySpan<byte> value = default;

if (_failed || bytes.IsEmpty || bytes[0] != 0)
Expand All @@ -68,7 +67,7 @@ public ReadOnlySpan<byte> BitString()

public bool Bool()
{
ReadOnlySpan<byte> bytes = Read(0x01).ApplyTo(_buffer);
ReadOnlySpan<byte> bytes = _buffer[Read(0x01)];
bool value = default;

if (_failed || bytes.Length != 1 || (bytes[0] != 0x00 && bytes[0] != 0xFF))
Expand All @@ -85,7 +84,7 @@ public bool Bool()

public void End()
{
if (_failed || !_stack[_depth].IsEmpty)
if (_failed || !_buffer[_stack[_depth]].IsEmpty)
{
Fail();
}
Expand All @@ -101,7 +100,7 @@ public void End()

public int Integer32()
{
ReadOnlySpan<byte> bytes = Read(0x02).ApplyTo(_buffer);
ReadOnlySpan<byte> bytes = _buffer[Read(0x02)];
int value = default;

if (_failed || IsInvalidInteger(bytes, sizeof(int)))
Expand All @@ -122,7 +121,7 @@ public int Integer32()

public long Integer64()
{
ReadOnlySpan<byte> bytes = Read(0x02).ApplyTo(_buffer);
ReadOnlySpan<byte> bytes = _buffer[Read(0x02)];
long value = default;

if (_failed || IsInvalidInteger(bytes, sizeof(long)))
Expand All @@ -143,22 +142,22 @@ public long Integer64()

public void Null()
{
Span span = Read(0x05);
ReadOnlySpan<byte> bytes = _buffer[Read(0x05)];

if (_failed || !span.IsEmpty)
if (_failed || !bytes.IsEmpty)
{
Fail();
}
}

public ReadOnlySpan<byte> ObjectIdentifier()
{
return Read(0x06).ApplyTo(_buffer);
return _buffer[Read(0x06)];
}

public ReadOnlySpan<byte> OctetString()
{
return Read(0x04).ApplyTo(_buffer);
return _buffer[Read(0x04)];
}

private void Fail()
Expand All @@ -178,18 +177,18 @@ private readonly bool IsInvalidInteger(
|| bytes.Length > 1 && bytes[0] == 0xFF && (bytes[1] & 0x80) == 0x80;
}

private Span Read(
private Range Read(
int tag)
{
Span span = _stack[_depth];
ReadOnlySpan<byte> bytes = span.ApplyTo(_buffer);
Range range = _stack[_depth];
ReadOnlySpan<byte> bytes = _buffer[range];

if (_failed || bytes.Length < 2 || bytes[0] != tag)
{
goto failed;
}

int start = 2;
int offset = 2;
int length = 0;

if ((bytes[1] & ~0x7F) == 0)
Expand All @@ -205,73 +204,31 @@ private Span Read(
}
while (count-- > 0)
{
length = (length << 8) | bytes[start++];
length = (length << 8) | bytes[offset++];
}
if (length < 0x80)
{
goto failed;
}
}

if (length > bytes.Length - start)
if (length > bytes.Length - offset)
{
goto failed;
}

_stack[_depth] = span[(start + length)..];
return span.Slice(start, length);
(int Offset, int Length) = range.GetOffsetAndLength(_buffer.Length);
_stack[_depth] = new Range(Offset + offset + length, Offset + Length);
return new Range(Offset + offset, Offset + offset + length);
failed:
Fail();
return default;
}

[InlineArray(MaxDepth)]
private struct InlineSpanArray
private struct InlineRangeArray
{
private Span _element0;
}

private readonly struct Span
{
private readonly int _start;
private readonly int _length;

public Span(ReadOnlySpan<byte> buffer)
: this(0, buffer.Length)
{
}

private Span(int start, int length)
{
_start = start;
_length = length;
}

public bool IsEmpty => _length == 0;

public int Length => _length;

public int Start => _start;

public ReadOnlySpan<byte> ApplyTo(ReadOnlySpan<byte> buffer)
{
return buffer.Slice(_start, _length);
}

public Span Slice(int start)
{
Debug.Assert(start >= 0 && start <= _length);

return new Span(_start + start, _length - start);
}

public Span Slice(int start, int length)
{
Debug.Assert(start >= 0 && start <= _length);
Debug.Assert(length >= 0 && length <= _length - start);

return new Span(_start + start, length);
}
private Range _element0;
}
}
}

0 comments on commit e94a024

Please sign in to comment.