mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-09-23 15:34:34 +00:00
Change ArchiveEncoding to interface. Simplify class. Question what to do about Forced and complex access
This commit is contained in:
@@ -46,7 +46,7 @@ namespace SharpCompress.Common.Ace.Headers
|
||||
}
|
||||
}
|
||||
|
||||
public AceFileHeader(ArchiveEncoding archiveEncoding)
|
||||
public AceFileHeader(IArchiveEncoding archiveEncoding)
|
||||
: base(archiveEncoding, AceHeaderType.FILE) { }
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -15,7 +15,7 @@ internal class SevenZipFilePart : FilePart
|
||||
ArchiveDatabase database,
|
||||
int index,
|
||||
CFileItem fileEntry,
|
||||
ArchiveEncoding archiveEncoding
|
||||
IArchiveEncoding archiveEncoding
|
||||
)
|
||||
: base(archiveEncoding)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -10,7 +10,7 @@ internal static class TarHeaderFactory
|
||||
internal static IEnumerable<TarHeader?> ReadHeader(
|
||||
StreamingMode mode,
|
||||
Stream stream,
|
||||
ArchiveEncoding archiveEncoding
|
||||
IArchiveEncoding archiveEncoding
|
||||
)
|
||||
{
|
||||
while (true)
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -23,7 +23,7 @@ public sealed class GZipWriter : AbstractWriter
|
||||
destination,
|
||||
CompressionMode.Compress,
|
||||
(CompressionLevel)(options?.CompressionLevel ?? (int)CompressionLevel.Default),
|
||||
WriterOptions.ArchiveEncoding.GetEncoding()
|
||||
WriterOptions.ArchiveEncoding.Default
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user