mirror of
https://github.com/dotnet/MQTTnet.git
synced 2026-10-15 00:15:15 +08:00
130 lines
3.3 KiB
C#
130 lines
3.3 KiB
C#
using MQTTnet.Exceptions;
|
|
using MQTTnet.Formatter;
|
|
using System;
|
|
using System.Buffers.Binary;
|
|
using System.Text;
|
|
|
|
namespace MQTTnet.AspNetCore
|
|
{
|
|
public class SpanBasedMqttPacketBodyReader : IMqttPacketBodyReader
|
|
{
|
|
ReadOnlyMemory<byte> _buffer;
|
|
|
|
int _offset;
|
|
|
|
public void SetBuffer(ReadOnlyMemory<byte> buffer)
|
|
{
|
|
_buffer = buffer;
|
|
_offset = 0;
|
|
}
|
|
|
|
public int Length => _buffer.Length;
|
|
|
|
public bool EndOfStream => _buffer.Length.Equals(_offset);
|
|
|
|
public int Offset => _offset;
|
|
|
|
public byte ReadByte()
|
|
{
|
|
return _buffer.Span[_offset++];
|
|
}
|
|
|
|
public byte[] ReadRemainingData()
|
|
{
|
|
return _buffer.Slice(_offset).ToArray();
|
|
}
|
|
|
|
public byte[] ReadWithLengthPrefix()
|
|
{
|
|
return ReadSegmentWithLengthPrefix().ToArray();
|
|
}
|
|
|
|
public unsafe string ReadStringWithLengthPrefix()
|
|
{
|
|
var buffer = ReadSegmentWithLengthPrefix();
|
|
if (buffer.Length == 0)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
fixed (byte* bytes = &buffer.GetPinnableReference())
|
|
{
|
|
var result = Encoding.UTF8.GetString(bytes, buffer.Length);
|
|
return result;
|
|
}
|
|
}
|
|
|
|
public ushort ReadTwoByteInteger()
|
|
{
|
|
var result = BinaryPrimitives.ReadUInt16BigEndian(_buffer.Span.Slice(_offset));
|
|
_offset += 2;
|
|
return result;
|
|
}
|
|
|
|
public uint ReadFourByteInteger()
|
|
{
|
|
var result = BinaryPrimitives.ReadUInt32BigEndian(_buffer.Span.Slice(_offset));
|
|
_offset += 4;
|
|
return result;
|
|
}
|
|
|
|
public uint ReadVariableLengthInteger()
|
|
{
|
|
var multiplier = 1;
|
|
var value = 0U;
|
|
byte encodedByte;
|
|
|
|
do
|
|
{
|
|
encodedByte = ReadByte();
|
|
value += (uint)((encodedByte & 127) * multiplier);
|
|
|
|
if (multiplier > 2097152)
|
|
{
|
|
throw new MqttProtocolViolationException("Variable length integer is invalid.");
|
|
}
|
|
|
|
multiplier *= 128;
|
|
} while ((encodedByte & 128) != 0);
|
|
|
|
return value;
|
|
}
|
|
|
|
public bool ReadBoolean()
|
|
{
|
|
var buffer = ReadByte();
|
|
|
|
if (buffer == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (buffer == 1)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
throw new MqttProtocolViolationException("Boolean values can be 0 or 1 only.");
|
|
}
|
|
|
|
public void Seek(int position)
|
|
{
|
|
_offset = position;
|
|
}
|
|
|
|
ReadOnlySpan<byte> ReadSegmentWithLengthPrefix()
|
|
{
|
|
var span = _buffer.Span;
|
|
var length = BinaryPrimitives.ReadUInt16BigEndian(span.Slice(_offset));
|
|
|
|
if (Length < _offset + length)
|
|
{
|
|
throw new MqttProtocolViolationException($"Expected at least {_offset + 2 + length} bytes but there are only {Length} bytes");
|
|
}
|
|
var result = span.Slice(_offset + 2, length);
|
|
_offset += 2 + length;
|
|
return result;
|
|
}
|
|
}
|
|
}
|