mirror of
https://github.com/gnh1201/welsonjs.git
synced 2024-11-26 15:31:42 +00:00
Add LZ77 (MsCompress) algorithm implementation
This commit is contained in:
parent
3cfc3fccf5
commit
e7068f0f97
103
WelsonJS.Toolkit/WelsonJS.Toolkit/Compression/LZ77.cs
Normal file
103
WelsonJS.Toolkit/WelsonJS.Toolkit/Compression/LZ77.cs
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
* WelsonJS.Toolkit: WelsonJS dotNET native component
|
||||||
|
*
|
||||||
|
* filename:
|
||||||
|
* LZ77.cs
|
||||||
|
*
|
||||||
|
* description:
|
||||||
|
* WelsonJS - Build a Windows app on the Windows built-in JavaScript engine
|
||||||
|
*
|
||||||
|
* website:
|
||||||
|
* - https://github.com/gnh1201/welsonjs
|
||||||
|
* - https://catswords.social/@catswords_oss
|
||||||
|
*
|
||||||
|
* 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -209,5 +209,17 @@ namespace WelsonJS
|
||||||
sharedMemory.Clear();
|
sharedMemory.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ComVisible(true)]
|
||||||
|
public void CompressLZ77(string input)
|
||||||
|
{
|
||||||
|
Compression.LZ77.Compress(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ComVisible(true)]
|
||||||
|
public string DecompressLZ77(string compressData)
|
||||||
|
{
|
||||||
|
return Compression.LZ77.Decompress(compressData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -232,35 +232,6 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"scope": [],
|
|
||||||
"name": "MsCompress for Windows",
|
|
||||||
"author": "gnuwin32",
|
|
||||||
"distributer": "gnuwin32",
|
|
||||||
"license": "GPL",
|
|
||||||
"architecture": ["x86"],
|
|
||||||
"website": "https://gnuwin32.sourceforge.net/packages/mscompress.htm",
|
|
||||||
"release": {
|
|
||||||
"version": "0.3",
|
|
||||||
"build": "2004-03-14",
|
|
||||||
"date": "2004-03-14",
|
|
||||||
"changelog": "https://gnuwin32.sourceforge.net/packages/mscompress.htm"
|
|
||||||
},
|
|
||||||
"environment": {
|
|
||||||
"knownAs": [
|
|
||||||
"mscompress",
|
|
||||||
"mscompress.exe"
|
|
||||||
],
|
|
||||||
"knownPath": []
|
|
||||||
},
|
|
||||||
"binaries": [
|
|
||||||
{
|
|
||||||
"architecture": "x86",
|
|
||||||
"downloadLink": "https://gnuwin32.sourceforge.net/downlinks/mscompress-bin-zip.php",
|
|
||||||
"tags": ["archive", "lz77", "standalone"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"scope": [],
|
"scope": [],
|
||||||
"name": "github.com/philr/bzip2-windows",
|
"name": "github.com/philr/bzip2-windows",
|
||||||
|
|
72
lib/lz77.js
Normal file
72
lib/lz77.js
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
// lz77.js
|
||||||
|
// https://github.com/gnh1201/welsonjs
|
||||||
|
|
||||||
|
function compress(input) {
|
||||||
|
var compressed = '';
|
||||||
|
var searchBufferIndex = 0;
|
||||||
|
|
||||||
|
while (searchBufferIndex < input.length) {
|
||||||
|
var longestMatchLength = 0;
|
||||||
|
var longestMatchOffset = 0;
|
||||||
|
|
||||||
|
// Search for the longest match in the look-ahead buffer
|
||||||
|
for (var i = 0; i < searchBufferIndex; i++) {
|
||||||
|
var matchLength = 0;
|
||||||
|
while (matchLength < input.length - searchBufferIndex && input.charAt(i + matchLength) === input.charAt(searchBufferIndex + matchLength)) {
|
||||||
|
matchLength++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchLength > longestMatchLength) {
|
||||||
|
longestMatchLength = matchLength;
|
||||||
|
longestMatchOffset = searchBufferIndex - i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output the token (offset, length)
|
||||||
|
if (longestMatchLength > 0) {
|
||||||
|
compressed += '(' + longestMatchOffset + ',' + longestMatchLength + ')';
|
||||||
|
searchBufferIndex += longestMatchLength;
|
||||||
|
} else {
|
||||||
|
compressed += '(0,' + input.charAt(searchBufferIndex) + ')';
|
||||||
|
searchBufferIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return compressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
function decompress(compressedData) {
|
||||||
|
var decompressed = '';
|
||||||
|
var currentIndex = 0;
|
||||||
|
|
||||||
|
while (currentIndex < compressedData.length) {
|
||||||
|
if (compressedData.charAt(currentIndex) === '(') {
|
||||||
|
// Match case
|
||||||
|
var commaIndex = compressedData.indexOf(',', currentIndex);
|
||||||
|
var offset = parseInt(compressedData.substring(currentIndex + 1, commaIndex), 10);
|
||||||
|
var closingParenIndex = compressedData.indexOf(')', commaIndex);
|
||||||
|
var length = parseInt(compressedData.substring(commaIndex + 1, closingParenIndex), 10);
|
||||||
|
|
||||||
|
for (var i = 0; i < length; i++) {
|
||||||
|
var copyIndex = decompressed.length - offset;
|
||||||
|
decompressed += decompressed.charAt(copyIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentIndex = closingParenIndex + 1;
|
||||||
|
} else {
|
||||||
|
// Literal case
|
||||||
|
decompressed += compressedData.charAt(currentIndex);
|
||||||
|
currentIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return decompressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.compress = compress;
|
||||||
|
exports.decompress = decompress;
|
||||||
|
|
||||||
|
exports.VERSIONINFO = "LZ77 (MsCompress) algorithm implementation version 0.1";
|
||||||
|
exports.AUTHOR = "abuse@catswords.net";
|
||||||
|
exports.global = global;
|
||||||
|
exports.require = global.require;
|
Loading…
Reference in New Issue
Block a user