I dunno man
This commit is contained in:
@@ -39,7 +39,7 @@ public class BitStreamTests
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestReadLong()
|
||||
public void TestReadInt()
|
||||
{
|
||||
var random = (uint)Random.Shared.Next();
|
||||
var bytes = BitConverter.GetBytes(random);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using fxl.codes.kisekae.data.Archives;
|
||||
using fxl.codes.kisekae.data.Archives.Algorithms;
|
||||
|
||||
namespace fxl.codes.kisekae.data.test;
|
||||
@@ -20,30 +19,10 @@ public class LZWTests
|
||||
{
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(_lzw.Encode(_unencoded), Is.EqualTo(_encoded), "Encoding failed");
|
||||
Assert.That(_lzw.Decode(_encoded), Is.EqualTo(_unencoded), "Decoding failed");
|
||||
var streamUnencoded = new MemoryStream(_unencoded);
|
||||
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
|
||||
{
|
||||
byte[] Encode(ReadOnlySpan<byte> stream);
|
||||
byte[] Decode(ReadOnlySpan<byte> stream);
|
||||
byte[] Encode(Stream stream);
|
||||
byte[] Decode(Stream stream, int bitLength);
|
||||
}
|
||||
@@ -4,24 +4,38 @@ namespace fxl.codes.kisekae.data.Archives.Algorithms;
|
||||
|
||||
internal class LZW : IAlgorithm
|
||||
{
|
||||
private static readonly Dictionary<uint, string> DecodeDictionary;
|
||||
private static readonly Dictionary<string, uint> EncodeDictionary;
|
||||
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)
|
||||
{
|
||||
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;
|
||||
var dictionary = new Dictionary<uint, string>();
|
||||
for (uint i = 0; i <= byte.MaxValue; i++) dictionary.Add(i, $"{(char)i}");
|
||||
|
||||
var buffer = "";
|
||||
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];
|
||||
|
||||
decoded.Add(dictionary[code]);
|
||||
@@ -33,17 +47,18 @@ internal class LZW : IAlgorithm
|
||||
return decoded.SelectMany(Encoding.UTF8.GetBytes).ToArray();
|
||||
}
|
||||
|
||||
public byte[] Encode(ReadOnlySpan<byte> stream)
|
||||
public byte[] Encode(Stream stream)
|
||||
{
|
||||
var next = byte.MaxValue + 1;
|
||||
var dictionary = new Dictionary<string, int>();
|
||||
for (var i = 0; i <= byte.MaxValue; i++) dictionary.Add($"{(char)i}", i);
|
||||
uint next = byte.MaxValue + 1;
|
||||
var dictionary = EncodeDictionary.ToDictionary(x => x.Key, x => x.Value);
|
||||
|
||||
var buffer = "";
|
||||
var encoded = new List<int>();
|
||||
foreach (var part in stream)
|
||||
var encoded = new List<uint>();
|
||||
while (true)
|
||||
{
|
||||
var charValue = (char)part;
|
||||
if (stream.Position >= stream.Length) break;
|
||||
|
||||
var charValue = (char)stream.ReadByte();
|
||||
buffer += charValue;
|
||||
if (dictionary.ContainsKey(buffer)) continue;
|
||||
if (next <= Max) dictionary.Add(buffer, next++);
|
||||
|
||||
@@ -41,17 +41,27 @@ public class BitStream : Stream
|
||||
}
|
||||
|
||||
var buffer = _bitBuffer;
|
||||
if (bitLength < 32)
|
||||
{
|
||||
buffer >>= 32 - bitLength;
|
||||
#if DEBUG
|
||||
Console.WriteLine($"BitStream buffer: {_bitBuffer:b}, extracted number: {buffer:b}");
|
||||
#endif
|
||||
_bitBuffer <<= bitLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
_bitBuffer = 0;
|
||||
}
|
||||
|
||||
Position += bitLength;
|
||||
_bitBufferCount -= bitLength;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public override int ReadByte()
|
||||
{
|
||||
return (int)ReadBits(8);
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
||||
Reference in New Issue
Block a user