13 Commits
0.4.2 ... 0.4.5

Author SHA1 Message Date
Matt Nadareski
d239d9f09b Bump version 2024-04-18 12:08:56 -04:00
Matt Nadareski
0cf3e3e816 Update SabreTools.IO 2024-04-18 12:05:30 -04:00
Matt Nadareski
fe319b71f1 Bump version 2024-04-16 22:10:41 -04:00
Matt Nadareski
cd5bf99f21 File formatting changes 2024-04-16 22:09:11 -04:00
Matt Nadareski
f79b5353f7 Add empty test project 2024-04-16 22:06:54 -04:00
Matt Nadareski
5e184b03c5 Move project files to subfolder 2024-04-16 22:02:51 -04:00
Matt Nadareski
a1417d2f8a Minor syntax cleanup 2024-04-16 22:00:58 -04:00
Matt Nadareski
7580d49830 Migrate to ReadOnlyBitStream 2024-04-16 21:57:31 -04:00
Matt Nadareski
c04c7d438d Update SabreTools.IO 2024-04-16 21:55:02 -04:00
Matt Nadareski
a0f602ed6f Bump version the correct way 2024-04-16 12:07:15 -04:00
Matt Nadareski
4bc7f53c9f Bump version 2024-04-16 12:05:46 -04:00
Matt Nadareski
049a8cf499 Minor fixes and tweaks 2024-04-16 12:04:58 -04:00
Matt Nadareski
9a8875f1e0 Update SabreTools.IO 2024-04-16 12:03:05 -04:00
21 changed files with 79 additions and 277 deletions

View File

@@ -1,238 +0,0 @@
using System;
using System.IO;
using SabreTools.IO;
namespace SabreTools.Compression
{
/// <summary>
/// Wrapper to allow reading bits from a source stream
/// </summary>
public class BitStream
{
/// <inheritdoc cref="Stream.Position"/>
public long Position => _source.Position;
/// <inheritdoc cref="Stream.Length"/>
public long Length => _source.Length;
/// <summary>
/// Original stream source
/// </summary>
private Stream _source;
/// <summary>
/// Last read byte value from the stream
/// </summary>
private byte? _bitBuffer;
/// <summary>
/// Index in the byte of the current bit
/// </summary>
private int _bitIndex;
/// <summary>
/// Create a new BitStream from a source Stream
/// </summary>
public BitStream(Stream? source)
{
if (source == null || !source.CanRead || !source.CanSeek)
throw new ArgumentException(nameof(source));
_source = source;
_bitBuffer = null;
_bitIndex = 0;
}
/// <summary>
/// Discard the current cached byte
/// </summary>
public void Discard()
{
_bitBuffer = null;
_bitIndex = 0;
}
/// <summary>
/// Read a single bit, if possible
/// </summary>
/// <returns>The next bit encoded in a byte, null on error or end of stream</returns>
public byte? ReadBit()
{
// If we reached the end of the stream
if (_source.Position >= _source.Length)
return null;
// If we don't have a value cached
if (_bitBuffer == null)
{
// Read the next byte, if possible
_bitBuffer = ReadSourceByte();
if (_bitBuffer == null)
return null;
// Reset the bit index
_bitIndex = 0;
}
// Get the value by bit-shifting
int value = _bitBuffer.Value & 0x01;
_bitBuffer = (byte?)(_bitBuffer >> 1);
_bitIndex++;
// Reset the byte if we're at the end
if (_bitIndex >= 8)
Discard();
return (byte)value;
}
/// <summary>
/// Read a multiple bits in LSB, if possible
/// </summary>
/// <returns>The next bits encoded in a UInt32, null on error or end of stream</returns>
public uint? ReadBitsLSB(int bits)
{
uint value = 0;
for (int i = 0; i < bits; i++)
{
// Read the next bit
byte? bitValue = ReadBit();
if (bitValue == null)
return null;
// Add the bit shifted by the current index
value += (uint)(bitValue.Value << i);
}
return value;
}
/// <summary>
/// Read a multiple bits in MSB, if possible
/// </summary>
/// <returns>The next bits encoded in a UInt32, null on error or end of stream</returns>
public uint? ReadBitsMSB(int bits)
{
uint value = 0;
for (int i = 0; i < bits; i++)
{
// Read the next bit
byte? bitValue = ReadBit();
if (bitValue == null)
return null;
// Add the bit shifted by the current index
value += (value << 1) + bitValue.Value;
}
return value;
}
/// <summary>
/// Read a byte, if possible
/// </summary>
/// <returns>The next byte, null on error or end of stream</returns>
/// <remarks>Assumes the stream is byte-aligned</remarks>
public byte? ReadByte()
{
try
{
Discard();
return _source.ReadByteValue();
}
catch
{
return null;
}
}
/// <summary>
/// Read a UInt16, if possible
/// </summary>
/// <returns>The next UInt16, null on error or end of stream</returns>
/// <remarks>Assumes the stream is byte-aligned</remarks>
public ushort? ReadUInt16()
{
try
{
Discard();
return _source.ReadUInt16();
}
catch
{
return null;
}
}
/// <summary>
/// Read a UInt32, if possible
/// </summary>
/// <returns>The next UInt32, null on error or end of stream</returns>
/// <remarks>Assumes the stream is byte-aligned</remarks>
public uint? ReadUInt32()
{
try
{
Discard();
return _source.ReadUInt32();
}
catch
{
return null;
}
}
/// <summary>
/// Read a UInt64, if possible
/// </summary>
/// <returns>The next UInt64, null on error or end of stream</returns>
/// <remarks>Assumes the stream is byte-aligned</remarks>
public ulong? ReadUInt64()
{
try
{
Discard();
return _source.ReadUInt64();
}
catch
{
return null;
}
}
/// <summary>
/// Read <paramref name="bytes"/> bytes, if possible
/// </summary>
/// <param name="bytes">Number of bytes to read</param>
/// <returns>The next <paramref name="bytes"/> bytes, null on error or end of stream</returns>
/// <remarks>Assumes the stream is byte-aligned</remarks>
public byte[]? ReadBytes(int bytes)
{
try
{
Discard();
return _source.ReadBytes(bytes);
}
catch
{
return null;
}
}
/// <summary>
/// Read a single byte from the underlying stream, if possible
/// </summary>
/// <returns>The next full byte from the stream, null on error or end of stream</returns>
private byte? ReadSourceByte()
{
try
{
return _source.ReadByteValue();
}
catch
{
return null;
}
}
}
}

