10 Commits

Author SHA1 Message Date
Matt Nadareski
1c989985d9 Update copyright date 2024-02-27 19:08:56 -05:00
Matt Nadareski
62c6e79ad3 Add nuget package and PR workflows 2024-02-27 19:08:42 -05:00
Matt Nadareski
6bbf521828 Fix repository URL 2023-11-22 09:40:32 -05:00
Matt Nadareski
7a4e2f0ee0 Bump version 2023-11-22 09:39:29 -05:00
Matt Nadareski
1d1a6f5976 Support .NET Framework 2.0 2023-11-22 09:39:18 -05:00
Matt Nadareski
065b68124b Update SabreTools libraries 2023-11-22 09:36:36 -05:00
Matt Nadareski
07b50e8c46 Support ancient .NET 2023-11-14 14:53:50 -05:00
Matt Nadareski
8eb82384d6 Expand supported RIDs 2023-11-08 22:51:25 -05:00
Matt Nadareski
dd6cc0e2f3 Fix whitespace in project file 2023-11-08 10:59:30 -05:00
Matt Nadareski
58502e0362 Enable latest language version 2023-11-07 22:12:51 -05:00
10 changed files with 141 additions and 182 deletions

43
.github/workflows/build_nupkg.yml vendored Normal file
View File

@@ -0,0 +1,43 @@
name: Nuget Pack
on:
push:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Restore dependencies
run: dotnet restore
- name: Pack
run: dotnet pack
- name: Upload build
uses: actions/upload-artifact@v4
with:
name: 'Nuget Package'
path: 'bin/Release/*.nupkg'
- name: Upload to rolling
uses: ncipollo/release-action@v1.14.0
with:
allowUpdates: True
artifacts: 'bin/Release/*.nupkg'
body: 'Last built commit: ${{ github.sha }}'
name: 'Rolling Release'
prerelease: True
replacesArtifacts: True
tag: "rolling"
updateOnlyUnreleased: True

17
.github/workflows/check_pr.yml vendored Normal file
View File

