From 4208e223a0019d893995808c9eac060ed855138c Mon Sep 17 00:00:00 2001
From: "SmallChi(Koike)" <564952747@qq.com>
Date: Sat, 10 Oct 2020 23:06:33 +0800
Subject: [PATCH] =?UTF-8?q?1.=E5=8D=87=E7=BA=A7=E5=BA=93=E4=BB=A5=E5=8F=8A?=
 =?UTF-8?q?=E5=AF=B9=E5=BA=94=E7=9A=84dotnetcore=E9=85=8D=E7=BD=AE?=
 =?UTF-8?q?=E6=96=87=E4=BB=B6=202.=E5=AE=8C=E5=96=84=E4=B8=80=E4=B8=8B?=
 =?UTF-8?q?=E9=99=84=E4=BB=B6=E7=9A=84=E5=88=86=E6=9E=90=E5=99=A8=203.?=
 =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=96=87=E6=A1=A3=E5=86=85=E5=AE=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .github/workflows/dotnetcore.yml              |   2 +-
 README.md                                     |  11 +-
 ...ocol.Extensions.JTActiveSafety.Test.csproj |   6 +-
 ....Protocol.Extensions.JTActiveSafety.csproj |   4 +-
 .../JTActiveSafety.Protocol.Test.csproj       |   4 +-
 .../Extensions/HexExtensions.cs               | 172 ++++++++++++++++++
 .../JTActiveSafety.Protocol.csproj            |   5 +-
 .../JTActiveSafetySerializer.cs               |  36 +++-
 8 files changed, 223 insertions(+), 17 deletions(-)
 create mode 100644 src/JTActiveSafety.Protocol/Extensions/HexExtensions.cs

diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml
index f23939b..ae99996 100644
--- a/.github/workflows/dotnetcore.yml
+++ b/.github/workflows/dotnetcore.yml
@@ -12,7 +12,7 @@ jobs:
     - name: Setup .NET Core
       uses: actions/setup-dotnet@master
       with:
-        dotnet-version: 3.1.101
+         dotnet-version: 3.1.401
     - name: dotnet info
       run: dotnet --info
     - name: dotnet restore
