I dunno man

This commit is contained in:
Lani Aung
2024-10-06 23:12:50 -06:00
parent 9c44ec0156
commit e3f23389da
6 changed files with 97 additions and 46 deletions
@@ -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);
+4 -25
View File
@@ -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++);
+15 -5
View File
@@ -41,17 +41,27 @@ public class BitStream : Stream
} }
var buffer = _bitBuffer; var buffer = _bitBuffer;
buffer >>= 32 - bitLength; if (bitLength < 32)
#if DEBUG {
Console.WriteLine($"BitStream buffer: {_bitBuffer:b}, extracted number: {buffer:b}"); buffer >>= 32 - bitLength;
#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();