mirror of
https://github.com/gnh1201/welsonjs.git
synced 2025-05-12 12:41:04 +00:00
105 lines
3.4 KiB
C#
105 lines
3.4 KiB
C#
/*
|
|
* WelsonJS.Toolkit: WelsonJS native component
|
|
*
|
|
* filename:
|
|
* LZ77.cs
|
|
*
|
|
* description:
|
|
* MsCompress(LZ77) algorithm implementation for WelsonJS
|
|
*
|
|
* website:
|
|
* - https://github.com/gnh1201/welsonjs
|
|
* - https://catswords.social/@catswords_oss
|
|
* - https://teams.live.com/l/community/FEACHncAhq8ldnojAI
|
|
*
|
|
* author:
|
|
* Namhyeon Go <abuse@catswords.net>
|
|
*
|
|
* license:
|
|
* GPLv3 or MS-RL(Microsoft Reciprocal License)
|
|
*
|
|
*/
|
|
using System.Text;
|
|
|
|
namespace WelsonJS.Compression
|
|
{
|
|
public class LZ77
|
|
{
|
|
public static string Compress(string input)
|
|
{
|
|
StringBuilder compressed = new StringBuilder();
|
|
int searchBufferIndex = 0;
|
|
|
|
while (searchBufferIndex < input.Length)
|
|
{
|
|
int longestMatchLength = 0;
|
|
int longestMatchOffset = 0;
|
|
|
|
// Search for the longest match in the look-ahead buffer
|
|
for (int i = 0; i < searchBufferIndex; i++)
|
|
{
|
|
int matchLength = 0;
|
|
while (matchLength < input.Length - searchBufferIndex && input[i + matchLength] == input[searchBufferIndex + matchLength])
|
|
{
|
|
matchLength++;
|
|
}
|
|
|
|
if (matchLength > longestMatchLength)
|
|
{
|
|
longestMatchLength = matchLength;
|
|
longestMatchOffset = searchBufferIndex - i;
|
|
}
|
|
}
|
|
|
|
// Output the token (offset, length)
|
|
if (longestMatchLength > 0)
|
|
{
|
|
compressed.Append($"({longestMatchOffset},{longestMatchLength})");
|
|
searchBufferIndex += longestMatchLength;
|
|
}
|
|
else
|
|
{
|
|
compressed.Append($"(0,{input[searchBufferIndex]})");
|
|
searchBufferIndex++;
|
|
}
|
|
}
|
|
|
|
return compressed.ToString();
|
|
}
|
|
|
|
public static string Decompress(string compressedData)
|
|
{
|
|
StringBuilder decompressed = new StringBuilder();
|
|
int currentIndex = 0;
|
|
|
|
while (currentIndex < compressedData.Length)
|
|
{
|
|
if (compressedData[currentIndex] == '(')
|
|
{
|
|
// Match case
|
|
int commaIndex = compressedData.IndexOf(',', currentIndex);
|
|
int offset = int.Parse(compressedData.Substring(currentIndex + 1, commaIndex - currentIndex - 1));
|
|
int closingParenIndex = compressedData.IndexOf(')', commaIndex);
|
|
int length = int.Parse(compressedData.Substring(commaIndex + 1, closingParenIndex - commaIndex - 1));
|
|
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
int copyIndex = decompressed.Length - offset;
|
|
decompressed.Append(decompressed[copyIndex]);
|
|
}
|
|
|
|
currentIndex = closingParenIndex + 1;
|
|
}
|
|
else
|
|
{
|
|
// Literal case
|
|
decompressed.Append(compressedData[currentIndex]);
|
|
currentIndex++;
|
|
}
|
|
}
|
|
|
|
return decompressed.ToString();
|
|
}
|
|
}
|
|
}
|