You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

130 lines
3.3 KiB

  1. using MQTTnet.Exceptions;
  2. using MQTTnet.Formatter;
  3. using System;
  4. using System.Buffers.Binary;
  5. using System.Text;
  6. namespace MQTTnet.AspNetCore
  7. {
  8. public class SpanBasedMqttPacketBodyReader : IMqttPacketBodyReader
  9. {
  10. ReadOnlyMemory<byte> _buffer;
  11. int _offset;
  12. public void SetBuffer(ReadOnlyMemory<byte> buffer)
  13. {
  14. _buffer = buffer;
  15. _offset = 0;
  16. }
  17. public int Length => _buffer.Length;
  18. public bool EndOfStream => _buffer.Length.Equals(_offset);
  19. public int Offset => _offset;
  20. public byte ReadByte()
  21. {
  22. return _buffer.Span[_offset++];
  23. }
  24. public byte[] ReadRemainingData()
  25. {
  26. return _buffer.Slice(_offset).ToArray();
  27. }
  28. public byte[] ReadWithLengthPrefix()
  29. {
  30. return ReadSegmentWithLengthPrefix().ToArray();
  31. }
  32. public unsafe string ReadStringWithLengthPrefix()
  33. {
  34. var buffer = ReadSegmentWithLengthPrefix();
  35. if (buffer.Length == 0)
  36. {
  37. return string.Empty;
  38. }
  39. fixed (byte* bytes = &buffer.GetPinnableReference())
  40. {
  41. var result = Encoding.UTF8.GetString(bytes, buffer.Length);
  42. return result;
  43. }
  44. }
  45. public ushort ReadTwoByteInteger()
  46. {
  47. var result = BinaryPrimitives.ReadUInt16BigEndian(_buffer.Span.Slice(_offset));
  48. _offset += 2;
  49. return result;
  50. }
  51. public uint ReadFourByteInteger()
  52. {
  53. var result = BinaryPrimitives.ReadUInt32BigEndian(_buffer.Span.Slice(_offset));
  54. _offset += 4;
  55. return result;
  56. }
  57. public uint ReadVariableLengthInteger()
  58. {
  59. var multiplier = 1;
  60. var value = 0U;
  61. byte encodedByte;
  62. do
  63. {
  64. encodedByte = ReadByte();
  65. value += (uint)((encodedByte & 127) * multiplier);
  66. if (multiplier > 2097152)
  67. {
  68. throw new MqttProtocolViolationException("Variable length integer is invalid.");
  69. }
  70. multiplier *= 128;
  71. } while ((encodedByte & 128) != 0);
  72. return value;
  73. }
  74. public bool ReadBoolean()
  75. {
  76. var buffer = ReadByte();
  77. if (buffer == 0)
  78. {
  79. return false;
  80. }
  81. if (buffer == 1)
  82. {
  83. return true;
  84. }
  85. throw new MqttProtocolViolationException("Boolean values can be 0 or 1 only.");
  86. }
  87. public void Seek(int position)
  88. {
  89. _offset = position;
  90. }
  91. ReadOnlySpan<byte> ReadSegmentWithLengthPrefix()
  92. {
  93. var span = _buffer.Span;
  94. var length = BinaryPrimitives.ReadUInt16BigEndian(span.Slice(_offset));
  95. if (Length < _offset + length)
  96. {
  97. throw new MqttProtocolViolationException($"Expected at least {_offset + 2 + length} bytes but there are only {Length} bytes");
  98. }
  99. var result = span.Slice(_offset + 2, length);
  100. _offset += 2 + length;
  101. return result;
  102. }
  103. }
  104. }