diff --git a/Utility/MiniLZO.cs b/Utility/MiniLZO.cs new file mode 100644 index 0000000..cea1da6 --- /dev/null +++ b/Utility/MiniLZO.cs @@ -0,0 +1,548 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Diagnostics; + +namespace Utility +{ + public static class MiniLZO + { + private const uint M2_MAX_LEN = 8; + private const uint M3_MAX_LEN = 33; + private const uint M4_MAX_LEN = 9; + private const byte M3_MARKER = 32; + private const byte M4_MARKER = 16; + private const uint M1_MAX_OFFSET = 0x0400; + private const uint M2_MAX_OFFSET = 0x0800; + private const uint M3_MAX_OFFSET = 0x4000; + private const uint M4_MAX_OFFSET = 0xbfff; + private const byte BITS = 14; + private const uint D_MASK = (1 << BITS) - 1; + private const uint DICT_SIZE = 65536 + 3; + + public unsafe static void Compress(byte[] src, out byte[] dst) + { + uint tmp; + uint dstlen = (uint)(src.Length + (src.Length / 16) + 64 + 3); + dst = new byte[dstlen]; + if (src.Length <= M2_MAX_LEN + 5) + { + tmp = (uint)src.Length; + dstlen = 0; + } + else + { + byte[] workmem = new byte[DICT_SIZE]; + fixed (byte* work = workmem, input = src, output = dst) + { + byte** dict = (byte**)work; + byte* in_end = input + src.Length; + byte* ip_end = input + src.Length - M2_MAX_LEN - 5; + byte* ii = input; + byte* ip = input + 4; + byte* op = output; + bool literal = false; + bool match = false; + uint offset; + uint length; + uint index; + byte* pos; + + for (; ; ) + { + offset = 0; + index = D_INDEX1(ip); + pos = ip - (ip - dict[index]); + if (pos < input || (offset = (uint)(ip - pos)) <= 0 || offset > M4_MAX_OFFSET) + literal = true; + else if (offset <= M2_MAX_OFFSET || pos[3] == ip[3]) + { + } + else + { + index = D_INDEX2(index); + pos = ip - (ip - dict[index]); + if (pos < input || (offset = (uint)(ip - pos)) <= 0 || offset > M4_MAX_OFFSET) + literal = true; + else if (offset <= M2_MAX_OFFSET || pos[3] == ip[3]) + { + } + else + literal = true; + } + + if (!literal) + { + if (*((ushort*)pos) == *((ushort*)ip) && pos[2] == ip[2]) + match = true; + } + + literal = false; + if (!match) + { + dict[index] = ip; + ++ip; + if (ip >= ip_end) + break; + continue; + } + match = false; + dict[index] = ip; + if (ip - ii > 0) + { + uint t = (uint)(ip - ii); + if (t <= 3) + { + Debug.Assert(op - 2 > output); + op[-2] |= (byte)(t); + } + else if (t <= 18) + *op++ = (byte)(t - 3); + else + { + uint tt = t - 18; + *op++ = 0; + while (tt > 255) + { + tt -= 255; + *op++ = 0; + } + Debug.Assert(tt > 0); + *op++ = (byte)(tt); + } + do + { + *op++ = *ii++; + } while (--t > 0); + } + Debug.Assert(ii == ip); + ip += 3; + if (pos[3] != *ip++ || pos[4] != *ip++ || pos[5] != *ip++ + || pos[6] != *ip++ || pos[7] != *ip++ || pos[8] != *ip++) + { + --ip; + length = (uint)(ip - ii); + Debug.Assert(length >= 3); + Debug.Assert(length <= M2_MAX_LEN); + if (offset <= M2_MAX_OFFSET) + { + --offset; + *op++ = (byte)(((length - 1) << 5) | ((offset & 7) << 2)); + *op++ = (byte)(offset >> 3); + } + else if (offset <= M3_MAX_OFFSET) + { + --offset; + *op++ = (byte)(M3_MARKER | (length - 2)); + *op++ = (byte)((offset & 63) << 2); + *op++ = (byte)(offset >> 6); + } + else + { + offset -= 0x4000; + Debug.Assert(offset > 0); + Debug.Assert(offset <= 0x7FFF); + *op++ = (byte)(M4_MARKER | ((offset & 0x4000) >> 11) | (length - 2)); + *op++ = (byte)((offset & 63) << 2); + *op++ = (byte)(offset >> 6); + } + } + else + { + byte* m = pos + M2_MAX_LEN + 1; + while (ip < in_end && *m == *ip) + { + ++m; + ++ip; + } + length = (uint)(ip - ii); + Debug.Assert(length > M2_MAX_LEN); + if (offset <= M3_MAX_OFFSET) + { + --offset; + if (length <= 33) + *op++ = (byte)(M3_MARKER | (length - 2)); + else + { + length -= 33; + *op++ = M3_MARKER | 0; + while (length > 255) + { + length -= 255; + *op++ = 0; + } + Debug.Assert(length > 0); + *op++ = (byte)(length); + } + } + else + { + offset -= 0x4000; + Debug.Assert(offset > 0); + Debug.Assert(offset <= 0x7FFF); + if (length <= M4_MAX_LEN) + *op++ = (byte)(M4_MARKER | ((offset & 0x4000) >> 11) | (length - 2)); + else + { + length -= M4_MAX_LEN; + *op++ = (byte)(M4_MARKER | ((offset & 0x4000) >> 11)); + while (length > 255) + { + length -= 255; + *op++ = 0; + } + Debug.Assert(length > 0); + *op++ = (byte)(length); + } + } + *op++ = (byte)((offset & 63) << 2); + *op++ = (byte)(offset >> 6); + } + ii = ip; + if (ip >= ip_end) + break; + } + dstlen = (uint)(op - output); + tmp = (uint)(in_end - ii); + } + } + if (tmp > 0) + { + uint ii = (uint)src.Length - tmp; + if (dstlen == 0 && tmp <= 238) + { + dst[dstlen++] = (byte)(17 + tmp); + } + else if (tmp <= 3) + { + dst[dstlen - 2] |= (byte)(tmp); + } + else if (tmp <= 18) + { + dst[dstlen++] = (byte)(tmp - 3); + } + else + { + uint tt = tmp - 18; + dst[dstlen++] = 0; + while (tt > 255) + { + tt -= 255; + dst[dstlen++] = 0; + } + Debug.Assert(tt > 0); + dst[dstlen++] = (byte)(tt); + } + do + { + dst[dstlen++] = src[ii++]; + } while (--tmp > 0); + } + dst[dstlen++] = M4_MARKER | 1; + dst[dstlen++] = 0; + dst[dstlen++] = 0; + + if (dst.Length != dstlen) + { + byte[] final = new byte[dstlen]; + Buffer.BlockCopy(dst, 0, final, 0, (int)dstlen); + dst = final; + } + } + public unsafe static void Decompress(byte[] src, byte[] dst) + { + uint t = 0; + fixed (byte* input = src, output = dst) + { + byte* pos = null; + byte* ip_end = input + src.Length; + byte* op_end = output + dst.Length; + byte* ip = input; + byte* op = output; + bool match = false; + bool match_next = false; + bool match_done = false; + bool copy_match = false; + bool first_literal_run = false; + bool eof_found = false; + + if (*ip > 17) + { + t = (uint)(*ip++ - 17); + if (t < 4) + match_next = true; + else + { + Debug.Assert(t > 0); + if ((op_end - op) < t) + throw new OverflowException("Output Overrun"); + if ((ip_end - ip) < t + 1) + throw new OverflowException("Input Overrun"); + do + { + *op++ = *ip++; + } while (--t > 0); + first_literal_run = true; + } + } + while (!eof_found && ip < ip_end) + { + if (!match_next && !first_literal_run) + { + t = *ip++; + if (t >= 16) + match = true; + else + { + if (t == 0) + { + if ((ip_end - ip) < 1) + throw new OverflowException("Input Overrun"); + while (*ip == 0) + { + t += 255; + ++ip; + if ((ip_end - ip) < 1) + throw new OverflowException("Input Overrun"); + } + t += (uint)(15 + *ip++); + } + Debug.Assert(t > 0); + if ((op_end - op) < t + 3) + throw new OverflowException("Output Overrun"); + if ((ip_end - ip) < t + 4) + throw new OverflowException("Input Overrun"); + for (int x = 0; x < 4; ++x, ++op, ++ip) + *op = *ip; + if (--t > 0) + { + if (t >= 4) + { + do + { + for (int x = 0; x < 4; ++x, ++op, ++ip) + *op = *ip; + t -= 4; + } while (t >= 4); + if (t > 0) + { + do + { + *op++ = *ip++; + } while (--t > 0); + } + } + else + { + do + { + *op++ = *ip++; + } while (--t > 0); + } + } + } + } + if (!match && !match_next) + { + first_literal_run = false; + + t = *ip++; + if (t >= 16) + match = true; + else + { + pos = op - (1 + M2_MAX_OFFSET); + pos -= t >> 2; + pos -= *ip++ << 2; + if (pos < output || pos >= op) + throw new OverflowException("Lookbehind Overrun"); + if ((op_end - op) < 3) + throw new OverflowException("Output Overrun"); + *op++ = *pos++; + *op++ = *pos++; + *op++ = *pos++; + match_done = true; + } + } + match = false; + do + { + if (t >= 64) + { + pos = op - 1; + pos -= (t >> 2) & 7; + pos -= *ip++ << 3; + t = (t >> 5) - 1; + if (pos < output || pos >= op) + throw new OverflowException("Lookbehind Overrun"); + if ((op_end - op) < t + 2) + throw new OverflowException("Output Overrun"); + copy_match = true; + } + else if (t >= 32) + { + t &= 31; + if (t == 0) + { + if ((ip_end - ip) < 1) + throw new OverflowException("Input Overrun"); + while (*ip == 0) + { + t += 255; + ++ip; + if ((ip_end - ip) < 1) + throw new OverflowException("Input Overrun"); + } + t += (uint)(31 + *ip++); + } + pos = op - 1; + pos -= (*(ushort*)ip) >> 2; + ip += 2; + } + else if (t >= 16) + { + pos = op; + pos -= (t & 8) << 11; + + t &= 7; + if (t == 0) + { + if ((ip_end - ip) < 1) + throw new OverflowException("Input Overrun"); + while (*ip == 0) + { + t += 255; + ++ip; + if ((ip_end - ip) < 1) + throw new OverflowException("Input Overrun"); + } + t += (uint)(7 + *ip++); + } + pos -= (*(ushort*)ip) >> 2; + ip += 2; + if (pos == op) + eof_found = true; + else + pos -= 0x4000; + } + else + { + pos = op - 1; + pos -= t >> 2; + pos -= *ip++ << 2; + if (pos < output || pos >= op) + throw new OverflowException("Lookbehind Overrun"); + if ((op_end - op) < 2) + throw new OverflowException("Output Overrun"); + *op++ = *pos++; + *op++ = *pos++; + match_done = true; + } + if (!eof_found && !match_done && !copy_match) + { + if (pos < output || pos >= op) + throw new OverflowException("Lookbehind Overrun"); + Debug.Assert(t > 0); + if ((op_end - op) < t + 2) + throw new OverflowException("Output Overrun"); + } + if (!eof_found && t >= 2 * 4 - 2 && (op - pos) >= 4 && !match_done && !copy_match) + { + for (int x = 0; x < 4; ++x, ++op, ++pos) + *op = *pos; + t -= 2; + do + { + for (int x = 0; x < 4; ++x, ++op, ++pos) + *op = *pos; + t -= 4; + + } while (t >= 4); + if (t > 0) + { + do + { + *op++ = *pos++; + } while (--t > 0); + } + } + else if (!eof_found && !match_done) + { + copy_match = false; + + *op++ = *pos++; + *op++ = *pos++; + do + { + *op++ = *pos++; + } while (--t > 0); + } + + if (!eof_found && !match_next) + { + match_done = false; + + t = (uint)(ip[-2] & 3); + if (t == 0) + break; + } + if (!eof_found) + { + match_next = false; + Debug.Assert(t > 0); + Debug.Assert(t < 4); + if ((op_end - op) < t) + throw new OverflowException("Output Overrun"); + if ((ip_end - ip) < t + 1) + throw new OverflowException("Input Overrun"); + *op++ = *ip++; + if (t > 1) + { + *op++ = *ip++; + if (t > 2) + *op++ = *ip++; + } + t = *ip++; + } + } while (!eof_found && ip < ip_end); + } + if (!eof_found) + throw new OverflowException("EOF Marker Not Found"); + else + { + Debug.Assert(t == 1); + if (ip > ip_end) + throw new OverflowException("Input Overrun"); + else if (ip < ip_end) + throw new OverflowException("Input Not Consumed"); + } + } + } + + private unsafe static uint D_INDEX1(byte* input) + { + return D_MS(D_MUL(0x21, D_X3(input, 5, 5, 6)) >> 5, 0); + } + private static uint D_INDEX2(uint idx) + { + return (idx & (D_MASK & 0x7FF)) ^ (((D_MASK >> 1) + 1) | 0x1F); + } + private static uint D_MS(uint v, byte s) + { + return (v & (D_MASK >> s)) << s; + } + private static uint D_MUL(uint a, uint b) + { + return a * b; + } + private unsafe static uint D_X2(byte* input, byte s1, byte s2) + { + return (uint)((((input[2] << s2) ^ input[1]) << s1) ^ input[0]); + } + private unsafe static uint D_X3(byte* input, byte s1, byte s2, byte s3) + { + return (D_X2(input + 1, s2, s3) << s1) ^ input[0]; + } + } +} diff --git a/Utility/Properties/AssemblyInfo.cs b/Utility/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..d30ffde --- /dev/null +++ b/Utility/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 어셈블리의 일반 정보는 다음 특성 집합을 통해 제어됩니다. +// 어셈블리와 관련된 정보를 수정하려면 +// 이 특성 값을 변경하십시오. +[assembly: AssemblyTitle("Utility")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Utility")] +[assembly: AssemblyCopyright("Copyright © 2022")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// ComVisible을 false로 설정하면 이 어셈블리의 형식이 COM 구성 요소에 +// 표시되지 않습니다. COM에서 이 어셈블리의 형식에 액세스하려면 +// 해당 형식에 대해 ComVisible 특성을 true로 설정하십시오. +[assembly: ComVisible(false)] + +// 이 프로젝트가 COM에 노출되는 경우 다음 GUID는 typelib의 ID를 나타냅니다. +[assembly: Guid("17877773-9fc8-4b5b-ba89-301e3800cbb7")] + +// 어셈블리의 버전 정보는 다음 네 가지 값으로 구성됩니다. +// +// 주 버전 +// 부 버전 +// 빌드 번호 +// 수정 버전 +// +// 모든 값을 지정하거나 아래와 같이 '*'를 사용하여 빌드 번호 및 수정 버전이 자동으로 +// 지정되도록 할 수 있습니다. +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Utility/Utility.csproj b/Utility/Utility.csproj new file mode 100644 index 0000000..6d630f5 --- /dev/null +++ b/Utility/Utility.csproj @@ -0,0 +1,56 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {B1FDE30A-B142-42D5-A6B8-5428D2F2E62A} + Library + Properties + Utility + Utility + v4.0 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + x86 + true + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + \ No newline at end of file