diff --git a/NewLife.Core/Security/Crc16.cs b/NewLife.Core/Security/Crc16.cs
index ff04d3c05..eff0069ed 100644
--- a/NewLife.Core/Security/Crc16.cs
+++ b/NewLife.Core/Security/Crc16.cs
@@ -42,8 +42,9 @@ public sealed class Crc16
0x6E17,0x7E36,0x4E55,0x5E74,0x2E93,0x3EB2,0x0ED1,0x1EF0
];
+ const UInt16 CrcSeed = 0xFFFF;
/// 校验值
- public UInt16 Value { get; set; } = 0xFFFF;
+ public UInt16 Value { get; set; } = CrcSeed;
#endregion
/// 重置清零
@@ -71,8 +72,7 @@ public Crc16 Update(Byte[] buffer, Int32 offset = 0, Int32 count = -1)
if (count < 0) count = buffer.Length;
if (offset < 0 || offset + count > buffer.Length) throw new ArgumentOutOfRangeException(nameof(offset));
- var crc = Value;
- crc ^= crc;
+ var crc = (UInt16)(Value ^ CrcSeed);
for (var i = 0; i < count; i++)
{
crc = (UInt16)((crc << 8) ^ CrcTable[(crc >> 8 ^ buffer[offset + i]) & 0xFF]);
@@ -82,28 +82,44 @@ public Crc16 Update(Byte[] buffer, Int32 offset = 0, Int32 count = -1)
return this;
}
+ /// 添加数据区进行检验
+ ///
+ ///
+ public Crc16 Update(ReadOnlySpan buffer)
+ {
+ var crc = (UInt16)(Value ^ CrcSeed);
+ for (var i = 0; i < buffer.Length; i++)
+ {
+ crc = (UInt16)((crc << 8) ^ CrcTable[(crc >> 8 ^ buffer[i]) & 0xFF]);
+ }
+ Value = crc;
+
+ return this;
+ }
+
/// 添加数据流进行校验,不查表计算 CRC-16 x16+x15+x2+1 8005 IBM SDLC
///
/// 数量
public Crc16 Update(Stream stream, Int64 count = -1)
{
if (stream == null) throw new ArgumentNullException(nameof(stream));
- if (count <= 0) count = Int64.MaxValue;
+ if (count <= 0) count = stream.Length - stream.Position;
- var crc = Value;
+ var crc = (UInt16)(Value ^ CrcSeed);
while (--count >= 0)
{
var b = stream.ReadByte();
if (b == -1) break;
- crc ^= (Byte)b;
- for (var i = 0; i < 8; i++)
- {
- if ((crc & 0x0001) != 0)
- crc = (UInt16)((crc >> 1) ^ 0xa001);
- else
- crc = (UInt16)(crc >> 1);
- }
+ crc = (UInt16)((crc << 8) ^ CrcTable[(crc >> 8 ^ b) & 0xFF]);
+ //crc ^= (Byte)b;
+ //for (var i = 0; i < 8; i++)
+ //{
+ // if ((crc & 0x0001) != 0)
+ // crc = (UInt16)((crc >> 1) ^ 0xa001);
+ // else
+ // crc = (UInt16)(crc >> 1);
+ //}
}
Value = crc;
@@ -122,6 +138,16 @@ public static UInt16 Compute(Byte[] buf, Int32 offset = 0, Int32 count = -1)
return crc.Value;
}
+ /// 计算校验码
+ ///
+ ///
+ public static UInt16 Compute(ReadOnlySpan buffer)
+ {
+ var crc = new Crc16();
+ crc.Update(buffer);
+ return crc.Value;
+ }
+
/// 计算数据流校验码
///
///
@@ -143,7 +169,7 @@ public static UInt16 Compute(Stream stream, Int32 count = -1)
/// 如果大于等于0,则表示从该位置开始计算
/// 字节数偏移量,一般用负数表示
///
- public static UInt16 Compute(Stream stream, Int64 position = -1, Int32 count = -1)
+ public static UInt16 Compute(Stream stream, Int64 position, Int32 count)
{
if (position >= 0)
{
@@ -172,7 +198,7 @@ public static UInt16 ComputeModbus(Byte[] data, Int32 offset, Int32 count = -1)
UInt16 u = 0xFFFF;
Byte b;
- if (count == 0) count = data.Length - offset;
+ if (count <= 0) count = data.Length - offset;
for (var i = offset; i < count; i++)
{
diff --git a/NewLife.Core/Security/Crc32.cs b/NewLife.Core/Security/Crc32.cs
index cc8179a77..e9b9a3861 100644
--- a/NewLife.Core/Security/Crc32.cs
+++ b/NewLife.Core/Security/Crc32.cs
@@ -1,6 +1,5 @@
namespace NewLife.Security;
-
/// CRC32校验
///
/// Generate a table for a byte-wise 32-bit CRC calculation on the polynomial:
@@ -100,6 +99,19 @@ public Crc32 Update(Byte[] buffer, Int32 offset = 0, Int32 count = -1)
return this;
}
+ /// 添加数据区进行检验
+ ///
+ ///
+ public Crc32 Update(ReadOnlySpan buffer)
+ {
+ for (var i = 0; i < buffer.Length; i++)
+ {
+ crc = Table[(crc ^ buffer[i]) & 0xFF] ^ (crc >> 8);
+ }
+
+ return this;
+ }
+
/// 添加数据流进行校验
///
/// 数量
@@ -132,6 +144,16 @@ public static UInt32 Compute(Byte[] buf, Int32 offset = 0, Int32 count = -1)
return crc.Value;
}
+ /// 计算校验码
+ ///
+ ///
+ public static UInt32 Compute(ReadOnlySpan buffer)
+ {
+ var crc = new Crc32();
+ crc.Update(buffer);
+ return crc.Value;
+ }
+
/// 计算数据流校验码
///
///
diff --git a/NewLife.Core/Serialization/Binary/Binary.cs b/NewLife.Core/Serialization/Binary/Binary.cs
index 1729baaf4..08d81194c 100644
--- a/NewLife.Core/Serialization/Binary/Binary.cs
+++ b/NewLife.Core/Serialization/Binary/Binary.cs
@@ -1,4 +1,6 @@
-using System.Reflection;
+using System.Buffers;
+using System.Reflection;
+using System.Runtime.InteropServices;
using NewLife.Collections;
using NewLife.Data;
using NewLife.Reflection;
@@ -148,6 +150,41 @@ public virtual void Write(Byte[] buffer, Int32 offset, Int32 count)
Stream.Write(buffer, offset, count);
}
+ /// 写入数据
+ ///
+ public virtual void Write(ReadOnlySpan buffer)
+ {
+#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
+ Stream.Write(buffer);
+#else
+ var array = ArrayPool.Shared.Rent(buffer.Length);
+ try
+ {
+ buffer.CopyTo(array);
+
+ Stream.Write(array, 0, buffer.Length);
+ }
+ finally
+ {
+ ArrayPool.Shared.Return(array);
+ }
+#endif
+ }
+
+ /// 写入数据
+ ///
+ public virtual void Write(ReadOnlyMemory buffer)
+ {
+ if (MemoryMarshal.TryGetArray(buffer, out var segment))
+ {
+ Stream.Write(segment.Array!, segment.Offset, segment.Count);
+
+ return;
+ }
+
+ Write(buffer.Span);
+ }
+
/// 写入大小,如果有FieldSize则返回,否则写入编码的大小并返回-1
///
///
diff --git a/XUnitTest.Core/Security/Crc16Tests.cs b/XUnitTest.Core/Security/Crc16Tests.cs
new file mode 100644
index 000000000..3d5fd11e1
--- /dev/null
+++ b/XUnitTest.Core/Security/Crc16Tests.cs
@@ -0,0 +1,49 @@
+using NewLife.Security;
+using Xunit;
+
+namespace XUnitTest.Security;
+
+public class Crc16Tests
+{
+ [Fact]
+ public void TestComputeWithByteArray()
+ {
+ var data = "123456789"u8.ToArray();
+ var crc = Crc16.Compute(data);
+ Assert.Equal(0x31C3, crc);
+ }
+
+ [Fact]
+ public void TestComputeWithStream()
+ {
+ var data = "123456789"u8.ToArray();
+ using var stream = new MemoryStream(data);
+ var crc = Crc16.Compute(stream, -1);
+ Assert.Equal(0x31C3, crc);
+ }
+
+ [Fact]
+ public void TestComputeWithReadOnlySpan()
+ {
+ var data = "123456789"u8.ToArray();
+ var crc = Crc16.Compute(new ReadOnlySpan(data));
+ Assert.Equal(0x31C3, crc);
+ }
+
+ [Fact]
+ public void TestComputeModbusWithByteArray()
+ {
+ var data = "123456789"u8.ToArray();
+ var crc = Crc16.ComputeModbus(data, 0);
+ Assert.Equal(0x4B37, crc);
+ }
+
+ [Fact]
+ public void TestComputeModbusWithStream()
+ {
+ var data = "123456789"u8.ToArray();
+ using var stream = new MemoryStream(data);
+ var crc = Crc16.ComputeModbus(stream);
+ Assert.Equal(0x4B37, crc);
+ }
+}
diff --git a/XUnitTest.Core/Security/Crc32Tests.cs b/XUnitTest.Core/Security/Crc32Tests.cs
new file mode 100644
index 000000000..8c960cd91
--- /dev/null
+++ b/XUnitTest.Core/Security/Crc32Tests.cs
@@ -0,0 +1,90 @@
+using NewLife.Security;
+using Xunit;
+
+namespace XUnitTest.Security;
+
+public class Crc32Tests
+{
+ [Fact]
+ public void Compute_ByteArray_ReturnsExpectedCrc()
+ {
+ Byte[] data = { 1, 2, 3, 4, 5 };
+ var expectedCrc = 0x470B99F4u;
+
+ var actualCrc = Crc32.Compute(data);
+
+ Assert.Equal(expectedCrc, actualCrc);
+ }
+
+ [Fact]
+ public void Compute_ReadOnlySpan_ReturnsExpectedCrc()
+ {
+ Byte[] data = { 1, 2, 3, 4, 5 };
+ var expectedCrc = 0x470B99F4u;
+
+ var actualCrc = Crc32.Compute(new ReadOnlySpan(data));
+
+ Assert.Equal(expectedCrc, actualCrc);
+ }
+
+ [Fact]
+ public void Compute_Stream_ReturnsExpectedCrc()
+ {
+ Byte[] data = { 1, 2, 3, 4, 5 };
+ var expectedCrc = 0x470B99F4u;
+
+ using var stream = new MemoryStream(data);
+ var actualCrc = Crc32.Compute(stream);
+
+ Assert.Equal(expectedCrc, actualCrc);
+ }
+
+ [Fact]
+ public void ComputeRange_Stream_ReturnsExpectedCrc()
+ {
+ Byte[] data = { 1, 2, 3, 4, 5 };
+ var expectedCrc = 0x470B99F4u;
+
+ using var stream = new MemoryStream(data);
+ var actualCrc = Crc32.ComputeRange(stream, 0, data.Length);
+
+ Assert.Equal(expectedCrc, actualCrc);
+ }
+
+ [Fact]
+ public void Update_ByteArray_ReturnsExpectedCrc()
+ {
+ Byte[] data = { 1, 2, 3, 4, 5 };
+ var expectedCrc = 0x470B99F4u;
+
+ var crc32 = new Crc32();
+ crc32.Update(data);
+
+ Assert.Equal(expectedCrc, crc32.Value);
+ }
+
+ [Fact]
+ public void Update_ReadOnlySpan_ReturnsExpectedCrc()
+ {
+ Byte[] data = { 1, 2, 3, 4, 5 };
+ var expectedCrc = 0x470B99F4u;
+
+ var crc32 = new Crc32();
+ crc32.Update(new ReadOnlySpan(data));
+
+ Assert.Equal(expectedCrc, crc32.Value);
+ }
+
+ [Fact]
+ public void Update_Stream_ReturnsExpectedCrc()
+ {
+ Byte[] data = { 1, 2, 3, 4, 5 };
+ var expectedCrc = 0x470B99F4u;
+
+ using var stream = new MemoryStream(data);
+ var crc32 = new Crc32();
+ crc32.Update(stream);
+
+ Assert.Equal(expectedCrc, crc32.Value);
+ }
+}