I dunno man
This commit is contained in:
@@ -39,7 +39,7 @@ public class BitStreamTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestReadLong()
|
public void TestReadInt()
|
||||||
{
|
{
|
||||||
var random = (uint)Random.Shared.Next();
|
var random = (uint)Random.Shared.Next();
|
||||||
var bytes = BitConverter.GetBytes(random);
|
var bytes = BitConverter.GetBytes(random);
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using fxl.codes.kisekae.data.Archives;
|
|
||||||
using fxl.codes.kisekae.data.Archives.Algorithms;
|
using fxl.codes.kisekae.data.Archives.Algorithms;
|
||||||
|
|
||||||
namespace fxl.codes.kisekae.data.test;
|
namespace fxl.codes.kisekae.data.test;
|
||||||
@@ -20,30 +19,10 @@ public class LZWTests
|
|||||||
{
|
{
|
||||||
Assert.Multiple(() =>
|
Assert.Multiple(() =>
|
||||||
{
|
{
|
||||||
Assert.That(_lzw.Encode(_unencoded), Is.EqualTo(_encoded), "Encoding failed");
|
var streamUnencoded = new MemoryStream(_unencoded);
|
||||||
Assert.That(_lzw.Decode(_encoded), Is.EqualTo(_unencoded), "Decoding failed");
|
var streamEncoded = new MemoryStream(_encoded);
|
||||||
});
|
Assert.That(_lzw.Encode(streamUnencoded), Is.EqualTo(_encoded), "Encoding failed");
|
||||||
}
|
Assert.That(_lzw.Decode(streamEncoded), Is.EqualTo(_unencoded), "Decoding failed");
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestDecompressLzh()
|
|
||||||
{
|
|
||||||
var assembly = typeof(LZWTests).Assembly;
|
|
||||||
foreach (var resource in assembly.GetManifestResourceNames())
|
|
||||||
{
|
|
||||||
using var stream = assembly.GetManifestResourceStream(resource);
|
|
||||||
if (stream == null) continue;
|
|
||||||
|
|
||||||
var files = LhCodecService.GetFiles(in stream);
|
|
||||||
foreach (var file in files)
|
|
||||||
Assert.Multiple(() =>
|
|
||||||
{
|
|
||||||
Assert.That(file.CompressedFile, Is.Not.Null);
|
|
||||||
Assert.That(file.CompressedFile, Is.Not.Empty);
|
|
||||||
|
|
||||||
var decompressed = _lzw.Decode(file.CompressedFile);
|
|
||||||
Assert.That(decompressed, Is.Not.Null);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
namespace fxl.codes.kisekae.data.Archives.Algorithms;
|
||||||
|
|
||||||
|
public class Huffman
|
||||||
|
{
|
||||||
|
private readonly List<HuffmanNode> Nodes;
|
||||||
|
|
||||||
|
public Huffman()
|
||||||
|
{
|
||||||
|
Nodes = new List<HuffmanNode>();
|
||||||
|
for (var i = char.MinValue; i < char.MaxValue; i++) Nodes.Add(new HuffmanNode(i, 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class HuffmanNode
|
||||||
|
{
|
||||||
|
public readonly char Value;
|
||||||
|
public HuffmanNode Left;
|
||||||
|
public HuffmanNode Parent;
|
||||||
|
public HuffmanNode Right;
|
||||||
|
public HuffmanSide Side;
|
||||||
|
public int Weight;
|
||||||
|
|
||||||
|
public HuffmanNode(char value, int weight = 0)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
Weight = weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HuffmanNode(HuffmanNode left, HuffmanNode right)
|
||||||
|
{
|
||||||
|
Left = left;
|
||||||
|
Left.Side = HuffmanSide.Left;
|
||||||
|
Left.Parent = this;
|
||||||
|
|
||||||
|
Right = right;
|
||||||
|
Right.Side = HuffmanSide.Right;
|
||||||
|
Right.Parent = this;
|
||||||
|
|
||||||
|
Weight = left.Weight + right.Weight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal enum HuffmanSide
|
||||||
|
{
|
||||||
|
Left,
|
||||||
|
Right
|
||||||
|
}
|
||||||
@@ -2,6 +2,6 @@ namespace fxl.codes.kisekae.data.Archives.Algorithms;
|
|||||||
|
|
||||||
public interface IAlgorithm
|
public interface IAlgorithm
|
||||||
{
|
{
|
||||||
byte[] Encode(ReadOnlySpan<byte> stream);
|
byte[] Encode(Stream stream);
|
||||||
byte[] Decode(ReadOnlySpan<byte> stream);
|
byte[] Decode(Stream stream, int bitLength);
|
||||||
}
|
}
|
||||||
@@ -4,24 +4,38 @@ namespace fxl.codes.kisekae.data.Archives.Algorithms;
|
|||||||
|
|
||||||
internal class LZW : IAlgorithm
|
internal class LZW : IAlgorithm
|
||||||
{
|
{
|
||||||
|
private static readonly Dictionary<uint, string> DecodeDictionary;
|
||||||
|
private static readonly Dictionary<string, uint> EncodeDictionary;
|
||||||
private readonly int Max;
|
private readonly int Max;
|
||||||
|
|
||||||
|
static LZW()
|
||||||
|
{
|
||||||
|
DecodeDictionary = new Dictionary<uint, string>();
|
||||||
|
EncodeDictionary = new Dictionary<string, uint>();
|
||||||
|
|
||||||
|
for (uint i = 0; i <= byte.MaxValue; i++)
|
||||||
|
{
|
||||||
|
var value = $"{(char)i}";
|
||||||
|
DecodeDictionary.Add(i, value);
|
||||||
|
EncodeDictionary.Add(value, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal LZW(int max = short.MaxValue)
|
internal LZW(int max = short.MaxValue)
|
||||||
{
|
{
|
||||||
Max = max;
|
Max = max;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] Decode(ReadOnlySpan<byte> stream)
|
public byte[] Decode(Stream stream, int bitLength = 32)
|
||||||
{
|
{
|
||||||
|
var dictionary = DecodeDictionary.ToDictionary(x => x.Key, x => x.Value);
|
||||||
uint next = byte.MaxValue + 1;
|
uint next = byte.MaxValue + 1;
|
||||||
var dictionary = new Dictionary<uint, string>();
|
|
||||||
for (uint i = 0; i <= byte.MaxValue; i++) dictionary.Add(i, $"{(char)i}");
|
|
||||||
|
|
||||||
var buffer = "";
|
var buffer = "";
|
||||||
var decoded = new List<string>();
|
var decoded = new List<string>();
|
||||||
for (var i = 0; i < stream.Length; i += 4)
|
var bitStream = new BitStream(stream);
|
||||||
|
while (bitStream.Position < bitStream.Length)
|
||||||
{
|
{
|
||||||
var code = BitConverter.ToUInt32(stream[i..(i + 4)]);
|
var code = bitStream.ReadBits(bitLength);
|
||||||
if (!dictionary.ContainsKey(code)) dictionary[code] = buffer + buffer[0];
|
if (!dictionary.ContainsKey(code)) dictionary[code] = buffer + buffer[0];
|
||||||
|
|
||||||
decoded.Add(dictionary[code]);
|
decoded.Add(dictionary[code]);
|
||||||
@@ -33,17 +47,18 @@ internal class LZW : IAlgorithm
|
|||||||
return decoded.SelectMany(Encoding.UTF8.GetBytes).ToArray();
|
return decoded.SelectMany(Encoding.UTF8.GetBytes).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] Encode(ReadOnlySpan<byte> stream)
|
public byte[] Encode(Stream stream)
|
||||||
{
|
{
|
||||||
var next = byte.MaxValue + 1;
|
uint next = byte.MaxValue + 1;
|
||||||
var dictionary = new Dictionary<string, int>();
|
var dictionary = EncodeDictionary.ToDictionary(x => x.Key, x => x.Value);
|
||||||
for (var i = 0; i <= byte.MaxValue; i++) dictionary.Add($"{(char)i}", i);
|
|
||||||
|
|
||||||
var buffer = "";
|
var buffer = "";
|
||||||
var encoded = new List<int>();
|
var encoded = new List<uint>();
|
||||||
foreach (var part in stream)
|
while (true)
|
||||||
{
|
{
|
||||||
var charValue = (char)part;
|
if (stream.Position >= stream.Length) break;
|
||||||
|
|
||||||
|
var charValue = (char)stream.ReadByte();
|
||||||
buffer += charValue;
|
buffer += charValue;
|
||||||
if (dictionary.ContainsKey(buffer)) continue;
|
if (dictionary.ContainsKey(buffer)) continue;
|
||||||
if (next <= Max) dictionary.Add(buffer, next++);
|
if (next <= Max) dictionary.Add(buffer, next++);
|
||||||
|
|||||||
@@ -41,17 +41,27 @@ public class BitStream : Stream
|
|||||||
}
|
}
|
||||||
|
|
||||||
var buffer = _bitBuffer;
|
var buffer = _bitBuffer;
|
||||||
|
if (bitLength < 32)
|
||||||
|
{
|
||||||
buffer >>= 32 - bitLength;
|
buffer >>= 32 - bitLength;
|
||||||
#if DEBUG
|
|
||||||
Console.WriteLine($"BitStream buffer: {_bitBuffer:b}, extracted number: {buffer:b}");
|
|
||||||
#endif
|
|
||||||
_bitBuffer <<= bitLength;
|
_bitBuffer <<= bitLength;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_bitBuffer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
Position += bitLength;
|
Position += bitLength;
|
||||||
_bitBufferCount -= bitLength;
|
_bitBufferCount -= bitLength;
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override int ReadByte()
|
||||||
|
{
|
||||||
|
return (int)ReadBits(8);
|
||||||
|
}
|
||||||
|
|
||||||
public override void Flush()
|
public override void Flush()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
|||||||
Reference in New Issue
Block a user