Change ArchiveEncoding to interface. Simplify class. Question what to do about Forced and complex access

This commit is contained in:
Adam Hathcock
2026-01-07 08:44:12 +00:00
parent be045c4f15
commit 725503d1ce
24 changed files with 83 additions and 84 deletions

View File

@@ -46,7 +46,7 @@ namespace SharpCompress.Common.Ace.Headers
}
}
public AceFileHeader(ArchiveEncoding archiveEncoding)
public AceFileHeader(IArchiveEncoding archiveEncoding)
: base(archiveEncoding, AceHeaderType.FILE) { }
/// <summary>

View File

@@ -31,13 +31,13 @@ namespace SharpCompress.Common.Ace.Headers
(byte)'*',
];
public AceHeader(ArchiveEncoding archiveEncoding, AceHeaderType type)
public AceHeader(IArchiveEncoding archiveEncoding, AceHeaderType type)
{
AceHeaderType = type;
ArchiveEncoding = archiveEncoding;
}
public ArchiveEncoding ArchiveEncoding { get; }
public IArchiveEncoding ArchiveEncoding { get; }
public AceHeaderType AceHeaderType { get; }
public ushort HeaderFlags { get; set; }

View File

@@ -22,7 +22,7 @@ namespace SharpCompress.Common.Ace.Headers
public List<byte> Comment { get; set; } = new();
public byte AceVersion { get; private set; }
public AceMainHeader(ArchiveEncoding archiveEncoding)
public AceMainHeader(IArchiveEncoding archiveEncoding)
: base(archiveEncoding, AceHeaderType.MAIN) { }
/// <summary>

View File