@@ -0,0 +1,17 @@
name: Build PR
on: [pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Build
run: dotnet build

View File

@@ -33,11 +33,7 @@ namespace SabreTools.Compression
/// <summary>
/// Create a new BitStream from a source Stream
/// </summary>
#if NET48
public BitStream(Stream source)
#else
public BitStream(Stream? source)
#endif
{
if (source == null || !source.CanRead || !source.CanSeek)
throw new ArgumentException(nameof(source));
@@ -210,11 +206,7 @@ namespace SabreTools.Compression
/// <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>
#if NET48
public byte[] ReadBytes(int bytes)
#else
public byte[]? ReadBytes(int bytes)
#endif
{
try
{

View File

@@ -17,11 +17,7 @@ namespace SabreTools.Compression.LZ
/// </summary>
/// <param name="compressed">Byte array representing the compressed data</param>
/// <returns>Decompressed data as a byte array, null on error</returns>
#if NET48
public static byte[] Decompress(byte[] compressed)
#else
public static byte[]? Decompress(byte[]? compressed)
#endif
{
// If we have and invalid input
if (compressed == null || compressed.Length == 0)
@@ -37,11 +33,7 @@ namespace SabreTools.Compression.LZ
/// </summary>
/// <param name="compressed">Stream representing the compressed data</param>
/// <returns>Decompressed data as a byte array, null on error</returns>
#if NET48
public static byte[] Decompress(Stream compressed)
#else
public static byte[]? Decompress(Stream? compressed)
#endif
{
// If we have and invalid input
if (compressed == null || compressed.Length == 0)
@@ -87,11 +79,7 @@ namespace SabreTools.Compression.LZ
/// <summary>
/// Reconstructs the full filename of the compressed file
/// </summary>
#if NET48
public static string GetExpandedName(string input, out LZERROR error)
#else
public static string? GetExpandedName(string input, out LZERROR error)
#endif
{
// Try to open the file as a compressed stream
var fileStream = File.Open(input, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
@@ -103,7 +91,7 @@ namespace SabreTools.Compression.LZ
string inputExtension = Path.GetExtension(input).TrimStart('.');
// If we have no extension
if (string.IsNullOrWhiteSpace(inputExtension))
if (string.IsNullOrEmpty(inputExtension))
return Path.GetFileNameWithoutExtension(input);
// If we have an extension of length 1
@@ -137,11 +125,7 @@ namespace SabreTools.Compression.LZ
/// <param name="error">Output representing the last error</param>
/// <returns>An initialized State, null on error</returns>
/// <remarks>Uncompressed streams are represented by a State with no buffer</remarks>
#if NET48
public State Open(Stream stream, out LZERROR error)
#else
public State? Open(Stream stream, out LZERROR error)
#endif
{
var lzs = Init(stream, out error);
if (error == LZERROR.LZERROR_OK || error == LZERROR.LZERROR_NOT_LZ)
@@ -170,11 +154,7 @@ namespace SabreTools.Compression.LZ
/// <param name="error">Output representing the last error</param>
/// <returns>An initialized State, null on error</returns>
/// <remarks>Uncompressed streams are represented by a State with no buffer</remarks>
#if NET48
public State Init(Stream source, out LZERROR error)
#else
public State? Init(Stream? source, out LZERROR error)
#endif
{
// If we have an invalid source
if (source == null)
@@ -540,11 +520,7 @@ namespace SabreTools.Compression.LZ
/// <param name="data">Stream to parse</param>
/// <param name="error">Output representing the last error</param>
/// <returns>Filled file header on success, null on error</returns>
#if NET48
private FileHeaader ParseFileHeader(Stream data, out LZERROR error)
#else
private FileHeaader? ParseFileHeader(Stream data, out LZERROR error)
#endif
{
error = LZERROR.LZERROR_OK;
var fileHeader = new FileHeaader();
@@ -576,6 +552,6 @@ namespace SabreTools.Compression.LZ
return fileHeader;
}
#endregion
#endregion
}
}

View File

@@ -19,11 +19,7 @@ namespace SabreTools.Compression.MSZIP
/// Create a new Decompressor from a byte array
/// </summary>
/// <param name="input">Byte array to decompress</param>
#if NET48
public DeflateDecompressor(byte[] input)
#else
public DeflateDecompressor(byte[]? input)
#endif
{
// If we have an invalid stream
if (input == null || input.Length == 0)
@@ -40,11 +36,7 @@ namespace SabreTools.Compression.MSZIP
/// Create a new Decompressor from a Stream
/// </summary>
/// <param name="input">Stream to decompress</param>
#if NET48
public DeflateDecompressor(Stream input)
#else
public DeflateDecompressor(Stream? input)
#endif
{
// If we have an invalid stream
if (input == null || !input.CanRead || !input.CanSeek)
@@ -58,11 +50,7 @@ namespace SabreTools.Compression.MSZIP
/// Decompress a stream into a <see cref="Block"/>
/// </summary>
/// <returns>Block containing the decompressed data on success, null on error</returns>
#if NET48
public Block Process()
#else
public Block? Process()
#endif
{
// Create a new block
var block = new Block();
@@ -85,11 +73,7 @@ namespace SabreTools.Compression.MSZIP
deflateBlocks.Add(deflateBlock);
// If we're at the final block, exit out of the loop
#if NET48
if (deflateBlock.Header.BFINAL)
#else
if (deflateBlock.Header!.BFINAL)
#endif
break;
}
@@ -187,11 +171,7 @@ namespace SabreTools.Compression.MSZIP
/// <summary>
/// Read an RFC1951 block
/// </summary>
#if NET48
private DeflateBlock ReadDeflateBlock()
#else
private DeflateBlock? ReadDeflateBlock()
#endif
{
var deflateBlock = new DeflateBlock();
@@ -241,11 +221,7 @@ namespace SabreTools.Compression.MSZIP
/// <summary>
/// Read an RFC1951 block with no compression
/// </summary>
#if NET48
private (NonCompressedBlockHeader, byte[]) ReadNoCompression()
#else
private (NonCompressedBlockHeader?, byte[]?) ReadNoCompression()
#endif
{
// Skip any remaining bits in current partially processed byte
_bitStream.Discard();
@@ -262,11 +238,7 @@ namespace SabreTools.Compression.MSZIP
/// <summary>
/// Read an RFC1951 block with fixed Huffman compression
/// </summary>
#if NET48
private (FixedCompressedDataHeader, byte[]) ReadFixedHuffman()
#else
private (FixedCompressedDataHeader, byte[]?) ReadFixedHuffman()
#endif
{
var bytes = new List<byte>();
@@ -284,11 +256,7 @@ namespace SabreTools.Compression.MSZIP
/// <summary>
/// Read an RFC1951 block with dynamic Huffman compression
/// </summary>
#if NET48
private (DynamicCompressedDataHeader, byte[]) ReadDynamicHuffman()
#else
private (DynamicCompressedDataHeader?, byte[]?) ReadDynamicHuffman()
#endif
{
// Get the dynamic huffman header
(var header, uint numLiteral, uint numDistance) = ReadDynamicCompressedDataHeader();
@@ -304,11 +272,7 @@ namespace SabreTools.Compression.MSZIP
/// <summary>
/// Read an RFC1951 block with Huffman compression
/// </summary>
#if NET48
private byte[] ReadHuffmanBlock(HuffmanDecoder literalTree, HuffmanDecoder distanceTree)
#else
private byte[]? ReadHuffmanBlock(HuffmanDecoder literalTree, HuffmanDecoder distanceTree)
#endif
{
// Now loop and decode
var bytes = new List<byte>();

View File

@@ -16,22 +16,14 @@ namespace SabreTools.Compression.MSZIP
/// </summary>
/// <param name="lengths">Array representing the number of bits for each value</param>
/// <param name="numCodes">Number of Huffman codes encoded</param>
#if NET48
public HuffmanDecoder(uint[] lengths, uint numCodes)
#else
public HuffmanDecoder(uint[]? lengths, uint numCodes)
#endif
{
// Ensure we have lengths
if (lengths == null)
throw new ArgumentNullException(nameof(lengths));
// Set the root to null for now
#if NET48
HuffmanNode root = null;
#else
HuffmanNode? root = null;
#endif
// Determine the value for max_bits
uint max_bits = lengths.Max();
@@ -83,11 +75,7 @@ namespace SabreTools.Compression.MSZIP
}
// Assign the root value
#if NET48
_root = root;
#else
_root = root!;
#endif
}
/// <summary>
@@ -125,11 +113,7 @@ namespace SabreTools.Compression.MSZIP
/// <param name="length">Length of the current encoding</param>
/// <param name="code">Encoding of the value to traverse</param>
/// <returns>New instance of the node with value appended</returns>
#if NET48
private static HuffmanNode Insert(HuffmanNode node, int value, uint length, int code)
#else
private static HuffmanNode Insert(HuffmanNode? node, int value, uint length, int code)
#endif
{
// If no node is provided, create a new one
if (node == null)

View File

@@ -8,20 +8,12 @@ namespace SabreTools.Compression.MSZIP
/// <summary>
/// Left child of the current node
/// </summary>
#if NET48
public HuffmanNode Left { get; set; }
#else
public HuffmanNode? Left { get; set; }
#endif
/// <summary>
/// Right child of the current node
/// </summary>
#if NET48
public HuffmanNode Right { get; set; }
#else
public HuffmanNode? Right { get; set; }
#endif
/// <summary>
/// Value of the current node

50
OldDotNet.cs Normal file
View File

@@ -0,0 +1,50 @@
#if NET20 || NET35
using System;
using System.IO;
namespace SabreTools.Compression
{
/// <summary>
/// Derived from the mscorlib code from .NET Framework 4.0
/// </summary>
internal static class OldDotNet
{
public static void CopyTo(this Stream source, Stream destination)
{
if (destination == null)
{
throw new ArgumentNullException("destination");
}
if (!source.CanRead && !source.CanWrite)
{
throw new ObjectDisposedException(null);
}
if (!destination.CanRead && !destination.CanWrite)
{
throw new ObjectDisposedException("destination");
}
if (!source.CanRead)
{
throw new NotSupportedException();
}
if (!destination.CanWrite)
{
throw new NotSupportedException();
}
byte[] array = new byte[81920];
int count;
while ((count = source.Read(array, 0, array.Length)) != 0)
{
destination.Write(array, 0, count);
}
}
}
}
#endif

View File

@@ -87,11 +87,7 @@ namespace SabreTools.Compression.Quantum
/// </summary>
/// <param name="input">Byte array to decompress</param>
/// <param name="windowBits">Number of bits in the sliding window</param>
#if NET48
public Decompressor(byte[] input, uint windowBits)
#else
public Decompressor(byte[]? input, uint windowBits)
#endif
{
// If we have an invalid stream
if (input == null || input.Length == 0)
@@ -134,11 +130,7 @@ namespace SabreTools.Compression.Quantum
/// </summary>
/// <param name="input">Stream to decompress</param>
/// <param name="windowBits">Number of bits in the sliding window</param>
#if NET48
public Decompressor(Stream input, uint windowBits)
#else
public Decompressor(Stream? input, uint windowBits)
#endif
{
// If we have an invalid stream
if (input == null || !input.CanRead || !input.CanSeek)
@@ -293,36 +285,20 @@ namespace SabreTools.Compression.Quantum
/// </summary>
private int GetSymbol(Model model)
{
#if NET48
int freq = GetFrequency(model.Symbols[0].CumulativeFrequency);
#else
int freq = GetFrequency(model.Symbols![0]!.CumulativeFrequency);
#endif
int i;
for (i = 1; i < model.Entries; i++)
{
#if NET48
if (model.Symbols[i].CumulativeFrequency <= freq)
#else
if (model.Symbols[i]!.CumulativeFrequency <= freq)
#endif
break;
}
#if NET48
int sym = model.Symbols[i - 1].Symbol;
GetCode(model.Symbols[i - 1].CumulativeFrequency,
model.Symbols[i].CumulativeFrequency,
model.Symbols[0].CumulativeFrequency);
#else
int sym = model.Symbols![i - 1]!.Symbol;
GetCode(model.Symbols![i - 1]!.CumulativeFrequency,
model.Symbols![i]!.CumulativeFrequency,
model.Symbols![0]!.CumulativeFrequency);
#endif
UpdateModel(model, i);
@@ -369,20 +345,12 @@ namespace SabreTools.Compression.Quantum
// Update cumulative frequencies
for (int i = 0; i < lastUpdated; i++)
{
#if NET48
var sym = model.Symbols[i];
#else
var sym = model.Symbols![i]!;
#endif
sym.CumulativeFrequency += 8;
}
// Decrement reordering time, if needed
#if NET48
if (model.Symbols[0].CumulativeFrequency > 3800)
#else
if (model.Symbols![0]!.CumulativeFrequency > 3800)
#endif
model.TimeToReorder--;
// If we haven't hit the reordering time
@@ -392,21 +360,12 @@ namespace SabreTools.Compression.Quantum
for (int i = model.Entries - 1; i >= 0; i--)
{
// Divide with truncation by 2
#if NET48
var sym = model.Symbols[i];
#else
var sym = model.Symbols![i]!;
#endif
sym.CumulativeFrequency >>= 1;
// If we are lower the next frequency
#if NET48
if (i != 0 && sym.CumulativeFrequency <= model.Symbols[i + 1].CumulativeFrequency)
sym.CumulativeFrequency = (ushort)(model.Symbols[i + 1].CumulativeFrequency + 1);
#else
if (i != 0 && sym.CumulativeFrequency <= model.Symbols![i + 1]!.CumulativeFrequency)
sym.CumulativeFrequency = (ushort)(model.Symbols![i + 1]!.CumulativeFrequency + 1);
#endif
}
}
@@ -416,19 +375,11 @@ namespace SabreTools.Compression.Quantum
// Calculate frequencies from cumulative frequencies
for (int i = 0; i < model.Entries; i++)
{
#if NET48
if (i != model.Entries - 1)
model.Symbols[i].CumulativeFrequency -= model.Symbols[i + 1].CumulativeFrequency;
model.Symbols[i].CumulativeFrequency++;
model.Symbols[i].CumulativeFrequency >>= 1;
#else
if (i != model.Entries - 1)
model.Symbols![i]!.CumulativeFrequency -= model.Symbols![i + 1]!.CumulativeFrequency;
model.Symbols![i]!.CumulativeFrequency++;
model.Symbols![i]!.CumulativeFrequency >>= 1;
#endif
}
// Sort frequencies in decreasing order
@@ -436,11 +387,7 @@ namespace SabreTools.Compression.Quantum
{
for (int j = i + 1; j < model.Entries; j++)
{
#if NET48
if (model.Symbols[i].CumulativeFrequency < model.Symbols[j].CumulativeFrequency)
#else
if (model.Symbols![i]!.CumulativeFrequency < model.Symbols![j]!.CumulativeFrequency)
#endif
{
var temp = model.Symbols[i];
model.Symbols[i] = model.Symbols[j];
@@ -453,11 +400,7 @@ namespace SabreTools.Compression.Quantum
for (int i = model.Entries - 1; i >= 0; i--)
{
if (i != model.Entries - 1)
#if NET48
model.Symbols[i].CumulativeFrequency += model.Symbols[i + 1].CumulativeFrequency;
#else
model.Symbols![i]!.CumulativeFrequency += model.Symbols![i + 1]!.CumulativeFrequency;
#endif
}
// Reset the time to reorder

View File

@@ -1,36 +1,34 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- Assembly Properties -->
<TargetFrameworks>net48;net6.0;net7.0;net8.0</TargetFrameworks>
<RuntimeIdentifiers>win-x86;win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
<Version>0.1.1</Version>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<PropertyGroup>
<!-- Assembly Properties -->
<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;osx-arm64</RuntimeIdentifiers>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>0.3.0</Version>
<!-- Package Properties -->
<Authors>Matt Nadareski</Authors>
<Description>Clean compression implementations</Description>
<Copyright>Copyright (c) Matt Nadareski 2022-2023</Copyright>
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
<PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryUrl>https://github.com/SabreTools/SabreTools.Printing</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>compression decompression lz mszip</PackageTags>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>
<!-- Package Properties -->
<Authors>Matt Nadareski</Authors>
<Description>Clean compression implementations</Description>
<Copyright>Copyright (c) Matt Nadareski 2022-2024</Copyright>
<PackageProjectUrl>https://github.com/SabreTools/</PackageProjectUrl>
<PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryUrl>https://github.com/SabreTools/SabreTools.Compression</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>compression decompression lz mszip</PackageTags>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)'!='net48'">
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<None Include="README.md" Pack="true" PackagePath="" />
</ItemGroup>
<ItemGroup>
<None Include="README.md" Pack="true" PackagePath=""/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="SabreTools.IO" Version="1.1.1" />
<PackageReference Include="SabreTools.Models" Version="1.1.5" />
</ItemGroup>
</Project>
<ItemGroup>
<PackageReference Include="SabreTools.IO" Version="1.3.0" />
<PackageReference Include="SabreTools.Models" Version="1.3.0" />
</ItemGroup>
</Project>