diff --git a/README.md b/README.md
index 033d44f..52a9ffd 100644
--- a/README.md
+++ b/README.md
@@ -7,14 +7,13 @@ JTActiveSafety协议、道路运输车辆主动安全智能防控系统-主动
 
 [![MIT Licence](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/SmallChi/JTActiveSafety/blob/master/LICENSE)![.NET Core](https://github.com/SmallChi/JTActiveSafety/workflows/.NET%20Core/badge.svg?branch=master)
 
-## 基于JT808扩展的JTActiveSafety消息协议
-
 ## NuGet安装
 
-| Package Name          | Version                                            | Downloads                                           |
-| --------------------- | -------------------------------------------------- | --------------------------------------------------- |
-| Install-Package JT808 | ![JT808](https://img.shields.io/nuget/v/JT808.svg) | ![JT808](https://img.shields.io/nuget/dt/JT808.svg) |
-| Install-Package JT808.Protocol.Extensions.JTActiveSafety| ![JT808.Protocol.Extensions.JTActiveSafety](https://img.shields.io/nuget/v/JT808.Protocol.Extensions.JTActiveSafety.svg) | ![JT808](https://img.shields.io/nuget/dt/JT808.Protocol.Extensions.JTActiveSafety.svg) |
+| Package Name          | Version                                            | Downloads|                                     Remark      |
+| --------------------- | -------------------------------------------------- | --------------------------------------------------- |--------------------------------------------------- |
+| Install-Package JTActiveSafety| ![JTActiveSafety](https://img.shields.io/nuget/v/JTActiveSafety.svg) | ![JT808](https://img.shields.io/nuget/dt/JTActiveSafety.svg) |主动安全的附件协议|
+| Install-Package JT808 | ![JT808](https://img.shields.io/nuget/v/JT808.svg) | ![JT808](https://img.shields.io/nuget/dt/JT808.svg) |基础JT808协议|
+| Install-Package JT808.Protocol.Extensions.JTActiveSafety| ![JT808.Protocol.Extensions.JTActiveSafety](https://img.shields.io/nuget/v/JT808.Protocol.Extensions.JTActiveSafety.svg) | ![JT808](https://img.shields.io/nuget/dt/JT808.Protocol.Extensions.JTActiveSafety.svg) |基于JT808扩展的JTActiveSafety消息协议|
 
 ### JT808扩展协议消息对照表
 
diff --git a/src/JT808.Protocol.Extensions.JTActiveSafety.Test/JT808.Protocol.Extensions.JTActiveSafety.Test.csproj b/src/JT808.Protocol.Extensions.JTActiveSafety.Test/JT808.Protocol.Extensions.JTActiveSafety.Test.csproj
index 5e58ae8..c0d3bbe 100644
--- a/src/JT808.Protocol.Extensions.JTActiveSafety.Test/JT808.Protocol.Extensions.JTActiveSafety.Test.csproj
+++ b/src/JT808.Protocol.Extensions.JTActiveSafety.Test/JT808.Protocol.Extensions.JTActiveSafety.Test.csproj
@@ -7,10 +7,10 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.3" />
-    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
+    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.8" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
     <PackageReference Include="xunit" Version="2.4.1" />
-    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
+    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
       <PrivateAssets>all</PrivateAssets>
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
     </PackageReference>
diff --git a/src/JT808.Protocol.Extensions.JTActiveSafety/JT808.Protocol.Extensions.JTActiveSafety.csproj b/src/JT808.Protocol.Extensions.JTActiveSafety/JT808.Protocol.Extensions.JTActiveSafety.csproj
index 28be818..9c94bbb 100644
--- a/src/JT808.Protocol.Extensions.JTActiveSafety/JT808.Protocol.Extensions.JTActiveSafety.csproj
+++ b/src/JT808.Protocol.Extensions.JTActiveSafety/JT808.Protocol.Extensions.JTActiveSafety.csproj
@@ -15,7 +15,7 @@
     <licenseUrl>https://github.com/SmallChi/JTActiveSafety/blob/master/LICENSE</licenseUrl>
     <license>https://github.com/SmallChi/JTActiveSafety/blob/master/LICENSE</license>
     <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
-    <Version>1.0.4</Version>
+    <Version>1.0.5</Version>
     <PackageLicenseFile>LICENSE</PackageLicenseFile>
   </PropertyGroup>
 
@@ -35,7 +35,7 @@
   </ItemGroup>
 
   <ItemGroup>
-    <PackageReference Include="JT808" Version="2.2.10" />
+    <PackageReference Include="JT808" Version="2.2.12" />
   </ItemGroup>
 
 
diff --git a/src/JTActiveSafety.Protocol.Test/JTActiveSafety.Protocol.Test.csproj b/src/JTActiveSafety.Protocol.Test/JTActiveSafety.Protocol.Test.csproj
index 7e6211a..39267b4 100644
--- a/src/JTActiveSafety.Protocol.Test/JTActiveSafety.Protocol.Test.csproj
+++ b/src/JTActiveSafety.Protocol.Test/JTActiveSafety.Protocol.Test.csproj
@@ -7,9 +7,9 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
     <PackageReference Include="xunit" Version="2.4.1" />
-    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
+    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
       <PrivateAssets>all</PrivateAssets>
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
     </PackageReference>
diff --git a/src/JTActiveSafety.Protocol/Extensions/HexExtensions.cs b/src/JTActiveSafety.Protocol/Extensions/HexExtensions.cs
new file mode 100644
index 0000000..ff3420b
--- /dev/null
+++ b/src/JTActiveSafety.Protocol/Extensions/HexExtensions.cs
@@ -0,0 +1,172 @@
+using System;
+
+namespace JTActiveSafety.Protocol.Extensions
+{
+    /// <summary>
+    /// 
+    /// ref:"www.codeproject.com/tips/447938/high-performance-csharp-byte-array-to-hex-string-t"
+    /// </summary>
+    public static partial class HexExtensions
+    {
+        public static string ToHexString(this byte[] source)
+        {
+            return HexUtil.DoHexDump(source, 0, source.Length).ToUpper();
+        }
+
+        public static int WriteHexStringLittle(byte[] bytes, int offset, string data, int len)
+        {
+            if (data == null) data = "";
+            data = data.Replace(" ", "");
+            int startIndex = 0;
+            if (data.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
+            {
+                startIndex = 2;
+            }
+            int length = len;
+            if (length == -1)
+            {
+                length = (data.Length - startIndex) / 2;
+            }
+            int noOfZero = length * 2 + startIndex - data.Length;
+            if (noOfZero > 0)
+            {
+                data = data.Insert(startIndex, new string('0', noOfZero));
+            }
+            int byteIndex = 0;
+            while (startIndex < data.Length && byteIndex < length)
+            {
+                bytes[offset + byteIndex] = Convert.ToByte(data.Substring(startIndex, 2), 16);
+                startIndex += 2;
+                byteIndex++;
+            }
+            return length;
+        }
+
+        /// <summary>
+        /// 16进制字符串转16进制数组
+        /// </summary>
+        /// <param name="hexString"></param>
+        /// <param name="separator"></param>
+        /// <returns></returns>
+        public static byte[] ToHexBytes(this string hexString)
+        {
+            hexString = hexString.Replace(" ", "");
+            byte[] buf = new byte[hexString.Length / 2];
+            ReadOnlySpan<char> readOnlySpan = hexString.AsSpan();
+            for (int i = 0; i < hexString.Length; i++)
+            {
+                if (i % 2 == 0)
+                {
+                    buf[i / 2] = Convert.ToByte(readOnlySpan.Slice(i, 2).ToString(), 16);
+                }
+            }
+            return buf;
+        }
+
+        public static string ReadHexStringLittle(ReadOnlySpan<byte> read, ref int offset, int len)
+        {
+            ReadOnlySpan<byte> source = read.Slice(offset, len);
+            string hex = HexUtil.DoHexDump(read, offset, len);
+            offset += len;
+            return hex;
+        }
+
+        public static string ReadNumber(this byte value, string format = "X2")
+        {
+            return value.ToString(format);
+        }
+        public static string ReadNumber(this int value, string format = "X8")
+        {
+            return value.ToString(format);
+        }
+        public static string ReadNumber(this uint value, string format = "X8")
+        {
+            return value.ToString(format);
+        }
+        public static string ReadNumber(this long value, string format = "X16")
+        {
+            return value.ToString(format);
+        }
+        public static string ReadNumber(this ulong value, string format = "X16")
+        {
+            return value.ToString(format);
+        }
+        public static string ReadNumber(this short value, string format = "X4")
+        {
+            return value.ToString(format);
+        }
+        public static string ReadNumber(this ushort value, string format = "X4")
+        {
+            return value.ToString(format);
+        }
+        public static ReadOnlySpan<char> ReadBinary(this ushort value)
+        {
+            return System.Convert.ToString(value, 2).PadLeft(16, '0').AsSpan();
+        }
+        public static ReadOnlySpan<char> ReadBinary(this short value)
+        {
+            return System.Convert.ToString(value, 2).PadLeft(16, '0').AsSpan();
+        }
+        public static ReadOnlySpan<char> ReadBinary(this uint value)
+        {
+            return System.Convert.ToString(value, 2).PadLeft(32, '0').AsSpan();
+        }
+        public static ReadOnlySpan<char> ReadBinary(this int value)
+        {
+            return System.Convert.ToString(value, 2).PadLeft(32, '0').AsSpan();
+        }
+        public static ReadOnlySpan<char> ReadBinary(this byte value)
+        {
+            return System.Convert.ToString(value, 2).PadLeft(8, '0').AsSpan();
+        }
+
+    }
+
+    public static class HexUtil
+    {
+        static readonly char[] HexdumpTable = new char[256 * 4];
+        static HexUtil()
+        {
+            char[] digits = "0123456789ABCDEF".ToCharArray();
+            for (int i = 0; i < 256; i++)
+            {
+                HexdumpTable[i << 1] = digits[(int)((uint)i >> 4 & 0x0F)];
+                HexdumpTable[(i << 1) + 1] = digits[i & 0x0F];
+            }
+        }
+
+        public static string DoHexDump(ReadOnlySpan<byte> buffer, int fromIndex, int length)
+        {
+            if (length == 0)
+            {
+                return "";
+            }
+            int endIndex = fromIndex + length;
+            var buf = new char[length << 1];
+            int srcIdx = fromIndex;
+            int dstIdx = 0;
+            for (; srcIdx < endIndex; srcIdx++, dstIdx += 2)
+            {
+                Array.Copy(HexdumpTable, buffer[srcIdx] << 1, buf, dstIdx, 2);
+            }
+            return new string(buf);
+        }
+
+        public static string DoHexDump(byte[] array, int fromIndex, int length)
+        {
+            if (length == 0)
+            {
+                return "";
+            }
+            int endIndex = fromIndex + length;
+            var buf = new char[length << 1];
+            int srcIdx = fromIndex;
+            int dstIdx = 0;
+            for (; srcIdx < endIndex; srcIdx++, dstIdx += 2)
+            {
+                Array.Copy(HexdumpTable, (array[srcIdx] & 0xFF) << 1, buf, dstIdx, 2);
+            }
+            return new string(buf);
+        }
+    }
+}
diff --git a/src/JTActiveSafety.Protocol/JTActiveSafety.Protocol.csproj b/src/JTActiveSafety.Protocol/JTActiveSafety.Protocol.csproj
index 57c943e..4cb48a3 100644
--- a/src/JTActiveSafety.Protocol/JTActiveSafety.Protocol.csproj
+++ b/src/JTActiveSafety.Protocol/JTActiveSafety.Protocol.csproj
@@ -19,7 +19,10 @@
     <PackageLicenseFile>LICENSE</PackageLicenseFile>
   </PropertyGroup>
   <ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
-    <PackageReference Include="System.Memory" Version="4.5.3" />
+    <PackageReference Include="System.Memory" Version="4.5.4" />
+  </ItemGroup>
+  <ItemGroup>
+    <PackageReference Include="System.Text.Json" Version="4.7.2" />
   </ItemGroup>
   <ItemGroup>
     <None Include="..\..\LICENSE">
diff --git a/src/JTActiveSafety.Protocol/JTActiveSafetySerializer.cs b/src/JTActiveSafety.Protocol/JTActiveSafetySerializer.cs
index 023c64c..4751de2 100644
--- a/src/JTActiveSafety.Protocol/JTActiveSafetySerializer.cs
+++ b/src/JTActiveSafety.Protocol/JTActiveSafetySerializer.cs
@@ -1,14 +1,18 @@
 using JTActiveSafety.Protocol.Buffers;
+using JTActiveSafety.Protocol.Extensions;
 using JTActiveSafety.Protocol.MessagePack;
 using System;
 using System.Collections.Generic;
+using System.IO;
+using System.Linq;
 using System.Text;
+using System.Text.Json;
 
 namespace JTActiveSafety.Protocol
 {
     public static class JTActiveSafetySerializer
     {
-        public static byte[] Serialize(JTActiveSafetyPackage package, int minBufferSize = 4096)
+        public static byte[] Serialize(JTActiveSafetyPackage package, int minBufferSize = 65 * 1024)
         {
             byte[] buffer = JTActiveSafetyArrayPool.Rent(minBufferSize);
             try
@@ -17,7 +21,7 @@ namespace JTActiveSafety.Protocol
                 writer.WriteUInt32(package.FH_Flag);
                 writer.WriteString(package.FileName);
                 writer.WriteUInt32(package.Offset);
-                writer.WriteUInt32(package.Length);
+                writer.WriteUInt32((uint)package.Bodies.Length);
                 writer.WriteArray(package.Bodies);
                 return writer.FlushAndGetArray();
             }
@@ -38,5 +42,33 @@ namespace JTActiveSafety.Protocol
             jTActiveSafetyPackage.Bodies = reader.ReadRemainArray().ToArray();
             return jTActiveSafetyPackage;
         }
+
+        public static byte[] AnalyzeJsonBuffer(ReadOnlySpan<byte> bytes, JsonWriterOptions options = default)
+        {
+            JTActiveSafetyMessagePackReader reader = new JTActiveSafetyMessagePackReader(bytes);
+            using (MemoryStream memoryStream = new MemoryStream())
+            using (Utf8JsonWriter writer = new Utf8JsonWriter(memoryStream, options))
+            {
+                writer.WriteStartObject();
+                var header = reader.ReadUInt32();
+                writer.WriteString($"[{header}]头部", header.ReadNumber());
+                var FileName = reader.ReadString(50);
+                writer.WriteString($"[文件名称]", FileName);
+                var offset = reader.ReadUInt32();
+                writer.WriteNumber($"{offset}[数据偏移量]", offset);
+                var length = reader.ReadUInt32();
+                writer.WriteNumber($"{length}[数据长度]", length);
+                var bodies = reader.ReadRemainArray().ToArray();
+                writer.WriteString("[数据体]", string.Join(" ", (bodies).Select(p => p.ToString("X2"))));
+                writer.WriteEndObject();
+                writer.Flush();
+                return memoryStream.ToArray();
+            }
+        }
+        public static string Analyze(ReadOnlySpan<byte> bytes, JsonWriterOptions options = default)
+        {
+            string json = Encoding.UTF8.GetString(AnalyzeJsonBuffer(bytes, options));
+            return json;
+        }
     }
 }