welsonjs/WelsonJS.Toolkit/WelsonJS.Toolkit/Compression/LZ77.cs

89 lines
3.0 KiB
C#

// LZ77.cs
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2025 Catswords OSS and WelsonJS Contributors
// https://github.com/gnh1201/welsonjs
//
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();
}
}
}