View File

@@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SabreTools.Compression", "SabreTools.Compression.csproj", "{B26E863F-8509-48BB-BABA-4FF83DB28D2A}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SabreTools.Compression", "SabreTools.Compression\SabreTools.Compression.csproj", "{B26E863F-8509-48BB-BABA-4FF83DB28D2A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{FDF6EF41-1B5A-4F3B-A7DD-DEB810E55A30}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -18,5 +20,9 @@ Global
{B26E863F-8509-48BB-BABA-4FF83DB28D2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B26E863F-8509-48BB-BABA-4FF83DB28D2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B26E863F-8509-48BB-BABA-4FF83DB28D2A}.Release|Any CPU.Build.0 = Release|Any CPU
{FDF6EF41-1B5A-4F3B-A7DD-DEB810E55A30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FDF6EF41-1B5A-4F3B-A7DD-DEB810E55A30}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FDF6EF41-1B5A-4F3B-A7DD-DEB810E55A30}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FDF6EF41-1B5A-4F3B-A7DD-DEB810E55A30}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@@ -1,7 +1,7 @@
using System.IO;
using System.Linq;
using System.Text;
using SabreTools.IO;
using SabreTools.IO.Extensions;
using SabreTools.Models.Compression.LZ;
using static SabreTools.Models.Compression.LZ.Constants;
@@ -57,7 +57,7 @@ namespace SabreTools.Compression.LZ
long read = lz.CopyTo(sourceState, destState, out LZERROR error);
// Copy the data to the buffer
var decompressed = new byte[0];
byte[]? decompressed;
if (read == 0 || (error != LZERROR.LZERROR_OK && error != LZERROR.LZERROR_NOT_LZ))
{
decompressed = null;
@@ -552,6 +552,6 @@ namespace SabreTools.Compression.LZ
return fileHeader;
}
#endregion
#endregion
}
}

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SabreTools.IO.Streams;
using SabreTools.Models.Compression.MSZIP;
using static SabreTools.Models.Compression.MSZIP.Constants;
@@ -13,7 +14,7 @@ namespace SabreTools.Compression.MSZIP
/// <summary>
/// Internal bitstream to use for decompression
/// </summary>
private BitStream _bitStream;
private readonly ReadOnlyBitStream _bitStream;
/// <summary>
/// Create a new Decompressor from a byte array
@@ -28,8 +29,8 @@ namespace SabreTools.Compression.MSZIP
// Create a memory stream to wrap
var ms = new MemoryStream(input);
// Wrap the stream in a BitStream
_bitStream = new BitStream(ms);
// Wrap the stream in a ReadOnlyBitStream
_bitStream = new ReadOnlyBitStream(ms);
}
/// <summary>
@@ -42,8 +43,8 @@ namespace SabreTools.Compression.MSZIP
if (input == null || !input.CanRead || !input.CanSeek)
throw new ArgumentException(nameof(input));
// Wrap the stream in a BitStream
_bitStream = new BitStream(input);
// Wrap the stream in a ReadOnlyBitStream
_bitStream = new ReadOnlyBitStream(input);
}
/// <summary>
@@ -150,7 +151,7 @@ namespace SabreTools.Compression.MSZIP
}
// Make the lengths tree
HuffmanDecoder lengthTree = new HuffmanDecoder(lengthLengths, 19);
var lengthTree = new HuffmanDecoder(lengthLengths, 19);
// Setup the literal and distance lengths
header.LiteralLengths = new uint[288];
@@ -246,8 +247,8 @@ namespace SabreTools.Compression.MSZIP
(var header, uint numLiteral, uint numDistance) = RaadFixedCompressedDataHeader();
// Make the literal and distance trees
HuffmanDecoder literalTree = new HuffmanDecoder(header.LiteralLengths, numLiteral);
HuffmanDecoder distanceTree = new HuffmanDecoder(header.DistanceCodes, numDistance);
var literalTree = new HuffmanDecoder(header.LiteralLengths, numLiteral);
var distanceTree = new HuffmanDecoder(header.DistanceCodes, numDistance);
// Now loop and decode
return (header, ReadHuffmanBlock(literalTree, distanceTree));
@@ -262,8 +263,8 @@ namespace SabreTools.Compression.MSZIP
(var header, uint numLiteral, uint numDistance) = ReadDynamicCompressedDataHeader();
// Make the literal and distance trees
HuffmanDecoder literalTree = new HuffmanDecoder(header.LiteralLengths, numLiteral);
HuffmanDecoder distanceTree = new HuffmanDecoder(header.DistanceCodes, numDistance);
var literalTree = new HuffmanDecoder(header.LiteralLengths, numLiteral);
var distanceTree = new HuffmanDecoder(header.DistanceCodes, numDistance);
// Now loop and decode
return (header, ReadHuffmanBlock(literalTree, distanceTree));

