Updates recommended

This commit is contained in:
Adam Hathcock
2026-07-27 08:53:52 +01:00
parent 6062623dd8
commit 5ba71a0431
9 changed files with 87 additions and 115 deletions

View File

@@ -2,7 +2,7 @@
<ItemGroup>
<PackageVersion Include="BenchmarkDotNet" Version="0.15.8" />
<PackageVersion Include="Bullseye" Version="6.1.0" />
<PackageVersion Include="AwesomeAssertions" Version="9.4.0" />
<PackageVersion Include="AwesomeAssertions" Version="9.5.0" />
<PackageVersion Include="Glob" Version="1.1.9" />
<PackageVersion Include="JetBrains.Profiler.SelfApi" Version="2.5.18" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />

View File

@@ -24,14 +24,6 @@ public enum EncodingType
/// </summary>
public static class ArchiveEncodingExtensions
{
#if !NETFRAMEWORK
/// <summary>
/// Registers the code pages encoding provider.
/// </summary>
static ArchiveEncodingExtensions() =>
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
#endif
extension(IArchiveEncoding encoding)
{
/// <summary>

View File

@@ -0,0 +1,52 @@
using System.Runtime.CompilerServices;
using System.Text;
namespace SharpCompress.Common;
/// <summary>
/// Registers <see cref="CodePagesEncodingProvider"/> so that legacy code pages (e.g. 437, 866)
/// used by archive headers are resolvable via <see cref="Encoding.GetEncoding(int)"/>.
/// </summary>
/// <remarks>
/// <para>
/// This runs from a module initializer rather than a static constructor. Registration must happen
/// before <em>any</em> encoding lookup, including lookups a caller performs itself while building an
/// <see cref="ArchiveEncoding"/> — for example <c>Encoding.GetEncoding(866)</c>. A static constructor
/// only fires when its own type is first touched, which made registration order-dependent and caused
/// <see cref="System.NotSupportedException"/> for callers that resolved a code page before touching
/// any other SharpCompress type.
/// </para>
/// <para>
/// .NET Framework resolves these code pages natively, so registration is only needed elsewhere.
/// </para>
/// </remarks>
internal static class EncodingProviderRegistration
{
#if !NETFRAMEWORK
// CA2255 discourages [ModuleInitializer] in libraries because load-time work can surprise consumers.
// Registering an encoding provider is the exception it does not account for: the registration has to be
// in place before the first Encoding.GetEncoding call, and that call may be made by the consumer before
// it touches any SharpCompress type. Every lazier trigger reintroduces the ordering bug. Callers who need
// registration to be explicit (e.g. to keep it trimmable) can call RegisterCodePagesProvider themselves.
#pragma warning disable CA2255
[ModuleInitializer]
#pragma warning restore CA2255
internal static void Initialize() => RegisterCodePagesProvider();
private static bool _registered;
/// <summary>
/// Registers the code pages provider if it has not already been registered. Idempotent.
/// </summary>
internal static void RegisterCodePagesProvider()
{
if (_registered)
{
return;
}
_registered = true;
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
}
#endif
}

View File

@@ -1,71 +0,0 @@
using System;
using System.Collections.Generic;
using SharpCompress.Common;
namespace SharpCompress.Compressors.LZMA;
internal static class Log
{
private static readonly Stack<string> INDENT = new();
private static bool NEEDS_INDENT = true;
static Log() => INDENT.Push("");
public static void PushIndent(string indent = " ") => INDENT.Push(INDENT.Peek() + indent);
public static void PopIndent()
{
if (INDENT.Count == 1)
{
throw new ArchiveOperationException();
}
INDENT.Pop();
}
private static void EnsureIndent()
{
if (NEEDS_INDENT)
{
NEEDS_INDENT = false;
}
}
public static void Write(object value)
{
EnsureIndent();
}
public static void Write(string text)
{
EnsureIndent();
}
public static void Write(string format, params object[] args)
{
EnsureIndent();
}
public static void WriteLine()
{
NEEDS_INDENT = true;
}
public static void WriteLine(object value)
{
EnsureIndent();
NEEDS_INDENT = true;
}
public static void WriteLine(string text)
{
EnsureIndent();
NEEDS_INDENT = true;
}
public static void WriteLine(string format, params object[] args)
{
EnsureIndent();
NEEDS_INDENT = true;
}
}

View File

@@ -36,20 +36,16 @@ public static class StreamStackExtensions
}
/// <summary>
/// Gets the root underlying stream at the bottom of the stack.
/// This is useful for seeking when the intermediate streams don't support it.
/// Rewinds by <paramref name="count"/> bytes within the buffered region of the nearest
/// <see cref="SharpCompressStream"/> in the stack.
/// </summary>
public static Stream GetRootStream(this IStreamStack stack)
{
var current = stack.BaseStream();
while (current is IStreamStack streamStack)
{
current = streamStack.BaseStream();
}
return current;
}
internal static void Rewind(this IStreamStack stream, int count)
/// <remarks>
/// Named distinctly from <see cref="SharpCompressStream.Rewind()"/> and
/// <see cref="SharpCompressStream.Rewind(bool)"/>, which rewind to the recording anchor instead.
/// A single <c>Rewind</c> name across both would let <c>Rewind(4)</c> and <c>Rewind(true)</c> select
/// unrelated semantics on the same variable with no compiler complaint.
/// </remarks>
internal static void RewindBytes(this IStreamStack stream, int count)
{
IStreamStack? current = stream;

View File

@@ -0,0 +1,19 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// This file is required for [ModuleInitializer] to work on older target frameworks
// (.NET Framework 4.8, .NET Standard 2.0/2.1). The attribute is recognised by the C# compiler
// by name, so supplying our own definition is enough to enable module initializers there.
#if NETFRAMEWORK || NETSTANDARD2_0 || NETSTANDARD2_1
using System.ComponentModel;
namespace System.Runtime.CompilerServices;
/// <summary>
/// Used to indicate to the compiler that a method should be called in its containing module's initializer.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
internal sealed class ModuleInitializerAttribute : Attribute { }
#endif

View File

@@ -13,14 +13,6 @@ namespace SharpCompress.Test.Tar;
public class TarWriterAsyncTests : WriterTests
{
static TarWriterAsyncTests()
{
#if !NETFRAMEWORK
//fix issue where these tests could not be ran in isolation
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
#endif
}
public TarWriterAsyncTests()
: base(ArchiveType.Tar) => UseExtensionInsteadOfNameToVerify = true;

View File

@@ -11,14 +11,6 @@ namespace SharpCompress.Test.Tar;
public class TarWriterTests : WriterTests
{
static TarWriterTests()
{
#if !NETFRAMEWORK
//fix issue where these tests could not be ran in isolation
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
#endif
}
public TarWriterTests()
: base(ArchiveType.Tar) => UseExtensionInsteadOfNameToVerify = true;

View File

@@ -4,9 +4,9 @@
".NETFramework,Version=v4.8": {
"AwesomeAssertions": {
"type": "Direct",
"requested": "[9.4.0, )",
"resolved": "9.4.0",
"contentHash": "dJxkWiQ8D+xT6Gr2sSL83+Mar+Vpy2JTcUPxFcckpPJ8VYBfSgnk+zqpS6t7kcGnjz8NLyF14qfuoL4bKzzoew==",
"requested": "[9.5.0, )",
"resolved": "9.5.0",
"contentHash": "F92MsjoF8B7IdcWETru4QGZx6VAl38qQPKNGS3kwPwlLB5lb0O4bhFqG8a8sz2estQJWkKmZkVy1r19HTaFcpg==",
"dependencies": {
"System.Threading.Tasks.Extensions": "4.5.4"
}
@@ -331,9 +331,9 @@
"net10.0": {
"AwesomeAssertions": {
"type": "Direct",
"requested": "[9.4.0, )",
"resolved": "9.4.0",
"contentHash": "dJxkWiQ8D+xT6Gr2sSL83+Mar+Vpy2JTcUPxFcckpPJ8VYBfSgnk+zqpS6t7kcGnjz8NLyF14qfuoL4bKzzoew=="
"requested": "[9.5.0, )",
"resolved": "9.5.0",
"contentHash": "F92MsjoF8B7IdcWETru4QGZx6VAl38qQPKNGS3kwPwlLB5lb0O4bhFqG8a8sz2estQJWkKmZkVy1r19HTaFcpg=="
},
"Microsoft.NET.Test.Sdk": {
"type": "Direct",