mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-09-22 06:54:40 +00:00
Merge pull request #1380 from adamhathcock/adam/sol-cleanup
Updates recommended by 5.6 Sol
This commit is contained in:
@@ -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>
|
||||
|
||||
52
src/SharpCompress/Common/EncodingProviderRegistration.cs
Normal file
52
src/SharpCompress/Common/EncodingProviderRegistration.cs
Normal 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 can call Encoding.RegisterProvider(CodePagesEncodingProvider.Instance) 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
|
||||
}
|
||||
@@ -313,7 +313,7 @@ internal sealed partial class StreamingZipHeaderFactory
|
||||
var nextHeaderBytes = await _reader
|
||||
.ReadUInt32Async(_cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
_sharpCompressStream.Rewind(sizeof(uint));
|
||||
_sharpCompressStream.RewindBytes(sizeof(uint));
|
||||
|
||||
// Check if next data is PostDataDescriptor, streamed file with 0 length
|
||||
header.HasData = !IsHeader(nextHeaderBytes);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -143,11 +142,11 @@ internal partial class StreamingZipHeaderFactory : ZipHeaderFactory
|
||||
_lastEntryHeader.IsCrcAvailable = true;
|
||||
|
||||
// The DataDescriptor can be either 64bit or 32bit
|
||||
var compressed_size = reader.ReadUInt32();
|
||||
var uncompressed_size = reader.ReadUInt32();
|
||||
var compressedSize = reader.ReadUInt32();
|
||||
var uncompressedSize = reader.ReadUInt32();
|
||||
|
||||
var test_64bit = ((long)uncompressed_size << 32) | compressed_size;
|
||||
if (test_64bit == _lastEntryHeader.CompressedSize)
|
||||
var test64Bit = ((long)uncompressedSize << 32) | compressedSize;
|
||||
if (test64Bit == _lastEntryHeader.CompressedSize)
|
||||
{
|
||||
_lastEntryHeader.UncompressedSize =
|
||||
((long)reader.ReadUInt32() << 32) | headerBytes;
|
||||
@@ -155,7 +154,7 @@ internal partial class StreamingZipHeaderFactory : ZipHeaderFactory
|
||||
}
|
||||
else
|
||||
{
|
||||
_lastEntryHeader.UncompressedSize = uncompressed_size;
|
||||
_lastEntryHeader.UncompressedSize = uncompressedSize;
|
||||
}
|
||||
|
||||
if (pos.HasValue)
|
||||
@@ -193,34 +192,34 @@ internal partial class StreamingZipHeaderFactory : ZipHeaderFactory
|
||||
//entry could be zero bytes so we need to know that.
|
||||
if (header.ZipHeaderType == ZipHeaderType.LocalEntry)
|
||||
{
|
||||
var local_header = ((LocalEntryHeader)header);
|
||||
var dir_header = _entries?.FirstOrDefault(entry =>
|
||||
entry.Key == local_header.Name
|
||||
&& local_header.CompressedSize == 0
|
||||
&& local_header.UncompressedSize == 0
|
||||
&& local_header.Crc == 0
|
||||
&& local_header.IsDirectory == false
|
||||
var localHeader = (LocalEntryHeader)header;
|
||||
var dirHeader = _entries?.FirstOrDefault(entry =>
|
||||
entry.Key == localHeader.Name
|
||||
&& localHeader.CompressedSize == 0
|
||||
&& localHeader.UncompressedSize == 0
|
||||
&& localHeader.Crc == 0
|
||||
&& localHeader.IsDirectory == false
|
||||
);
|
||||
|
||||
if (dir_header != null)
|
||||
if (dirHeader != null)
|
||||
{
|
||||
local_header.UncompressedSize = dir_header.Size;
|
||||
local_header.CompressedSize = dir_header.CompressedSize;
|
||||
local_header.Crc = (uint)dir_header.Crc;
|
||||
local_header.IsCrcAvailable = true;
|
||||
localHeader.UncompressedSize = dirHeader.Size;
|
||||
localHeader.CompressedSize = dirHeader.CompressedSize;
|
||||
localHeader.Crc = (uint)dirHeader.Crc;
|
||||
localHeader.IsCrcAvailable = true;
|
||||
}
|
||||
|
||||
// If we have CompressedSize, there is data to be read
|
||||
if (local_header.CompressedSize > 0)
|
||||
if (localHeader.CompressedSize > 0)
|
||||
{
|
||||
header.HasData = true;
|
||||
} // Check if zip is streaming ( Length is 0 and is declared in PostDataDescriptor )
|
||||
else if (local_header.Flags.HasFlag(HeaderFlags.UsePostDataDescriptor))
|
||||
else if (localHeader.Flags.HasFlag(HeaderFlags.UsePostDataDescriptor))
|
||||
{
|
||||
// Peek ahead to check if next data is a header or file data.
|
||||
// Use the IStreamStack.Rewind mechanism to give back the peeked bytes.
|
||||
var nextHeaderBytes = reader.ReadUInt32();
|
||||
sharpCompressStream.Rewind(sizeof(uint));
|
||||
sharpCompressStream.RewindBytes(sizeof(uint));
|
||||
|
||||
// Check if next data is PostDataDescriptor, streamed file with 0 length
|
||||
header.HasData = !IsHeader(nextHeaderBytes);
|
||||
|
||||
@@ -622,7 +622,7 @@ internal class ZlibBaseStream : Stream, IStreamStack
|
||||
// This handles the case where the decompressor over-read past the end of the entry
|
||||
if (_stream is IStreamStack stack)
|
||||
{
|
||||
stack.Rewind(z.AvailableBytesIn);
|
||||
stack.RewindBytes(z.AvailableBytesIn);
|
||||
}
|
||||
z.AvailableBytesIn = 0;
|
||||
}
|
||||
@@ -643,7 +643,7 @@ internal class ZlibBaseStream : Stream, IStreamStack
|
||||
// This handles the case where the decompressor over-read past the end of the entry
|
||||
if (_stream is IStreamStack stack)
|
||||
{
|
||||
stack.Rewind(z.AvailableBytesIn);
|
||||
stack.RewindBytes(z.AvailableBytesIn);
|
||||
}
|
||||
z.AvailableBytesIn = 0;
|
||||
}
|
||||
@@ -1023,7 +1023,7 @@ internal class ZlibBaseStream : Stream, IStreamStack
|
||||
if (rc == ZlibConstants.Z_STREAM_END && z.AvailableBytesIn != 0 && !_wantCompress)
|
||||
{
|
||||
//rewind the buffer
|
||||
this.Rewind(z.AvailableBytesIn);
|
||||
this.RewindBytes(z.AvailableBytesIn);
|
||||
z.AvailableBytesIn = 0;
|
||||
}
|
||||
|
||||
@@ -1217,7 +1217,7 @@ internal class ZlibBaseStream : Stream, IStreamStack
|
||||
if (rc == ZlibConstants.Z_STREAM_END && z.AvailableBytesIn != 0 && !_wantCompress)
|
||||
{
|
||||
//rewind the buffer
|
||||
this.Rewind(z.AvailableBytesIn);
|
||||
this.RewindBytes(z.AvailableBytesIn);
|
||||
z.AvailableBytesIn = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
19
src/SharpCompress/Polyfills/ModuleInitializerAttribute.cs
Normal file
19
src/SharpCompress/Polyfills/ModuleInitializerAttribute.cs
Normal 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
|
||||
Reference in New Issue
Block a user