@@ -7,7 +7,7 @@ namespace SharpCompress.Common.Arc
{
public class ArcEntryHeader
{
public ArchiveEncoding ArchiveEncoding { get; }
public IArchiveEncoding ArchiveEncoding { get; }
public CompressionType CompressionMethod { get; private set; }
public string? Name { get; private set; }
public long CompressedSize { get; private set; }
@@ -16,7 +16,7 @@ namespace SharpCompress.Common.Arc
public long OriginalSize { get; private set; }
public long DataStartPosition { get; private set; }
public ArcEntryHeader(ArchiveEncoding archiveEncoding)
public ArcEntryHeader(IArchiveEncoding archiveEncoding)
{
this.ArchiveEncoding = archiveEncoding;
}

View File

@@ -3,55 +3,54 @@ using System.Text;
namespace SharpCompress.Common;
public class ArchiveEncoding
public class ArchiveEncoding : IArchiveEncoding
{
public ArchiveEncoding()
{
Default = Encoding.Default;
Password = Encoding.Default;
UTF8 = Encoding.UTF8;
}
/// <summary>
/// Default encoding to use when archive format doesn't specify one.
/// </summary>
public Encoding? Default { get; set; }
public Encoding Default { get; set; }
/// <summary>
/// ArchiveEncoding used by encryption schemes which don't comply with RFC 2898.
/// </summary>
public Encoding? Password { get; set; }
public Encoding Password { get; set; }
/// <summary>
/// Set this encoding when you want to force it for all encoding operations.
/// Default encoding to use when archive format specifies UTF-8 encoding.
/// </summary>
public Encoding? Forced { get; set; }
/// <summary>
/// Set this when you want to use a custom method for all decoding operations.
/// </summary>
/// <returns>string Func(bytes, index, length)</returns>
public Func<byte[], int, int, string>? CustomDecoder { get; set; }
public ArchiveEncoding()
: this(Encoding.Default, Encoding.Default) { }
public ArchiveEncoding(Encoding def, Encoding password)
{
Default = def;
Password = password;
}
#if !NETFRAMEWORK
static ArchiveEncoding() => Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
#endif
public string Decode(byte[] bytes) => Decode(bytes, 0, bytes.Length);
public string Decode(byte[] bytes, int start, int length) =>
GetDecoder().Invoke(bytes, start, length);
public string DecodeUTF8(byte[] bytes) => Encoding.UTF8.GetString(bytes, 0, bytes.Length);
public byte[] Encode(string str) => GetEncoding().GetBytes(str);
public Encoding GetEncoding() => Forced ?? Default ?? Encoding.UTF8;
public Encoding GetPasswordEncoding() => Password ?? Encoding.UTF8;
public Func<byte[], int, int, string> GetDecoder() =>
CustomDecoder ?? ((bytes, index, count) => GetEncoding().GetString(bytes, index, count));
public Encoding UTF8 { get; set; }
}
public interface IArchiveEncoding
{
/// <summary>
/// Default encoding to use when archive format doesn't specify one.
/// </summary>
public Encoding Default { get; set; }
/// <summary>
/// ArchiveEncoding used by encryption schemes which don't comply with RFC 2898.
/// </summary>
public Encoding Password { get; set; }
/// <summary>
/// Default encoding to use when archive format specifies UTF-8 encoding.
/// </summary>
public Encoding UTF8 { get; set; }
}
public static class ArchiveEncodingExtensions
{
public static byte[] Encode(this IArchiveEncoding encoding, string str) => encoding.Default.GetBytes(str);
public static string Decode(this IArchiveEncoding encoding, byte[] bytes) => encoding.Default.GetString(bytes);
public static string Decode(this IArchiveEncoding encoding, byte[] bytes, int start, int length) =>
encoding.Default.GetString(bytes, start, length);
}

View File

@@ -4,9 +4,9 @@ namespace SharpCompress.Common;
public abstract class FilePart
{
protected FilePart(ArchiveEncoding archiveEncoding) => ArchiveEncoding = archiveEncoding;
protected FilePart(IArchiveEncoding archiveEncoding) => ArchiveEncoding = archiveEncoding;
internal ArchiveEncoding ArchiveEncoding { get; }
internal IArchiveEncoding ArchiveEncoding { get; }
internal abstract string? FilePartName { get; }
public int Index { get; set; }

View File

@@ -13,7 +13,7 @@ internal sealed class GZipFilePart : FilePart
private string? _name;
private readonly Stream _stream;
internal GZipFilePart(Stream stream, ArchiveEncoding archiveEncoding)
internal GZipFilePart(Stream stream, IArchiveEncoding archiveEncoding)
: base(archiveEncoding)
{
_stream = stream;

View File

@@ -7,5 +7,5 @@ public class OptionsBase
/// </summary>
public bool LeaveStreamOpen { get; set; } = true;
public ArchiveEncoding ArchiveEncoding { get; set; } = new();
public IArchiveEncoding ArchiveEncoding { get; set; } = new ArchiveEncoding();
}

View File

@@ -13,7 +13,7 @@ internal class RarHeader : IRarHeader
internal static RarHeader? TryReadBase(
RarCrcBinaryReader reader,
bool isRar5,
ArchiveEncoding archiveEncoding
IArchiveEncoding archiveEncoding
)
{
try
@@ -26,7 +26,7 @@ internal class RarHeader : IRarHeader
}
}
private RarHeader(RarCrcBinaryReader reader, bool isRar5, ArchiveEncoding archiveEncoding)
private RarHeader(RarCrcBinaryReader reader, bool isRar5, IArchiveEncoding archiveEncoding)
{
_headerType = HeaderType.Null;
_isRar5 = isRar5;
@@ -115,7 +115,7 @@ internal class RarHeader : IRarHeader
protected int HeaderSize { get; }
internal ArchiveEncoding ArchiveEncoding { get; }
internal IArchiveEncoding ArchiveEncoding { get; }
/// <summary>
/// Extra header size.

View File

@@ -15,7 +15,7 @@ internal class SevenZipFilePart : FilePart
ArchiveDatabase database,
int index,
CFileItem fileEntry,
ArchiveEncoding archiveEncoding
IArchiveEncoding archiveEncoding
)
: base(archiveEncoding)
{

View File

@@ -11,7 +11,7 @@ internal sealed class TarHeader
internal static readonly DateTime EPOCH = new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public TarHeader(
ArchiveEncoding archiveEncoding,
IArchiveEncoding archiveEncoding,
TarHeaderWriteFormat writeFormat = TarHeaderWriteFormat.GNU_TAR_LONG_LINK
)
{
@@ -30,7 +30,7 @@ internal sealed class TarHeader
internal DateTime LastModifiedTime { get; set; }
internal EntryType EntryType { get; set; }
internal Stream? PackedStream { get; set; }
internal ArchiveEncoding ArchiveEncoding { get; }
internal IArchiveEncoding ArchiveEncoding { get; }
internal const int BLOCK_SIZE = 512;
@@ -63,7 +63,7 @@ internal sealed class TarHeader
//ArchiveEncoding.UTF8.GetBytes("magic").CopyTo(buffer, 257);
var nameByteCount = ArchiveEncoding
.GetEncoding()
.Default
.GetByteCount(Name.NotNull("Name is null"));
if (nameByteCount > 100)
@@ -87,7 +87,7 @@ internal sealed class TarHeader
for (int i = 0; i < dirSeps.Count; i++)
{
int count = ArchiveEncoding
.GetEncoding()
.Default
.GetByteCount(fullName.Substring(0, dirSeps[i]));
if (count < 155)
{
@@ -109,12 +109,12 @@ internal sealed class TarHeader
string namePrefix = fullName.Substring(0, splitIndex);
string name = fullName.Substring(splitIndex + 1);
if (this.ArchiveEncoding.GetEncoding().GetByteCount(namePrefix) >= 155)
if (this.ArchiveEncoding.Default.GetByteCount(namePrefix) >= 155)
throw new Exception(
$"Tar header USTAR format can not fit file name \"{fullName}\" of length {nameByteCount}! Try using GNU Tar format instead!"
);
if (this.ArchiveEncoding.GetEncoding().GetByteCount(name) >= 100)
if (this.ArchiveEncoding.Default.GetByteCount(name) >= 100)
throw new Exception(
$"Tar header USTAR format can not fit file name \"{fullName}\" of length {nameByteCount}! Try using GNU Tar format instead!"
);
@@ -156,7 +156,7 @@ internal sealed class TarHeader
//ArchiveEncoding.UTF8.GetBytes("magic").CopyTo(buffer, 257);
var nameByteCount = ArchiveEncoding
.GetEncoding()
.Default
.GetByteCount(Name.NotNull("Name is null"));
if (nameByteCount > 100)
{
@@ -200,7 +200,7 @@ internal sealed class TarHeader
Name = ArchiveEncoding.Decode(
ArchiveEncoding.Encode(Name.NotNull("Name is null")),
0,
100 - ArchiveEncoding.GetEncoding().GetMaxByteCount(1)
100 - ArchiveEncoding.Default.GetMaxByteCount(1)
);
WriteGnuTarLongLink(output);
}

View File

@@ -54,7 +54,7 @@ public class TarEntry : Entry
StreamingMode mode,
Stream stream,
CompressionType compressionType,
ArchiveEncoding archiveEncoding
IArchiveEncoding archiveEncoding
)
{
foreach (var header in TarHeaderFactory.ReadHeader(mode, stream, archiveEncoding))

View File

@@ -10,7 +10,7 @@ internal static class TarHeaderFactory
internal static IEnumerable<TarHeader?> ReadHeader(
StreamingMode mode,
Stream stream,
ArchiveEncoding archiveEncoding
IArchiveEncoding archiveEncoding
)
{
while (true)

View File

@@ -5,7 +5,7 @@ namespace SharpCompress.Common.Zip.Headers;
internal class DirectoryEntryHeader : ZipFileEntry
{
public DirectoryEntryHeader(ArchiveEncoding archiveEncoding)
public DirectoryEntryHeader(IArchiveEncoding archiveEncoding)
: base(ZipHeaderType.DirectoryEntry, archiveEncoding) { }
internal override void Read(BinaryReader reader)
@@ -41,8 +41,8 @@ internal class DirectoryEntryHeader : ZipFileEntry
if (Flags.HasFlag(HeaderFlags.Efs))
{
Name = ArchiveEncoding.DecodeUTF8(name);
Comment = ArchiveEncoding.DecodeUTF8(comment);
Name = ArchiveEncoding.UTF8.GetString(name);
Comment = ArchiveEncoding.UTF8.GetString(comment);
}
else
{

View File

@@ -5,7 +5,7 @@ namespace SharpCompress.Common.Zip.Headers;
internal class LocalEntryHeader : ZipFileEntry
{
public LocalEntryHeader(ArchiveEncoding archiveEncoding)
public LocalEntryHeader(IArchiveEncoding archiveEncoding)
: base(ZipHeaderType.LocalEntry, archiveEncoding) { }
internal override void Read(BinaryReader reader)
@@ -33,7 +33,7 @@ internal class LocalEntryHeader : ZipFileEntry
if (Flags.HasFlag(HeaderFlags.Efs))
{
Name = ArchiveEncoding.DecodeUTF8(name);
Name = ArchiveEncoding.UTF8.GetString(name);
}
else
{

View File

@@ -7,7 +7,7 @@ namespace SharpCompress.Common.Zip.Headers;
internal abstract class ZipFileEntry : ZipHeader
{
protected ZipFileEntry(ZipHeaderType type, ArchiveEncoding archiveEncoding)
protected ZipFileEntry(ZipHeaderType type, IArchiveEncoding archiveEncoding)
: base(type)
{
Extra = new List<ExtraData>();
@@ -30,7 +30,7 @@ internal abstract class ZipFileEntry : ZipHeader
internal Stream? PackedStream { get; set; }
internal ArchiveEncoding ArchiveEncoding { get; }
internal IArchiveEncoding ArchiveEncoding { get; }
internal string? Name { get; set; }

View File

@@ -8,9 +8,9 @@ internal class PkwareTraditionalEncryptionData
{
private static readonly CRC32 CRC32 = new();
private readonly uint[] _keys = { 0x12345678, 0x23456789, 0x34567890 };
private readonly ArchiveEncoding _archiveEncoding;
private readonly IArchiveEncoding _archiveEncoding;
private PkwareTraditionalEncryptionData(string password, ArchiveEncoding archiveEncoding)
private PkwareTraditionalEncryptionData(string password, IArchiveEncoding archiveEncoding)
{
_archiveEncoding = archiveEncoding;
Initialize(password);
@@ -103,7 +103,7 @@ internal class PkwareTraditionalEncryptionData
internal byte[] StringToByteArray(string value)
{
var a = _archiveEncoding.GetPasswordEncoding().GetBytes(value);
var a = _archiveEncoding.Password.GetBytes(value);
return a;
}

View File

@@ -15,7 +15,7 @@ internal sealed class SeekableZipHeaderFactory : ZipHeaderFactory
private const int MAX_SEARCH_LENGTH_FOR_EOCD = 65557;
private bool _zip64;
internal SeekableZipHeaderFactory(string? password, ArchiveEncoding archiveEncoding)
internal SeekableZipHeaderFactory(string? password, IArchiveEncoding archiveEncoding)
: base(StreamingMode.Seekable, password, archiveEncoding) { }
internal IEnumerable<ZipHeader> ReadSeekableHeader(Stream stream)

View File

@@ -13,7 +13,7 @@ internal class StreamingZipHeaderFactory : ZipHeaderFactory
internal StreamingZipHeaderFactory(
string? password,
ArchiveEncoding archiveEncoding,
IArchiveEncoding archiveEncoding,
IEnumerable<ZipEntry>? entries
)
: base(StreamingMode.Streaming, password, archiveEncoding) => _entries = entries;

View File

@@ -21,12 +21,12 @@ internal class ZipHeaderFactory
protected LocalEntryHeader? _lastEntryHeader;
private readonly string? _password;
private readonly StreamingMode _mode;
private readonly ArchiveEncoding _archiveEncoding;
private readonly IArchiveEncoding _archiveEncoding;
protected ZipHeaderFactory(
StreamingMode mode,
string? password,
ArchiveEncoding archiveEncoding
IArchiveEncoding archiveEncoding
)
{
_mode = mode;

View File

@@ -25,7 +25,7 @@ namespace SharpCompress.Readers.Ace
/// </remarks>
public abstract class AceReader : AbstractReader<AceEntry, AceVolume>
{
private readonly ArchiveEncoding _archiveEncoding;
private readonly IArchiveEncoding _archiveEncoding;
internal AceReader(ReaderOptions options)
: base(options, ArchiveType.Ace)

View File

@@ -23,7 +23,7 @@ public sealed class GZipWriter : AbstractWriter
destination,
CompressionMode.Compress,
(CompressionLevel)(options?.CompressionLevel ?? (int)CompressionLevel.Default),
WriterOptions.ArchiveEncoding.GetEncoding()
WriterOptions.ArchiveEncoding.Default
)
);
}

View File

@@ -12,13 +12,13 @@ internal class ZipCentralDirectoryEntry
{
private readonly ZipCompressionMethod compression;
private readonly string fileName;
private readonly ArchiveEncoding archiveEncoding;
private readonly IArchiveEncoding archiveEncoding;
public ZipCentralDirectoryEntry(
ZipCompressionMethod compression,
string fileName,
ulong headerOffset,
ArchiveEncoding archiveEncoding
IArchiveEncoding archiveEncoding
)
{
this.compression = compression;
@@ -72,7 +72,7 @@ internal class ZipCentralDirectoryEntry
version = 20;
}
var flags = Equals(archiveEncoding.GetEncoding(), Encoding.UTF8)
var flags = Equals(archiveEncoding.Default, Encoding.UTF8)
? HeaderFlags.Efs
: HeaderFlags.None;
if (!outputStream.CanSeek)

View File

@@ -244,7 +244,7 @@ public class ZipWriter : AbstractWriter
{
OutputStream.Write(stackalloc byte[] { 63, 0 }); //version says we used PPMd or LZMA
}
var flags = Equals(WriterOptions.ArchiveEncoding.GetEncoding(), Encoding.UTF8)
var flags = Equals(WriterOptions.ArchiveEncoding.Default, Encoding.UTF8)
? HeaderFlags.Efs
: 0;
if (!OutputStream.CanSeek)