View File

@@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Linq;
using SabreTools.IO.Streams;
namespace SabreTools.Compression.MSZIP
{
@@ -83,7 +84,7 @@ namespace SabreTools.Compression.MSZIP
/// </summary>
/// <param name="input">BitStream representing the input</param>
/// <returns>Value of the node described by the input</returns>
public int Decode(BitStream input)
public int Decode(ReadOnlyBitStream input)
{
// Start at the root of the tree
var node = _root;

View File

@@ -4,48 +4,48 @@ namespace SabreTools.Compression.Quantum
/// TODO: Remove this class when Models gets updated
public static class Constants
{
public static readonly int[] PositionSlot = new int[]
{
public static readonly int[] PositionSlot =
[
0x00000, 0x00001, 0x00002, 0x00003, 0x00004, 0x00006, 0x00008, 0x0000c,
0x00010, 0x00018, 0x00020, 0x00030, 0x00040, 0x00060, 0x00080, 0x000c0,
0x00100, 0x00180, 0x00200, 0x00300, 0x00400, 0x00600, 0x00800, 0x00c00,
0x01000, 0x01800, 0x02000, 0x03000, 0x04000, 0x06000, 0x08000, 0x0c000,
0x10000, 0x18000, 0x20000, 0x30000, 0x40000, 0x60000, 0x80000, 0xc0000,
0x100000, 0x180000
};
];
public static readonly int[] PositionExtraBits = new int[]
{
public static readonly int[] PositionExtraBits =
[
0, 0, 0, 0, 1, 1, 2, 2,
3, 3, 4, 4, 5, 5, 6, 6,
7, 7, 8, 8, 9, 9, 10, 10,
11, 11, 12, 12, 13, 13, 14, 14,
15, 15, 16, 16, 17, 17, 18, 18,
19, 19
};
];
public static readonly int[] LengthSlot = new int[]
{
public static readonly int[] LengthSlot =
[
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08,
0x0a, 0x0c, 0x0e, 0x12, 0x16, 0x1a, 0x1e, 0x26,
0x2e, 0x36, 0x3e, 0x4e, 0x5e, 0x6e, 0x7e, 0x9e,
0xbe, 0xde, 0xfe
};
];
public static readonly int[] LengthExtraBits = new int[]
{
public static readonly int[] LengthExtraBits =
[
0, 0, 0, 0, 0, 0, 1, 1,
1, 1, 2, 2, 2, 2, 3, 3,
3, 3, 4, 4, 4, 4, 5, 5,
5, 5, 0
};
];
/// <summary>
/// Number of position slots for (tsize - 10)
/// </summary>
public static readonly int[] NumPositionSlots = new int[]
{
public static readonly int[] NumPositionSlots =
[
20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42
};
];
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using SabreTools.IO.Streams;
using SabreTools.Models.Compression.Quantum;
using static SabreTools.Compression.Quantum.Constants;
@@ -12,7 +13,7 @@ namespace SabreTools.Compression.Quantum
/// <summary>
/// Internal bitstream to use for decompression
/// </summary>
private BitStream _bitStream;
private readonly ReadOnlyBitStream _bitStream;
#region Models
@@ -100,8 +101,8 @@ namespace SabreTools.Compression.Quantum
// Create a memory stream to wrap
var ms = new MemoryStream(input);
// Wrap the stream in a BitStream
_bitStream = new BitStream(ms);
// Wrap the stream in a ReadOnlyBitStream
_bitStream = new ReadOnlyBitStream(ms);
// Initialize literal models
this._model0 = CreateModel(0, 64);
@@ -140,8 +141,8 @@ namespace SabreTools.Compression.Quantum
if (windowBits < 10 || windowBits > 21)
throw new ArgumentOutOfRangeException(nameof(windowBits));
// Wrap the stream in a BitStream
_bitStream = new BitStream(input);
// Wrap the stream in a ReadOnlyBitStream
_bitStream = new ReadOnlyBitStream(input);
// Initialize literal models
this._model0 = CreateModel(0, 64);
@@ -217,7 +218,7 @@ namespace SabreTools.Compression.Quantum
offset = PositionSlot[model4sym] + model4extra + 1;
length = 3;
break;
case 5:
int model5sym = GetSymbol(_model5);
int model5extra = (int)(_bitStream.ReadBitsMSB(PositionExtraBits[model5sym]) ?? 0);

View File

@@ -8,7 +8,7 @@
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>0.4.2</Version>
<Version>0.4.5</Version>
<!-- Package Properties -->
<Authors>Matt Nadareski</Authors>
@@ -23,11 +23,11 @@
</PropertyGroup>
<ItemGroup>
<None Include="README.md" Pack="true" PackagePath="" />
<None Include="../README.md" Pack="true" PackagePath="" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SabreTools.IO" Version="1.3.3" />
<PackageReference Include="SabreTools.IO" Version="1.3.7" />
<PackageReference Include="SabreTools.Models" Version="1.4.2" />
</ItemGroup>

12
Test/Program.cs Normal file
View File

@@ -0,0 +1,12 @@
using SabreTools.Compression;
namespace Test
{
public static class Program
{
public static void Main(string[] args)
{
// No implementation, used for experimentation
}
}
}

19
Test/Test.csproj Normal file
View File

@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0</TargetFrameworks>
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64</RuntimeIdentifiers>
<OutputType>Exe</OutputType>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\SabreTools.Compression\SabreTools.Compression.csproj" />
</ItemGroup>
</Project>