From 5e09012ad7b011155f47eb39700aa495cee07f06 Mon Sep 17 00:00:00 2001 From: Sunny Date: Wed, 6 Jul 2022 23:22:21 +0800 Subject: [PATCH] =?UTF-8?q?*=20FastLZ:=20=E5=A2=9E=E5=8A=A0=E4=BA=86?= =?UTF-8?q?=E6=89=A9=E5=B1=95=E7=9A=84=E8=87=AA=E5=AE=9A=E4=B9=89=E5=8E=8B?= =?UTF-8?q?=E7=BC=A9=E8=A7=A3=E5=8E=8B=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SunnyUI/Common/UFastLZ.cs | 133 +++++++++++++++++++++++++++++++++----- 1 file changed, 117 insertions(+), 16 deletions(-) diff --git a/SunnyUI/Common/UFastLZ.cs b/SunnyUI/Common/UFastLZ.cs index 0ffae9ef..821f95b8 100644 --- a/SunnyUI/Common/UFastLZ.cs +++ b/SunnyUI/Common/UFastLZ.cs @@ -25,6 +25,36 @@ * compressed form. * * 2022-03-31: V3.1.2 增加文件说明 + ****************************************************************************** + * 压缩函数 + * int fastlz_compress_level(int level, const void* input, int length, void* output); + * + * level: 压缩级别,目前,仅支持级别1和级别2。 + * 级别1是最快的压缩,通常对短数据有用。 + * 级别2稍微慢一点,但它提供了更好的压缩比。 + * 无论级别如何,压缩数据都可以使用下面的函数fastlz_decompress进行解压缩。 + * + * input: 输入缓冲区,用于存放要压缩的数据。 + * length: 输入缓冲区的大小,最小输入缓冲区大小为16。 + * output: 输出缓冲区,用于存放压缩后的数据。输出缓冲区必须至少比输入缓冲区大5%,并且不能小于66字节。 + * + * 返回值是压缩后的数据大小,如果输入不可压缩,则返回值可能大于长度。注意,输入缓冲区和输出缓冲区不能重叠。 + ****************************************************************************** + * 解压函数 + * int fastlz_decompress(const void* input, int length, void* output, int maxout); + * + * input: 输入缓冲区,用于存放要解压的数据。 + * length: 输入缓冲区的长度。 + * output: 输出缓冲区,用于存放解压后的数据。 + * maxout: 输出缓冲区的所能容纳的最大长度。解压时会保证输出缓冲区的写入量不会超过maxout中指定的值。 + * + * 返回值是解压后的数据大小。如果发生错误,例如压缩数据损坏或输出缓冲区不够大,则将返回0。 + * 注意,输入缓冲区和输出缓冲区不能重叠。 + ****************************************************************************** + * 扩展CompressEx,DecompressEx + * 扩展压缩结果增加16个字节头部和8个字节尾部,以!开头,\r\n结尾 + * 16个字节头部:8字节标识(!FastLZ )+4字节(输出缓冲区的所能容纳的最大长度maxout)+4字节(当前数据大小) + * 8个字节尾部:4字节(保留)+1字节(*)+1字节(CRC,累加和,0不判断)+2字节(\r\n) ******************************************************************************/ using System; @@ -32,7 +62,7 @@ using System.Runtime.InteropServices; namespace Sunny.UI { - internal static unsafe class FastLZx86 + public static unsafe class FastLZx86 { [DllImport("FastLZx86.dll", EntryPoint = "FastLZ_Compress", CallingConvention = CallingConvention.Cdecl)] public static extern int FastLZ_Compress(void* input, int length, void* output); @@ -44,7 +74,7 @@ namespace Sunny.UI public static extern int FastLZ_Decompress(void* input, int length, void* output, int maxout); } - internal static unsafe class FastLZx64 + public static unsafe class FastLZx64 { [DllImport("FastLZx64.dll", EntryPoint = "FastLZ_Compress", CallingConvention = CallingConvention.Cdecl)] public static extern int FastLZ_Compress(void* input, int length, void* output); @@ -56,6 +86,12 @@ namespace Sunny.UI public static extern int FastLZ_Decompress(void* input, int length, void* output, int maxout); } + public enum FastLZCompressionLevel + { + Level1 = 1, + Level2 = 2 + } + /// /// FastLZ压缩解压类 /// @@ -65,25 +101,25 @@ namespace Sunny.UI /// 是否64位 /// /// - public static bool Is64bitApp() + private static bool Is64bitApp() { return IntPtr.Size == 8; } /// - /// 压缩 + /// 压缩(原生) /// /// 输入 /// 起始位置 - /// 长度 + /// 长度 /// 压缩结果 - public static byte[] Compress(byte[] input, int begin, int len) + public static byte[] Compress(byte[] input, int begin, int length) { - byte[] output = new byte[input.Length]; + byte[] output = new byte[Math.Max(length * 2, 66)]; fixed (void* pSrc1 = &input[begin]) fixed (void* pSrc2 = output) { - int outlen = Is64bitApp() ? FastLZx64.FastLZ_Compress(pSrc1, len, pSrc2) : FastLZx86.FastLZ_Compress(pSrc1, len, pSrc2); + int outlen = Is64bitApp() ? FastLZx64.FastLZ_Compress(pSrc1, length, pSrc2) : FastLZx86.FastLZ_Compress(pSrc1, length, pSrc2); byte[] result = new byte[outlen]; Array.Copy(output, 0, result, 0, outlen); return result; @@ -91,20 +127,20 @@ namespace Sunny.UI } /// - /// 压缩 + /// 压缩(原生) /// /// 压缩级别 /// 输入 /// 起始位置 - /// 长度 + /// 长度 /// 压缩结果 - public static byte[] Compress(int level, byte[] input, int begin, int len) + public static byte[] Compress(FastLZCompressionLevel level, byte[] input, int begin, int length) { - byte[] output = new byte[input.Length]; + byte[] output = new byte[Math.Max(length * 2, 66)]; fixed (void* pSrc1 = &input[begin]) fixed (void* pSrc2 = output) { - int outlen = Is64bitApp() ? FastLZx64.FastLZ_Compress_level(level, pSrc1, len, pSrc2) : FastLZx86.FastLZ_Compress_level(level, pSrc1, len, pSrc2); + int outlen = Is64bitApp() ? FastLZx64.FastLZ_Compress_level((int)level, pSrc1, length, pSrc2) : FastLZx86.FastLZ_Compress_level((int)level, pSrc1, length, pSrc2); byte[] result = new byte[outlen]; Array.Copy(output, 0, result, 0, outlen); return result; @@ -112,7 +148,7 @@ namespace Sunny.UI } /// - /// 解压缩 + /// 解压缩(原生) /// /// 输入 /// 起始位置 @@ -121,15 +157,80 @@ namespace Sunny.UI /// 解压缩结果 public static byte[] Decompress(byte[] input, int begin, int length, int maxout) { - byte[] output = new byte[maxout]; + byte[] output = new byte[maxout + 66]; fixed (byte* pSrc1 = &input[begin]) fixed (byte* pSrc2 = output) { - int outlen = Is64bitApp() ? FastLZx64.FastLZ_Decompress(pSrc1, length, pSrc2, maxout) : FastLZx86.FastLZ_Decompress(pSrc1, length, pSrc2, maxout); + int outlen = Is64bitApp() ? FastLZx64.FastLZ_Decompress(pSrc1, length, pSrc2, output.Length) : FastLZx86.FastLZ_Decompress(pSrc1, length, pSrc2, output.Length); byte[] result = new byte[outlen]; Array.Copy(output, 0, result, 0, outlen); return result; } } + + private static byte[] ExHead = "!FastLZ".ToEnBytes(8); + private const int ExHeadAllLength = 16; + private const int ExTailAllLength = 8; + + /// + /// 压缩(扩展) + /// + /// 输入 + /// 起始位置 + /// 长度 + /// 压缩结果 + public static byte[] CompressEx(byte[] input, int begin, int length) + { + byte[] result = new byte[0]; + if (begin + length > input.Length) return result; + byte[] output = new byte[Math.Max(length * 2, 66)]; + fixed (void* pSrc1 = &input[begin]) + fixed (void* pSrc2 = output) + { + int outlen = Is64bitApp() ? FastLZx64.FastLZ_Compress(pSrc1, length, pSrc2) : FastLZx86.FastLZ_Compress(pSrc1, length, pSrc2); + result = new byte[outlen + ExHeadAllLength + ExTailAllLength]; + Array.Copy(ExHead, 0, result, 0, ExHead.Length); + Array.Copy(BitConverter.GetBytes((int)output.Length), 0, result, 8, 4); + Array.Copy(BitConverter.GetBytes((int)outlen), 0, result, 12, 4); + Array.Copy(output, 0, result, 16, outlen); + result[result.Length - 1 - 7] = 0; //保留 + result[result.Length - 1 - 6] = 0; //保留 + result[result.Length - 1 - 5] = 0; //保留 + result[result.Length - 1 - 4] = 0; //保留 + result[result.Length - 1 - 3] = 42; //* + result[result.Length - 1 - 2] = 0; //CRC + result[result.Length - 1 - 1] = 13; //\r + result[result.Length - 1 - 0] = 10; //\n + return result; + } + } + + /// + /// 解压缩(扩展) + /// + /// 输入 + /// 起始位置 + /// 长度 + /// 解压缩结果 + public static byte[] DecompressEx(byte[] input, int begin, int length) + { + byte[] result = new byte[0]; + if (input.Length <= 2 + ExHeadAllLength + ExTailAllLength) return result; + if (begin + length > input.Length) return result; + if (input[begin] != 33) return result; + if (input[begin + length - 4] != 42) return result; + if (length != BitConverter.ToInt32(input, begin + 12) + ExHeadAllLength + ExTailAllLength) return result; + + byte[] output = new byte[BitConverter.ToInt32(input, begin + ExHead.Length)]; + fixed (byte* pSrc1 = &input[begin + ExHeadAllLength]) + fixed (byte* pSrc2 = output) + { + length = length - ExHeadAllLength - ExTailAllLength; + int outlen = Is64bitApp() ? FastLZx64.FastLZ_Decompress(pSrc1, length, pSrc2, output.Length) : FastLZx86.FastLZ_Decompress(pSrc1, length, pSrc2, output.Length); + result = new byte[outlen]; + Array.Copy(output, 0, result, 0, outlen); + return result; + } + } } } \ No newline at end of file