Skip to content

Commit a900bbf

Browse files
authored
[NRBF] change StartsWithPayloadHeader to accept a Span rather than array (#103636)
* change StartsWithPayloadHeader to accept a Span rather than array * address code review feedback: don't use MemoryMarshal.Cast<byte, int> because it's not guaranteed to work everywhere
1 parent 203f993 commit a900bbf

File tree

2 files changed

+18
-26
lines changed

2 files changed

+18
-26
lines changed

src/libraries/System.Formats.Nrbf/ref/System.Formats.Nrbf.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public static partial class NrbfDecoder
4848
public static System.Formats.Nrbf.SerializationRecord Decode(System.IO.Stream payload, out System.Collections.Generic.IReadOnlyDictionary<System.Formats.Nrbf.SerializationRecordId, System.Formats.Nrbf.SerializationRecord> recordMap, System.Formats.Nrbf.PayloadOptions options=null, bool leaveOpen=false) { throw null; }
4949
public static System.Formats.Nrbf.SerializationRecord Decode(System.IO.Stream payload, System.Formats.Nrbf.PayloadOptions? options=null, bool leaveOpen=false) { throw null; }
5050
public static System.Formats.Nrbf.ClassRecord DecodeClassRecord(System.IO.Stream payload, System.Formats.Nrbf.PayloadOptions? options=null, bool leaveOpen=false) { throw null; }
51-
public static bool StartsWithPayloadHeader(byte[] bytes) { throw null; }
51+
public static bool StartsWithPayloadHeader(System.ReadOnlySpan<byte> bytes) { throw null; }
5252
public static bool StartsWithPayloadHeader(System.IO.Stream stream) { throw null; }
5353
}
5454
public sealed partial class PayloadOptions

src/libraries/System.Formats.Nrbf/src/System/Formats/Nrbf/NrbfDecoder.cs

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Formats.Nrbf.Utils;
99
using System.Text;
1010
using System.Runtime.Serialization;
11+
using System.Runtime.InteropServices;
1112

1213
namespace System.Formats.Nrbf;
1314

@@ -18,33 +19,24 @@ public static class NrbfDecoder
1819
{
1920
private static UTF8Encoding ThrowOnInvalidUtf8Encoding { get; } = new(false, throwOnInvalidBytes: true);
2021

22+
// The header consists of:
23+
// - a byte that describes the record type (SerializationRecordType.SerializedStreamHeader)
24+
// - four 32 bit integers:
25+
// - root Id (every value is valid)
26+
// - header Id (value is ignored)
27+
// - major version, it has to be equal 1.
28+
// - minor version, it has to be equal 0.
29+
private static ReadOnlySpan<byte> HeaderSuffix => [1, 0, 0, 0, 0, 0, 0, 0];
30+
2131
/// <summary>
2232
/// Checks if given buffer starts with <see href="https://learn.microsoft.com/openspecs/windows_protocols/ms-nrbf/a7e578d3-400a-4249-9424-7529d10d1b3c">NRBF payload header</see>.
2333
/// </summary>
2434
/// <param name="bytes">The buffer to inspect.</param>
2535
/// <returns><see langword="true" /> if it starts with NRBF payload header; otherwise, <see langword="false" />.</returns>
26-
public static bool StartsWithPayloadHeader(byte[] bytes)
27-
{
28-
#if NET
29-
ArgumentNullException.ThrowIfNull(bytes);
30-
#else
31-
if (bytes is null)
32-
{
33-
throw new ArgumentNullException(nameof(bytes));
34-
}
35-
#endif
36-
37-
return bytes.Length >= SerializedStreamHeaderRecord.Size
38-
&& bytes[0] == (byte)SerializationRecordType.SerializedStreamHeader
39-
#if NET
40-
&& BinaryPrimitives.ReadInt32LittleEndian(bytes.AsSpan(9)) == SerializedStreamHeaderRecord.MajorVersion
41-
&& BinaryPrimitives.ReadInt32LittleEndian(bytes.AsSpan(13)) == SerializedStreamHeaderRecord.MinorVersion;
42-
#else
43-
&& BitConverter.ToInt32(bytes, 9) == SerializedStreamHeaderRecord.MajorVersion
44-
&& BitConverter.ToInt32(bytes, 13) == SerializedStreamHeaderRecord.MinorVersion;
45-
#endif
46-
}
47-
36+
public static bool StartsWithPayloadHeader(ReadOnlySpan<byte> bytes)
37+
=> bytes.Length >= SerializedStreamHeaderRecord.Size
38+
&& bytes[0] == (byte)SerializationRecordType.SerializedStreamHeader
39+
&& bytes.Slice(SerializedStreamHeaderRecord.Size - HeaderSuffix.Length, HeaderSuffix.Length).SequenceEqual(HeaderSuffix);
4840

4941
/// <summary>
5042
/// Checks if given stream starts with <see href="https://learn.microsoft.com/openspecs/windows_protocols/ms-nrbf/a7e578d3-400a-4249-9424-7529d10d1b3c">NRBF payload header</see>.
@@ -76,13 +68,13 @@ public static bool StartsWithPayloadHeader(Stream stream)
7668
return false;
7769
}
7870

79-
byte[] buffer = new byte[SerializedStreamHeaderRecord.Size];
80-
8171
try
8272
{
8373
#if NET
84-
stream.ReadExactly(buffer, 0, buffer.Length);
74+
Span<byte> buffer = stackalloc byte[SerializedStreamHeaderRecord.Size];
75+
stream.ReadExactly(buffer);
8576
#else
77+
byte[] buffer = new byte[SerializedStreamHeaderRecord.Size];
8678
int offset = 0;
8779
while (offset < buffer.Length)
8880
{

0 commit comments

Comments
 (0)