mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-09-25 16:34:45 +00:00
cleanup and run csharpier
This commit is contained in:
@@ -82,7 +82,7 @@ namespace SharpCompress.Algorithms
|
||||
public static int EvenReduceSum(Vector256<int> accumulator)
|
||||
{
|
||||
Vector128<int> vsum = Sse2.Add(accumulator.GetLower(), accumulator.GetUpper()); // add upper lane to lower lane
|
||||
vsum = Sse2.Add(vsum, Sse2.Shuffle(vsum, 0b_11_10_11_10)); // add high to low
|
||||
vsum = Sse2.Add(vsum, Sse2.Shuffle(vsum, 0b_11_10_11_10)); // add high to low
|
||||
|
||||
// Vector128<int>.ToScalar() isn't optimized pre-net5.0 https://github.com/dotnet/runtime/pull/37882
|
||||
return Sse2.ConvertToInt32(vsum);
|
||||
@@ -107,11 +107,42 @@ namespace SharpCompress.Algorithms
|
||||
private const int BlockSize = 1 << 5;
|
||||
|
||||
// The C# compiler emits this as a compile-time constant embedded in the PE file.
|
||||
private static ReadOnlySpan<byte> Tap1Tap2 => new byte[]
|
||||
{
|
||||
32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, // tap1
|
||||
16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 // tap2
|
||||
};
|
||||
private static ReadOnlySpan<byte> Tap1Tap2 =>
|
||||
new byte[]
|
||||
{
|
||||
32,
|
||||
31,
|
||||
30,
|
||||
29,
|
||||
28,
|
||||
27,
|
||||
26,
|
||||
25,
|
||||
24,
|
||||
23,
|
||||
22,
|
||||
21,
|
||||
20,
|
||||
19,
|
||||
18,
|
||||
17, // tap1
|
||||
16,
|
||||
15,
|
||||
14,
|
||||
13,
|
||||
12,
|
||||
11,
|
||||
10,
|
||||
9,
|
||||
8,
|
||||
7,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
1 // tap2
|
||||
};
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
@@ -120,8 +151,7 @@ namespace SharpCompress.Algorithms
|
||||
/// <param name="buffer">The readonly span of bytes.</param>
|
||||
/// <returns>The <see cref="uint"/>.</returns>
|
||||
[MethodImpl(InliningOptions.ShortMethod)]
|
||||
public static uint Calculate(ReadOnlySpan<byte> buffer)
|
||||
=> Calculate(SeedValue, buffer);
|
||||
public static uint Calculate(ReadOnlySpan<byte> buffer) => Calculate(SeedValue, buffer);
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the Adler32 checksum with the bytes taken from the span and seed.
|
||||
@@ -181,7 +211,7 @@ namespace SharpCompress.Algorithms
|
||||
|
||||
while (blocks > 0)
|
||||
{
|
||||
uint n = NMAX / BlockSize; /* The NMAX constraint. */
|
||||
uint n = NMAX / BlockSize; /* The NMAX constraint. */
|
||||
if (n > blocks)
|
||||
{
|
||||
n = blocks;
|
||||
@@ -206,23 +236,28 @@ namespace SharpCompress.Algorithms
|
||||
|
||||
// Horizontally add the bytes for s1, multiply-adds the
|
||||
// bytes by [ 32, 31, 30, ... ] for s2.
|
||||
v_s1 = Sse2.Add(v_s1, Sse2.SumAbsoluteDifferences(bytes1, zero).AsUInt32());
|
||||
v_s1 = Sse2.Add(
|
||||
v_s1,
|
||||
Sse2.SumAbsoluteDifferences(bytes1, zero).AsUInt32()
|
||||
);
|
||||
Vector128<short> mad1 = Ssse3.MultiplyAddAdjacent(bytes1, tap1);
|
||||
v_s2 = Sse2.Add(v_s2, Sse2.MultiplyAddAdjacent(mad1, ones).AsUInt32());
|
||||
|
||||
v_s1 = Sse2.Add(v_s1, Sse2.SumAbsoluteDifferences(bytes2, zero).AsUInt32());
|
||||
v_s1 = Sse2.Add(
|
||||
v_s1,
|
||||
Sse2.SumAbsoluteDifferences(bytes2, zero).AsUInt32()
|
||||
);
|
||||
Vector128<short> mad2 = Ssse3.MultiplyAddAdjacent(bytes2, tap2);
|
||||
v_s2 = Sse2.Add(v_s2, Sse2.MultiplyAddAdjacent(mad2, ones).AsUInt32());
|
||||
|
||||
localBufferPtr += BlockSize;
|
||||
}
|
||||
while (--n > 0);
|
||||
} while (--n > 0);
|
||||
|
||||
v_s2 = Sse2.Add(v_s2, Sse2.ShiftLeftLogical(v_ps, 5));
|
||||
|
||||
// Sum epi32 ints v_s1(s2) and accumulate in s1(s2).
|
||||
const byte S2301 = 0b1011_0001; // A B C D -> B A D C
|
||||
const byte S1032 = 0b0100_1110; // A B C D -> C D A B
|
||||
const byte S2301 = 0b1011_0001; // A B C D -> B A D C
|
||||
const byte S1032 = 0b0100_1110; // A B C D -> C D A B
|
||||
|
||||
v_s1 = Sse2.Add(v_s1, Sse2.Shuffle(v_s1, S1032));
|
||||
|
||||
@@ -262,7 +297,40 @@ namespace SharpCompress.Algorithms
|
||||
|
||||
Vector256<byte> zero = Vector256<byte>.Zero;
|
||||
var dot3v = Vector256.Create((short)1);
|
||||
var dot2v = Vector256.Create(32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1);
|
||||
var dot2v = Vector256.Create(
|
||||
32,
|
||||
31,
|
||||
30,
|
||||
29,
|
||||
28,
|
||||
27,
|
||||
26,
|
||||
25,
|
||||
24,
|
||||
23,
|
||||
22,
|
||||
21,
|
||||
20,
|
||||
19,
|
||||
18,
|
||||
17,
|
||||
16,
|
||||
15,
|
||||
14,
|
||||
13,
|
||||
12,
|
||||
11,
|
||||
10,
|
||||
9,
|
||||
8,
|
||||
7,
|
||||
6,
|
||||
5,
|
||||
4,
|
||||
3,
|
||||
2,
|
||||
1
|
||||
);
|
||||
|
||||
// Process n blocks of data. At most NMAX data bytes can be
|
||||
// processed before s2 must be reduced modulo BASE.
|
||||
@@ -325,7 +393,12 @@ namespace SharpCompress.Algorithms
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe void HandleLeftOver(byte* localBufferPtr, uint length, ref uint s1, ref uint s2)
|
||||
private static unsafe void HandleLeftOver(
|
||||
byte* localBufferPtr,
|
||||
uint length,
|
||||
ref uint s1,
|
||||
ref uint s2
|
||||
)
|
||||
{
|
||||
if (length >= 16)
|
||||
{
|
||||
|
||||
@@ -42,13 +42,17 @@ namespace SharpCompress.Archives
|
||||
lazyVolumes = new LazyReadOnlyCollection<TVolume>(Enumerable.Empty<TVolume>());
|
||||
lazyEntries = new LazyReadOnlyCollection<TEntry>(Enumerable.Empty<TEntry>());
|
||||
}
|
||||
|
||||
#nullable enable
|
||||
|
||||
public ArchiveType Type { get; }
|
||||
|
||||
void IArchiveExtractionListener.FireEntryExtractionBegin(IArchiveEntry entry)
|
||||
{
|
||||
EntryExtractionBegin?.Invoke(this, new ArchiveExtractionEventArgs<IArchiveEntry>(entry));
|
||||
EntryExtractionBegin?.Invoke(
|
||||
this,
|
||||
new ArchiveExtractionEventArgs<IArchiveEntry>(entry)
|
||||
);
|
||||
}
|
||||
|
||||
void IArchiveExtractionListener.FireEntryExtractionEnd(IArchiveEntry entry)
|
||||
@@ -78,12 +82,14 @@ namespace SharpCompress.Archives
|
||||
/// <summary>
|
||||
/// The total size of the files compressed in the archive.
|
||||
/// </summary>
|
||||
public virtual long TotalSize => Entries.Aggregate(0L, (total, cf) => total + cf.CompressedSize);
|
||||
public virtual long TotalSize =>
|
||||
Entries.Aggregate(0L, (total, cf) => total + cf.CompressedSize);
|
||||
|
||||
/// <summary>
|
||||
/// The total size of the files as uncompressed in the archive.
|
||||
/// </summary>
|
||||
public virtual long TotalUncompressSize => Entries.Aggregate(0L, (total, cf) => total + cf.Size);
|
||||
public virtual long TotalUncompressSize =>
|
||||
Entries.Aggregate(0L, (total, cf) => total + cf.Size);
|
||||
|
||||
protected abstract IEnumerable<TVolume> LoadVolumes(SourceStream srcStream);
|
||||
protected abstract IEnumerable<TEntry> LoadEntries(IEnumerable<TVolume> volumes);
|
||||
@@ -110,21 +116,34 @@ namespace SharpCompress.Archives
|
||||
lazyVolumes.EnsureFullyLoaded();
|
||||
}
|
||||
|
||||
void IExtractionListener.FireCompressedBytesRead(long currentPartCompressedBytes, long compressedReadBytes)
|
||||
void IExtractionListener.FireCompressedBytesRead(
|
||||
long currentPartCompressedBytes,
|
||||
long compressedReadBytes
|
||||
)
|
||||
{
|
||||
CompressedBytesRead?.Invoke(this, new CompressedBytesReadEventArgs(
|
||||
currentFilePartCompressedBytesRead: currentPartCompressedBytes,
|
||||
compressedBytesRead: compressedReadBytes
|
||||
));
|
||||
CompressedBytesRead?.Invoke(
|
||||
this,
|
||||
new CompressedBytesReadEventArgs(
|
||||
currentFilePartCompressedBytesRead: currentPartCompressedBytes,
|
||||
compressedBytesRead: compressedReadBytes
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void IExtractionListener.FireFilePartExtractionBegin(string name, long size, long compressedSize)
|
||||
void IExtractionListener.FireFilePartExtractionBegin(
|
||||
string name,
|
||||
long size,
|
||||
long compressedSize
|
||||
)
|
||||
{
|
||||
FilePartExtractionBegin?.Invoke(this, new FilePartExtractionBeginEventArgs(
|
||||
compressedSize: compressedSize,
|
||||
size: size,
|
||||
name: name
|
||||
));
|
||||
FilePartExtractionBegin?.Invoke(
|
||||
this,
|
||||
new FilePartExtractionBeginEventArgs(
|
||||
compressedSize: compressedSize,
|
||||
size: size,
|
||||
name: name
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -9,7 +9,9 @@ using SharpCompress.Writers;
|
||||
|
||||
namespace SharpCompress.Archives
|
||||
{
|
||||
public abstract class AbstractWritableArchive<TEntry, TVolume> : AbstractArchive<TEntry, TVolume>, IWritableArchive
|
||||
public abstract class AbstractWritableArchive<TEntry, TVolume>
|
||||
: AbstractArchive<TEntry, TVolume>,
|
||||
IWritableArchive
|
||||
where TEntry : IArchiveEntry
|
||||
where TVolume : IVolume
|
||||
{
|
||||
@@ -29,6 +31,7 @@ namespace SharpCompress.Archives
|
||||
archive.RebuildModifiedCollection();
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<TEntry> newEntries = new List<TEntry>();
|
||||
private readonly List<TEntry> removedEntries = new List<TEntry>();
|
||||
|
||||
@@ -36,15 +39,10 @@ namespace SharpCompress.Archives
|
||||
private bool hasModifications;
|
||||
private bool pauseRebuilding;
|
||||
|
||||
internal AbstractWritableArchive(ArchiveType type)
|
||||
: base(type)
|
||||
{
|
||||
}
|
||||
internal AbstractWritableArchive(ArchiveType type) : base(type) { }
|
||||
|
||||
internal AbstractWritableArchive(ArchiveType type, SourceStream srcStream)
|
||||
: base(type, srcStream)
|
||||
{
|
||||
}
|
||||
: base(type, srcStream) { }
|
||||
|
||||
public override ICollection<TEntry> Entries
|
||||
{
|
||||
@@ -75,7 +73,10 @@ namespace SharpCompress.Archives
|
||||
modifiedEntries.AddRange(OldEntries.Concat(newEntries));
|
||||
}
|
||||
|
||||
private IEnumerable<TEntry> OldEntries { get { return base.Entries.Where(x => !removedEntries.Contains(x)); } }
|
||||
private IEnumerable<TEntry> OldEntries
|
||||
{
|
||||
get { return base.Entries.Where(x => !removedEntries.Contains(x)); }
|
||||
}
|
||||
|
||||
public void RemoveEntry(TEntry entry)
|
||||
{
|
||||
@@ -91,19 +92,29 @@ namespace SharpCompress.Archives
|
||||
RemoveEntry((TEntry)entry);
|
||||
}
|
||||
|
||||
public TEntry AddEntry(string key, Stream source,
|
||||
long size = 0, DateTime? modified = null)
|
||||
public TEntry AddEntry(string key, Stream source, long size = 0, DateTime? modified = null)
|
||||
{
|
||||
return AddEntry(key, source, false, size, modified);
|
||||
}
|
||||
|
||||
IArchiveEntry IWritableArchive.AddEntry(string key, Stream source, bool closeStream, long size, DateTime? modified)
|
||||
IArchiveEntry IWritableArchive.AddEntry(
|
||||
string key,
|
||||
Stream source,
|
||||
bool closeStream,
|
||||
long size,
|
||||
DateTime? modified
|
||||
)
|
||||
{
|
||||
return AddEntry(key, source, closeStream, size, modified);
|
||||
}
|
||||
|
||||
public TEntry AddEntry(string key, Stream source, bool closeStream,
|
||||
long size = 0, DateTime? modified = null)
|
||||
public TEntry AddEntry(
|
||||
string key,
|
||||
Stream source,
|
||||
bool closeStream,
|
||||
long size = 0,
|
||||
DateTime? modified = null
|
||||
)
|
||||
{
|
||||
if (key.Length > 0 && key[0] is '/' or '\\')
|
||||
{
|
||||
@@ -136,24 +147,43 @@ namespace SharpCompress.Archives
|
||||
public void SaveTo(Stream stream, WriterOptions options)
|
||||
{
|
||||
//reset streams of new entries
|
||||
newEntries.Cast<IWritableArchiveEntry>().ForEach(x => x.Stream.Seek(0, SeekOrigin.Begin));
|
||||
newEntries
|
||||
.Cast<IWritableArchiveEntry>()
|
||||
.ForEach(x => x.Stream.Seek(0, SeekOrigin.Begin));
|
||||
SaveTo(stream, options, OldEntries, newEntries);
|
||||
}
|
||||
|
||||
protected TEntry CreateEntry(string key, Stream source, long size, DateTime? modified,
|
||||
bool closeStream)
|
||||
protected TEntry CreateEntry(
|
||||
string key,
|
||||
Stream source,
|
||||
long size,
|
||||
DateTime? modified,
|
||||
bool closeStream
|
||||
)
|
||||
{
|
||||
if (!source.CanRead || !source.CanSeek)
|
||||
{
|
||||
throw new ArgumentException("Streams must be readable and seekable to use the Writing Archive API");
|
||||
throw new ArgumentException(
|
||||
"Streams must be readable and seekable to use the Writing Archive API"
|
||||
);
|
||||
}
|
||||
return CreateEntryInternal(key, source, size, modified, closeStream);
|
||||
}
|
||||
|
||||
protected abstract TEntry CreateEntryInternal(string key, Stream source, long size, DateTime? modified,
|
||||
bool closeStream);
|
||||
protected abstract TEntry CreateEntryInternal(
|
||||
string key,
|
||||
Stream source,
|
||||
long size,
|
||||
DateTime? modified,
|
||||
bool closeStream
|
||||
);
|
||||
|
||||
protected abstract void SaveTo(Stream stream, WriterOptions options, IEnumerable<TEntry> oldEntries, IEnumerable<TEntry> newEntries);
|
||||
protected abstract void SaveTo(
|
||||
Stream stream,
|
||||
WriterOptions options,
|
||||
IEnumerable<TEntry> oldEntries,
|
||||
IEnumerable<TEntry> newEntries
|
||||
);
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
|
||||
@@ -31,14 +31,13 @@ namespace SharpCompress.Archives
|
||||
|
||||
public static IWritableArchive Create(ArchiveType type)
|
||||
{
|
||||
var factory = Factories.Factory
|
||||
.Factories
|
||||
var factory = Factories.Factory.Factories
|
||||
.OfType<IWriteableArchiveFactory>()
|
||||
.Where(item => item.KnownArchiveType == type)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (factory != null)
|
||||
return factory.CreateWriteableArchive();
|
||||
return factory.CreateWriteableArchive();
|
||||
|
||||
throw new NotSupportedException("Cannot create Archives of type: " + type);
|
||||
}
|
||||
@@ -60,7 +59,7 @@ namespace SharpCompress.Archives
|
||||
/// <param name="fileInfo"></param>
|
||||
/// <param name="options"></param>
|
||||
public static IArchive Open(FileInfo fileInfo, ReaderOptions? options = null)
|
||||
{
|
||||
{
|
||||
options ??= new ReaderOptions { LeaveStreamOpen = false };
|
||||
|
||||
return FindFactory<IArchiveFactory>(fileInfo).Open(fileInfo, options);
|
||||
@@ -105,14 +104,17 @@ namespace SharpCompress.Archives
|
||||
firstStream.CheckNotNull(nameof(firstStream));
|
||||
options ??= new ReaderOptions();
|
||||
|
||||
return FindFactory<IMultiArchiveFactory>(firstStream).Open(streamsArray, options);
|
||||
}
|
||||
return FindFactory<IMultiArchiveFactory>(firstStream).Open(streamsArray, options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract to specific directory, retaining filename
|
||||
/// </summary>
|
||||
public static void WriteToDirectory(string sourceArchive, string destinationDirectory,
|
||||
ExtractionOptions? options = null)
|
||||
public static void WriteToDirectory(
|
||||
string sourceArchive,
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options = null
|
||||
)
|
||||
{
|
||||
using IArchive archive = Open(sourceArchive);
|
||||
foreach (IArchiveEntry entry in archive.Entries)
|
||||
@@ -121,8 +123,7 @@ namespace SharpCompress.Archives
|
||||
}
|
||||
}
|
||||
|
||||
private static T FindFactory<T>(FileInfo finfo)
|
||||
where T : IFactory
|
||||
private static T FindFactory<T>(FileInfo finfo) where T : IFactory
|
||||
{
|
||||
finfo.CheckNotNull(nameof(finfo));
|
||||
using (Stream stream = finfo.OpenRead())
|
||||
@@ -131,8 +132,7 @@ namespace SharpCompress.Archives
|
||||
}
|
||||
}
|
||||
|
||||
private static T FindFactory<T>(Stream stream)
|
||||
where T: IFactory
|
||||
private static T FindFactory<T>(Stream stream) where T : IFactory
|
||||
{
|
||||
stream.CheckNotNull(nameof(stream));
|
||||
if (!stream.CanRead || !stream.CanSeek)
|
||||
@@ -158,7 +158,9 @@ namespace SharpCompress.Archives
|
||||
|
||||
var extensions = string.Join(", ", factories.Select(item => item.Name));
|
||||
|
||||
throw new InvalidOperationException($"Cannot determine compressed stream type. Supported Archive Formats: {extensions}");
|
||||
throw new InvalidOperationException(
|
||||
$"Cannot determine compressed stream type. Supported Archive Formats: {extensions}"
|
||||
);
|
||||
}
|
||||
|
||||
public static bool IsArchive(string filePath, out ArchiveType? type)
|
||||
@@ -180,7 +182,7 @@ namespace SharpCompress.Archives
|
||||
|
||||
var startPosition = stream.Position;
|
||||
|
||||
foreach(var factory in Factories.Factory.Factories)
|
||||
foreach (var factory in Factories.Factory.Factories)
|
||||
{
|
||||
stream.Position = startPosition;
|
||||
|
||||
@@ -213,9 +215,9 @@ namespace SharpCompress.Archives
|
||||
public static IEnumerable<FileInfo> GetFileParts(FileInfo part1)
|
||||
{
|
||||
part1.CheckNotNull(nameof(part1));
|
||||
yield return part1;
|
||||
yield return part1;
|
||||
|
||||
foreach(var factory in Factory.Factories.OfType<IFactory>())
|
||||
foreach (var factory in Factory.Factories.OfType<IFactory>())
|
||||
{
|
||||
int i = 1;
|
||||
FileInfo? part = factory.GetFilePart(i++, part1);
|
||||
|
||||
@@ -18,12 +18,19 @@ namespace SharpCompress.Archives
|
||||
//split 001, 002 ...
|
||||
Match m = Regex.Match(part1.Name, @"^(.*\.)([0-9]+)$", RegexOptions.IgnoreCase);
|
||||
if (m.Success)
|
||||
item = new FileInfo(Path.Combine(part1.DirectoryName!, String.Concat(m.Groups[1].Value, (index + 1).ToString().PadLeft(m.Groups[2].Value.Length, '0'))));
|
||||
item = new FileInfo(
|
||||
Path.Combine(
|
||||
part1.DirectoryName!,
|
||||
String.Concat(
|
||||
m.Groups[1].Value,
|
||||
(index + 1).ToString().PadLeft(m.Groups[2].Value.Length, '0')
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if (item != null && item.Exists)
|
||||
return item;
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,13 @@ namespace SharpCompress.Archives.GZip
|
||||
public static GZipArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
fileInfo.CheckNotNull(nameof(fileInfo));
|
||||
return new GZipArchive(new SourceStream(fileInfo, i => ArchiveVolumeFactory.GetFilePart(i, fileInfo), readerOptions ?? new ReaderOptions()));
|
||||
return new GZipArchive(
|
||||
new SourceStream(
|
||||
fileInfo,
|
||||
i => ArchiveVolumeFactory.GetFilePart(i, fileInfo),
|
||||
readerOptions ?? new ReaderOptions()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -41,11 +47,20 @@ namespace SharpCompress.Archives.GZip
|
||||
/// </summary>
|
||||
/// <param name="fileInfos"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
public static GZipArchive Open(IEnumerable<FileInfo> fileInfos, ReaderOptions? readerOptions = null)
|
||||
public static GZipArchive Open(
|
||||
IEnumerable<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
fileInfos.CheckNotNull(nameof(fileInfos));
|
||||
FileInfo[] files = fileInfos.ToArray();
|
||||
return new GZipArchive(new SourceStream(files[0], i => i < files.Length ? files[i] : null, readerOptions ?? new ReaderOptions()));
|
||||
return new GZipArchive(
|
||||
new SourceStream(
|
||||
files[0],
|
||||
i => i < files.Length ? files[i] : null,
|
||||
readerOptions ?? new ReaderOptions()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -53,11 +68,20 @@ namespace SharpCompress.Archives.GZip
|
||||
/// </summary>
|
||||
/// <param name="streams"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
public static GZipArchive Open(IEnumerable<Stream> streams, ReaderOptions? readerOptions = null)
|
||||
public static GZipArchive Open(
|
||||
IEnumerable<Stream> streams,
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
streams.CheckNotNull(nameof(streams));
|
||||
Stream[] strms = streams.ToArray();
|
||||
return new GZipArchive(new SourceStream(strms[0], i => i < strms.Length ? strms[i] : null, readerOptions ?? new ReaderOptions()));
|
||||
return new GZipArchive(
|
||||
new SourceStream(
|
||||
strms[0],
|
||||
i => i < strms.Length ? strms[i] : null,
|
||||
readerOptions ?? new ReaderOptions()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -68,7 +92,9 @@ namespace SharpCompress.Archives.GZip
|
||||
public static GZipArchive Open(Stream stream, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
stream.CheckNotNull(nameof(stream));
|
||||
return new GZipArchive(new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions()));
|
||||
return new GZipArchive(
|
||||
new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions())
|
||||
);
|
||||
}
|
||||
|
||||
public static GZipArchive Create()
|
||||
@@ -81,10 +107,7 @@ namespace SharpCompress.Archives.GZip
|
||||
/// </summary>
|
||||
/// <param name="srcStream"></param>
|
||||
/// <param name="options"></param>
|
||||
internal GZipArchive(SourceStream srcStream)
|
||||
: base(ArchiveType.Tar, srcStream)
|
||||
{
|
||||
}
|
||||
internal GZipArchive(SourceStream srcStream) : base(ArchiveType.Tar, srcStream) { }
|
||||
|
||||
protected override IEnumerable<GZipVolume> LoadVolumes(SourceStream srcStream)
|
||||
{
|
||||
@@ -92,6 +115,7 @@ namespace SharpCompress.Archives.GZip
|
||||
int idx = 0;
|
||||
return srcStream.Streams.Select(a => new GZipVolume(a, ReaderOptions, idx++));
|
||||
}
|
||||
|
||||
public static bool IsGZipFile(string filePath)
|
||||
{
|
||||
return IsGZipFile(new FileInfo(filePath));
|
||||
@@ -140,24 +164,36 @@ namespace SharpCompress.Archives.GZip
|
||||
return true;
|
||||
}
|
||||
|
||||
internal GZipArchive()
|
||||
: base(ArchiveType.GZip)
|
||||
{
|
||||
}
|
||||
internal GZipArchive() : base(ArchiveType.GZip) { }
|
||||
|
||||
protected override GZipArchiveEntry CreateEntryInternal(string filePath, Stream source, long size, DateTime? modified,
|
||||
bool closeStream)
|
||||
protected override GZipArchiveEntry CreateEntryInternal(
|
||||
string filePath,
|
||||
Stream source,
|
||||
long size,
|
||||
DateTime? modified,
|
||||
bool closeStream
|
||||
)
|
||||
{
|
||||
if (Entries.Any())
|
||||
{
|
||||
throw new InvalidOperationException("Only one entry is allowed in a GZip Archive");
|
||||
}
|
||||
return new GZipWritableArchiveEntry(this, source, filePath, size, modified, closeStream);
|
||||
return new GZipWritableArchiveEntry(
|
||||
this,
|
||||
source,
|
||||
filePath,
|
||||
size,
|
||||
modified,
|
||||
closeStream
|
||||
);
|
||||
}
|
||||
|
||||
protected override void SaveTo(Stream stream, WriterOptions options,
|
||||
IEnumerable<GZipArchiveEntry> oldEntries,
|
||||
IEnumerable<GZipArchiveEntry> newEntries)
|
||||
protected override void SaveTo(
|
||||
Stream stream,
|
||||
WriterOptions options,
|
||||
IEnumerable<GZipArchiveEntry> oldEntries,
|
||||
IEnumerable<GZipArchiveEntry> newEntries
|
||||
)
|
||||
{
|
||||
if (Entries.Count > 1)
|
||||
{
|
||||
@@ -165,8 +201,7 @@ namespace SharpCompress.Archives.GZip
|
||||
}
|
||||
using (var writer = new GZipWriter(stream, new GZipWriterOptions(options)))
|
||||
{
|
||||
foreach (var entry in oldEntries.Concat(newEntries)
|
||||
.Where(x => !x.IsDirectory))
|
||||
foreach (var entry in oldEntries.Concat(newEntries).Where(x => !x.IsDirectory))
|
||||
{
|
||||
using (var entryStream = entry.OpenEntryStream())
|
||||
{
|
||||
@@ -176,10 +211,15 @@ namespace SharpCompress.Archives.GZip
|
||||
}
|
||||
}
|
||||
|
||||
protected override IEnumerable<GZipArchiveEntry> LoadEntries(IEnumerable<GZipVolume> volumes)
|
||||
protected override IEnumerable<GZipArchiveEntry> LoadEntries(
|
||||
IEnumerable<GZipVolume> volumes
|
||||
)
|
||||
{
|
||||
Stream stream = volumes.Single().Stream;
|
||||
yield return new GZipArchiveEntry(this, new GZipFilePart(stream, ReaderOptions.ArchiveEncoding));
|
||||
yield return new GZipArchiveEntry(
|
||||
this,
|
||||
new GZipFilePart(stream, ReaderOptions.ArchiveEncoding)
|
||||
);
|
||||
}
|
||||
|
||||
protected override IReader CreateReaderForSolidExtraction()
|
||||
|
||||
@@ -6,8 +6,7 @@ namespace SharpCompress.Archives.GZip
|
||||
{
|
||||
public class GZipArchiveEntry : GZipEntry, IArchiveEntry
|
||||
{
|
||||
internal GZipArchiveEntry(GZipArchive archive, GZipFilePart part)
|
||||
: base(part)
|
||||
internal GZipArchiveEntry(GZipArchive archive, GZipFilePart part) : base(part)
|
||||
{
|
||||
Archive = archive;
|
||||
}
|
||||
@@ -31,4 +30,4 @@ namespace SharpCompress.Archives.GZip
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,14 @@ namespace SharpCompress.Archives.GZip
|
||||
private readonly bool closeStream;
|
||||
private readonly Stream stream;
|
||||
|
||||
internal GZipWritableArchiveEntry(GZipArchive archive, Stream stream,
|
||||
string path, long size, DateTime? lastModified, bool closeStream)
|
||||
: base(archive, null)
|
||||
internal GZipWritableArchiveEntry(
|
||||
GZipArchive archive,
|
||||
Stream stream,
|
||||
string path,
|
||||
long size,
|
||||
DateTime? lastModified,
|
||||
bool closeStream
|
||||
) : base(archive, null)
|
||||
{
|
||||
this.stream = stream;
|
||||
Key = path;
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace SharpCompress.Archives
|
||||
|
||||
/// <summary>
|
||||
/// Use this method to extract all entries in an archive in order.
|
||||
/// This is primarily for SOLID Rar Archives or 7Zip Archives as they need to be
|
||||
/// This is primarily for SOLID Rar Archives or 7Zip Archives as they need to be
|
||||
/// extracted sequentially for the best performance.
|
||||
/// </summary>
|
||||
IReader ExtractAllEntries();
|
||||
@@ -46,4 +46,4 @@ namespace SharpCompress.Archives
|
||||
/// </summary>
|
||||
long TotalUncompressSize { get; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,4 +21,4 @@ namespace SharpCompress.Archives
|
||||
/// </summary>
|
||||
IArchive Archive { get; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,11 @@ namespace SharpCompress.Archives
|
||||
var streamListener = (IArchiveExtractionListener)archiveEntry.Archive;
|
||||
streamListener.EnsureEntriesLoaded();
|
||||
streamListener.FireEntryExtractionBegin(archiveEntry);
|
||||
streamListener.FireFilePartExtractionBegin(archiveEntry.Key, archiveEntry.Size, archiveEntry.CompressedSize);
|
||||
streamListener.FireFilePartExtractionBegin(
|
||||
archiveEntry.Key,
|
||||
archiveEntry.Size,
|
||||
archiveEntry.CompressedSize
|
||||
);
|
||||
var entryStream = archiveEntry.OpenEntryStream();
|
||||
if (entryStream is null)
|
||||
{
|
||||
@@ -35,29 +39,41 @@ namespace SharpCompress.Archives
|
||||
/// <summary>
|
||||
/// Extract to specific directory, retaining filename
|
||||
/// </summary>
|
||||
public static void WriteToDirectory(this IArchiveEntry entry, string destinationDirectory,
|
||||
ExtractionOptions? options = null)
|
||||
public static void WriteToDirectory(
|
||||
this IArchiveEntry entry,
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options = null
|
||||
)
|
||||
{
|
||||
ExtractionMethods.WriteEntryToDirectory(entry, destinationDirectory, options,
|
||||
entry.WriteToFile);
|
||||
ExtractionMethods.WriteEntryToDirectory(
|
||||
entry,
|
||||
destinationDirectory,
|
||||
options,
|
||||
entry.WriteToFile
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract to specific file
|
||||
/// </summary>
|
||||
public static void WriteToFile(this IArchiveEntry entry,
|
||||
string destinationFileName,
|
||||
ExtractionOptions? options = null)
|
||||
public static void WriteToFile(
|
||||
this IArchiveEntry entry,
|
||||
string destinationFileName,
|
||||
ExtractionOptions? options = null
|
||||
)
|
||||
{
|
||||
|
||||
ExtractionMethods.WriteEntryToFile(entry, destinationFileName, options,
|
||||
(x, fm) =>
|
||||
{
|
||||
using (FileStream fs = File.Open(destinationFileName, fm))
|
||||
{
|
||||
entry.WriteTo(fs);
|
||||
}
|
||||
});
|
||||
ExtractionMethods.WriteEntryToFile(
|
||||
entry,
|
||||
destinationFileName,
|
||||
options,
|
||||
(x, fm) =>
|
||||
{
|
||||
using (FileStream fs = File.Open(destinationFileName, fm))
|
||||
{
|
||||
entry.WriteTo(fs);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,11 @@ namespace SharpCompress.Archives
|
||||
/// <summary>
|
||||
/// Extract to specific directory, retaining filename
|
||||
/// </summary>
|
||||
public static void WriteToDirectory(this IArchive archive, string destinationDirectory,
|
||||
ExtractionOptions? options = null)
|
||||
public static void WriteToDirectory(
|
||||
this IArchive archive,
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options = null
|
||||
)
|
||||
{
|
||||
foreach (IArchiveEntry entry in archive.Entries.Where(x => !x.IsDirectory))
|
||||
{
|
||||
@@ -17,4 +20,4 @@ namespace SharpCompress.Archives
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,4 +8,4 @@ namespace SharpCompress.Archives
|
||||
void FireEntryExtractionBegin(IArchiveEntry entry);
|
||||
void FireEntryExtractionEnd(IArchiveEntry entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@ namespace SharpCompress.Archives
|
||||
/// <list type="table">
|
||||
/// <item><see cref="Factories.TarFactory"/></item>
|
||||
/// <item><see cref="Factories.RarFactory"/></item>
|
||||
/// <item><see cref="Factories.ZipFactory"/></item>
|
||||
/// <item><see cref="Factories.GZipFactory"/></item>
|
||||
/// <item><see cref="Factories.ZipFactory"/></item>
|
||||
/// <item><see cref="Factories.GZipFactory"/></item>
|
||||
/// <item><see cref="Factories.SevenZipFactory"/></item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
|
||||
@@ -16,8 +16,8 @@ namespace SharpCompress.Archives
|
||||
/// <list type="table">
|
||||
/// <item><see cref="Factories.TarFactory"/></item>
|
||||
/// <item><see cref="Factories.RarFactory"/></item>
|
||||
/// <item><see cref="Factories.ZipFactory"/></item>
|
||||
/// <item><see cref="Factories.GZipFactory"/></item>
|
||||
/// <item><see cref="Factories.ZipFactory"/></item>
|
||||
/// <item><see cref="Factories.GZipFactory"/></item>
|
||||
/// <item><see cref="Factories.SevenZipFactory"/></item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
@@ -35,6 +35,9 @@ namespace SharpCompress.Archives
|
||||
/// </summary>
|
||||
/// <param name="fileInfos"></param>
|
||||
/// <param name="readerOptions">reading options.</param>
|
||||
IArchive Open(IReadOnlyList<System.IO.FileInfo> fileInfos, ReaderOptions? readerOptions = null);
|
||||
IArchive Open(
|
||||
IReadOnlyList<System.IO.FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,13 @@ namespace SharpCompress.Archives
|
||||
{
|
||||
void RemoveEntry(IArchiveEntry entry);
|
||||
|
||||
IArchiveEntry AddEntry(string key, Stream source, bool closeStream, long size = 0, DateTime? modified = null);
|
||||
IArchiveEntry AddEntry(
|
||||
string key,
|
||||
Stream source,
|
||||
bool closeStream,
|
||||
long size = 0,
|
||||
DateTime? modified = null
|
||||
);
|
||||
|
||||
void SaveTo(Stream stream, WriterOptions options);
|
||||
|
||||
@@ -18,4 +24,4 @@ namespace SharpCompress.Archives
|
||||
/// <returns>IDisposeable to resume entry rebuilding</returns>
|
||||
IDisposable PauseEntryRebuilding();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,4 +6,4 @@ namespace SharpCompress.Archives
|
||||
{
|
||||
Stream Stream { get; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,24 +6,40 @@ namespace SharpCompress.Archives
|
||||
{
|
||||
public static class IWritableArchiveExtensions
|
||||
{
|
||||
public static void AddEntry(this IWritableArchive writableArchive,
|
||||
string entryPath, string filePath)
|
||||
public static void AddEntry(
|
||||
this IWritableArchive writableArchive,
|
||||
string entryPath,
|
||||
string filePath
|
||||
)
|
||||
{
|
||||
var fileInfo = new FileInfo(filePath);
|
||||
if (!fileInfo.Exists)
|
||||
{
|
||||
throw new FileNotFoundException("Could not AddEntry: " + filePath);
|
||||
}
|
||||
writableArchive.AddEntry(entryPath, new FileInfo(filePath).OpenRead(), true, fileInfo.Length,
|
||||
fileInfo.LastWriteTime);
|
||||
writableArchive.AddEntry(
|
||||
entryPath,
|
||||
new FileInfo(filePath).OpenRead(),
|
||||
true,
|
||||
fileInfo.Length,
|
||||
fileInfo.LastWriteTime
|
||||
);
|
||||
}
|
||||
|
||||
public static void SaveTo(this IWritableArchive writableArchive, string filePath, WriterOptions options)
|
||||
public static void SaveTo(
|
||||
this IWritableArchive writableArchive,
|
||||
string filePath,
|
||||
WriterOptions options
|
||||
)
|
||||
{
|
||||
writableArchive.SaveTo(new FileInfo(filePath), options);
|
||||
}
|
||||
|
||||
public static void SaveTo(this IWritableArchive writableArchive, FileInfo fileInfo, WriterOptions options)
|
||||
public static void SaveTo(
|
||||
this IWritableArchive writableArchive,
|
||||
FileInfo fileInfo,
|
||||
WriterOptions options
|
||||
)
|
||||
{
|
||||
using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
@@ -33,25 +49,46 @@ namespace SharpCompress.Archives
|
||||
|
||||
public static void AddAllFromDirectory(
|
||||
this IWritableArchive writableArchive,
|
||||
string filePath, string searchPattern = "*.*", SearchOption searchOption = SearchOption.AllDirectories)
|
||||
string filePath,
|
||||
string searchPattern = "*.*",
|
||||
SearchOption searchOption = SearchOption.AllDirectories
|
||||
)
|
||||
{
|
||||
using (writableArchive.PauseEntryRebuilding())
|
||||
{
|
||||
foreach (var path in Directory.EnumerateFiles(filePath, searchPattern, searchOption))
|
||||
foreach (
|
||||
var path in Directory.EnumerateFiles(filePath, searchPattern, searchOption)
|
||||
)
|
||||
{
|
||||
var fileInfo = new FileInfo(path);
|
||||
writableArchive.AddEntry(path.Substring(filePath.Length), fileInfo.OpenRead(), true, fileInfo.Length,
|
||||
fileInfo.LastWriteTime);
|
||||
writableArchive.AddEntry(
|
||||
path.Substring(filePath.Length),
|
||||
fileInfo.OpenRead(),
|
||||
true,
|
||||
fileInfo.Length,
|
||||
fileInfo.LastWriteTime
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
public static IArchiveEntry AddEntry(this IWritableArchive writableArchive, string key, FileInfo fileInfo)
|
||||
|
||||
public static IArchiveEntry AddEntry(
|
||||
this IWritableArchive writableArchive,
|
||||
string key,
|
||||
FileInfo fileInfo
|
||||
)
|
||||
{
|
||||
if (!fileInfo.Exists)
|
||||
{
|
||||
throw new ArgumentException("FileInfo does not exist.");
|
||||
}
|
||||
return writableArchive.AddEntry(key, fileInfo.OpenRead(), true, fileInfo.Length, fileInfo.LastWriteTime);
|
||||
return writableArchive.AddEntry(
|
||||
key,
|
||||
fileInfo.OpenRead(),
|
||||
true,
|
||||
fileInfo.Length,
|
||||
fileInfo.LastWriteTime
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,13 @@ namespace SharpCompress.Archives.Rar
|
||||
|
||||
internal override RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader)
|
||||
{
|
||||
return new FileInfoRarFilePart(this, ReaderOptions.Password, markHeader, fileHeader, FileInfo);
|
||||
return new FileInfoRarFilePart(
|
||||
this,
|
||||
ReaderOptions.Password,
|
||||
markHeader,
|
||||
fileHeader,
|
||||
FileInfo
|
||||
);
|
||||
}
|
||||
|
||||
internal override IEnumerable<RarFilePart> ReadFileParts()
|
||||
|
||||
@@ -5,8 +5,13 @@ namespace SharpCompress.Archives.Rar
|
||||
{
|
||||
internal sealed class FileInfoRarFilePart : SeekableFilePart
|
||||
{
|
||||
internal FileInfoRarFilePart(FileInfoRarArchiveVolume volume, string? password, MarkHeader mh, FileHeader fh, FileInfo fi)
|
||||
: base(mh, fh, volume.Index, volume.Stream, password)
|
||||
internal FileInfoRarFilePart(
|
||||
FileInfoRarArchiveVolume volume,
|
||||
string? password,
|
||||
MarkHeader mh,
|
||||
FileHeader fh,
|
||||
FileInfo fi
|
||||
) : base(mh, fh, volume.Index, volume.Stream, password)
|
||||
{
|
||||
FileInfo = fi;
|
||||
}
|
||||
@@ -15,11 +20,7 @@ namespace SharpCompress.Archives.Rar
|
||||
|
||||
internal override string FilePartName
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Rar File: " + FileInfo.FullName
|
||||
+ " File Entry: " + FileHeader.FileName;
|
||||
}
|
||||
get { return "Rar File: " + FileInfo.FullName + " File Entry: " + FileHeader.FileName; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,4 +20,4 @@ namespace SharpCompress.Archives.Rar
|
||||
return archive.Volumes.First().IsMultiVolume;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,22 +11,19 @@ using SharpCompress.Readers.Rar;
|
||||
|
||||
namespace SharpCompress.Archives.Rar
|
||||
{
|
||||
public class
|
||||
RarArchive : AbstractArchive<RarArchiveEntry, RarVolume>
|
||||
public class RarArchive : AbstractArchive<RarArchiveEntry, RarVolume>
|
||||
{
|
||||
internal Lazy<IRarUnpack> UnpackV2017 { get; } = new Lazy<IRarUnpack>(() => new SharpCompress.Compressors.Rar.UnpackV2017.Unpack());
|
||||
internal Lazy<IRarUnpack> UnpackV1 { get; } = new Lazy<IRarUnpack>(() => new SharpCompress.Compressors.Rar.UnpackV1.Unpack());
|
||||
|
||||
internal Lazy<IRarUnpack> UnpackV2017 { get; } =
|
||||
new Lazy<IRarUnpack>(() => new SharpCompress.Compressors.Rar.UnpackV2017.Unpack());
|
||||
internal Lazy<IRarUnpack> UnpackV1 { get; } =
|
||||
new Lazy<IRarUnpack>(() => new SharpCompress.Compressors.Rar.UnpackV1.Unpack());
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with a SourceStream able to handle FileInfo and Streams.
|
||||
/// </summary>
|
||||
/// <param name="srcStream"></param>
|
||||
/// <param name="options"></param>
|
||||
internal RarArchive(SourceStream srcStream)
|
||||
: base(ArchiveType.Rar, srcStream)
|
||||
{
|
||||
}
|
||||
internal RarArchive(SourceStream srcStream) : base(ArchiveType.Rar, srcStream) { }
|
||||
|
||||
protected override IEnumerable<RarArchiveEntry> LoadEntries(IEnumerable<RarVolume> volumes)
|
||||
{
|
||||
@@ -44,7 +41,9 @@ namespace SharpCompress.Archives.Rar
|
||||
streams[1].Position = 0;
|
||||
base.SrcStream.Position = 0;
|
||||
|
||||
return srcStream.Streams.Select(a => new StreamRarArchiveVolume(a, ReaderOptions, idx++));
|
||||
return srcStream.Streams.Select(
|
||||
a => new StreamRarArchiveVolume(a, ReaderOptions, idx++)
|
||||
);
|
||||
}
|
||||
else //split mode or single file
|
||||
return new StreamRarArchiveVolume(base.SrcStream, ReaderOptions, idx++).AsEnumerable();
|
||||
@@ -72,7 +71,13 @@ namespace SharpCompress.Archives.Rar
|
||||
{
|
||||
filePath.CheckNotNullOrEmpty(nameof(filePath));
|
||||
FileInfo fileInfo = new FileInfo(filePath);
|
||||
return new RarArchive(new SourceStream(fileInfo, i => RarArchiveVolumeFactory.GetFilePart(i, fileInfo), options ?? new ReaderOptions()));
|
||||
return new RarArchive(
|
||||
new SourceStream(
|
||||
fileInfo,
|
||||
i => RarArchiveVolumeFactory.GetFilePart(i, fileInfo),
|
||||
options ?? new ReaderOptions()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -83,7 +88,13 @@ namespace SharpCompress.Archives.Rar
|
||||
public static RarArchive Open(FileInfo fileInfo, ReaderOptions? options = null)
|
||||
{
|
||||
fileInfo.CheckNotNull(nameof(fileInfo));
|
||||
return new RarArchive(new SourceStream(fileInfo, i => RarArchiveVolumeFactory.GetFilePart(i, fileInfo), options ?? new ReaderOptions()));
|
||||
return new RarArchive(
|
||||
new SourceStream(
|
||||
fileInfo,
|
||||
i => RarArchiveVolumeFactory.GetFilePart(i, fileInfo),
|
||||
options ?? new ReaderOptions()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -94,7 +105,9 @@ namespace SharpCompress.Archives.Rar
|
||||
public static RarArchive Open(Stream stream, ReaderOptions? options = null)
|
||||
{
|
||||
stream.CheckNotNull(nameof(stream));
|
||||
return new RarArchive(new SourceStream(stream, i => null, options ?? new ReaderOptions()));
|
||||
return new RarArchive(
|
||||
new SourceStream(stream, i => null, options ?? new ReaderOptions())
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -102,11 +115,20 @@ namespace SharpCompress.Archives.Rar
|
||||
/// </summary>
|
||||
/// <param name="fileInfos"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
public static RarArchive Open(IEnumerable<FileInfo> fileInfos, ReaderOptions? readerOptions = null)
|
||||
public static RarArchive Open(
|
||||
IEnumerable<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
fileInfos.CheckNotNull(nameof(fileInfos));
|
||||
FileInfo[] files = fileInfos.ToArray();
|
||||
return new RarArchive(new SourceStream(files[0], i => i < files.Length ? files[i] : null, readerOptions ?? new ReaderOptions()));
|
||||
return new RarArchive(
|
||||
new SourceStream(
|
||||
files[0],
|
||||
i => i < files.Length ? files[i] : null,
|
||||
readerOptions ?? new ReaderOptions()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -114,14 +136,22 @@ namespace SharpCompress.Archives.Rar
|
||||
/// </summary>
|
||||
/// <param name="streams"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
public static RarArchive Open(IEnumerable<Stream> streams, ReaderOptions? readerOptions = null)
|
||||
public static RarArchive Open(
|
||||
IEnumerable<Stream> streams,
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
streams.CheckNotNull(nameof(streams));
|
||||
Stream[] strms = streams.ToArray();
|
||||
return new RarArchive(new SourceStream(strms[0], i => i < strms.Length ? strms[i] : null, readerOptions ?? new ReaderOptions()));
|
||||
return new RarArchive(
|
||||
new SourceStream(
|
||||
strms[0],
|
||||
i => i < strms.Length ? strms[i] : null,
|
||||
readerOptions ?? new ReaderOptions()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public static bool IsRarFile(string filePath)
|
||||
{
|
||||
return IsRarFile(new FileInfo(filePath));
|
||||
|
||||
@@ -16,7 +16,11 @@ namespace SharpCompress.Archives.Rar
|
||||
private readonly RarArchive archive;
|
||||
private readonly ReaderOptions readerOptions;
|
||||
|
||||
internal RarArchiveEntry(RarArchive archive, IEnumerable<RarFilePart> parts, ReaderOptions readerOptions)
|
||||
internal RarArchiveEntry(
|
||||
RarArchive archive,
|
||||
IEnumerable<RarFilePart> parts,
|
||||
ReaderOptions readerOptions
|
||||
)
|
||||
{
|
||||
this.parts = parts.ToList();
|
||||
this.archive = archive;
|
||||
@@ -63,10 +67,18 @@ namespace SharpCompress.Archives.Rar
|
||||
{
|
||||
if (IsRarV3)
|
||||
{
|
||||
return new RarStream(archive.UnpackV1.Value, FileHeader, new MultiVolumeReadOnlyStream(Parts.Cast<RarFilePart>(), archive));
|
||||
return new RarStream(
|
||||
archive.UnpackV1.Value,
|
||||
FileHeader,
|
||||
new MultiVolumeReadOnlyStream(Parts.Cast<RarFilePart>(), archive)
|
||||
);
|
||||
}
|
||||
|
||||
return new RarStream(archive.UnpackV2017.Value, FileHeader, new MultiVolumeReadOnlyStream(Parts.Cast<RarFilePart>(), archive));
|
||||
return new RarStream(
|
||||
archive.UnpackV2017.Value,
|
||||
FileHeader,
|
||||
new MultiVolumeReadOnlyStream(Parts.Cast<RarFilePart>(), archive)
|
||||
);
|
||||
}
|
||||
|
||||
public bool IsComplete
|
||||
@@ -82,7 +94,9 @@ namespace SharpCompress.Archives.Rar
|
||||
{
|
||||
if (!readerOptions.DisableCheckIncomplete && !IsComplete)
|
||||
{
|
||||
throw new IncompleteArchiveException("ArchiveEntry is incomplete and cannot perform this operation.");
|
||||
throw new IncompleteArchiveException(
|
||||
"ArchiveEntry is incomplete and cannot perform this operation."
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,9 @@ namespace SharpCompress.Archives.Rar
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<IEnumerable<RarFilePart>> GetMatchedFileParts(IEnumerable<RarVolume> parts)
|
||||
private static IEnumerable<IEnumerable<RarFilePart>> GetMatchedFileParts(
|
||||
IEnumerable<RarVolume> parts
|
||||
)
|
||||
{
|
||||
var groupedParts = new List<RarFilePart>();
|
||||
foreach (RarFilePart fp in GetFileParts(parts))
|
||||
@@ -36,9 +38,11 @@ namespace SharpCompress.Archives.Rar
|
||||
}
|
||||
}
|
||||
|
||||
internal static IEnumerable<RarArchiveEntry> GetEntries(RarArchive archive,
|
||||
IEnumerable<RarVolume> rarParts,
|
||||
ReaderOptions readerOptions)
|
||||
internal static IEnumerable<RarArchiveEntry> GetEntries(
|
||||
RarArchive archive,
|
||||
IEnumerable<RarVolume> rarParts,
|
||||
ReaderOptions readerOptions
|
||||
)
|
||||
{
|
||||
foreach (var groupedParts in GetMatchedFileParts(rarParts))
|
||||
{
|
||||
@@ -46,4 +50,4 @@ namespace SharpCompress.Archives.Rar
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,15 +17,38 @@ namespace SharpCompress.Archives.Rar
|
||||
FileInfo? item = null;
|
||||
|
||||
//new style rar - ..part1 | /part01 | part001 ....
|
||||
Match m = Regex.Match(part1.Name, @"^(.*\.part)([0-9]+)(\.rar)$", RegexOptions.IgnoreCase);
|
||||
Match m = Regex.Match(
|
||||
part1.Name,
|
||||
@"^(.*\.part)([0-9]+)(\.rar)$",
|
||||
RegexOptions.IgnoreCase
|
||||
);
|
||||
if (m.Success)
|
||||
item = new FileInfo(Path.Combine(part1.DirectoryName!, String.Concat(m.Groups[1].Value, (index + 1).ToString().PadLeft(m.Groups[2].Value.Length, '0'), m.Groups[3].Value)));
|
||||
item = new FileInfo(
|
||||
Path.Combine(
|
||||
part1.DirectoryName!,
|
||||
String.Concat(
|
||||
m.Groups[1].Value,
|
||||
(index + 1).ToString().PadLeft(m.Groups[2].Value.Length, '0'),
|
||||
m.Groups[3].Value
|
||||
)
|
||||
)
|
||||
);
|
||||
else
|
||||
{
|
||||
//old style - ...rar, .r00, .r01 ...
|
||||
m = Regex.Match(part1.Name, @"^(.*\.r)(ar|[0-9]+)$", RegexOptions.IgnoreCase);
|
||||
if (m.Success)
|
||||
item = new FileInfo(Path.Combine(part1.DirectoryName!, String.Concat(m.Groups[1].Value, index == 0 ? "ar" : (index - 1).ToString().PadLeft(m.Groups[2].Value.Length, '0'))));
|
||||
item = new FileInfo(
|
||||
Path.Combine(
|
||||
part1.DirectoryName!,
|
||||
String.Concat(
|
||||
m.Groups[1].Value,
|
||||
index == 0
|
||||
? "ar"
|
||||
: (index - 1).ToString().PadLeft(m.Groups[2].Value.Length, '0')
|
||||
)
|
||||
)
|
||||
);
|
||||
else //split .001, .002 ....
|
||||
return ArchiveVolumeFactory.GetFilePart(index, part1);
|
||||
}
|
||||
@@ -35,6 +58,5 @@ namespace SharpCompress.Archives.Rar
|
||||
|
||||
return null; //no more items
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,13 @@ namespace SharpCompress.Archives.Rar
|
||||
private readonly Stream stream;
|
||||
private readonly string? password;
|
||||
|
||||
internal SeekableFilePart(MarkHeader mh, FileHeader fh, int index, Stream stream, string? password)
|
||||
: base(mh, fh, index)
|
||||
internal SeekableFilePart(
|
||||
MarkHeader mh,
|
||||
FileHeader fh,
|
||||
int index,
|
||||
Stream stream,
|
||||
string? password
|
||||
) : base(mh, fh, index)
|
||||
{
|
||||
this.stream = stream;
|
||||
this.password = password;
|
||||
@@ -26,6 +31,7 @@ namespace SharpCompress.Archives.Rar
|
||||
return stream;
|
||||
}
|
||||
|
||||
internal override string FilePartName => "Unknown Stream - File Entry: " + FileHeader.FileName;
|
||||
internal override string FilePartName =>
|
||||
"Unknown Stream - File Entry: " + FileHeader.FileName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,9 +10,7 @@ namespace SharpCompress.Archives.Rar
|
||||
internal class StreamRarArchiveVolume : RarVolume
|
||||
{
|
||||
internal StreamRarArchiveVolume(Stream stream, ReaderOptions options, int index = 0)
|
||||
: base(StreamingMode.Seekable, stream, options, index)
|
||||
{
|
||||
}
|
||||
: base(StreamingMode.Seekable, stream, options, index) { }
|
||||
|
||||
internal override IEnumerable<RarFilePart> ReadFileParts()
|
||||
{
|
||||
@@ -21,7 +19,13 @@ namespace SharpCompress.Archives.Rar
|
||||
|
||||
internal override RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader)
|
||||
{
|
||||
return new SeekableFilePart(markHeader, fileHeader, this.Index, Stream, ReaderOptions.Password);
|
||||
return new SeekableFilePart(
|
||||
markHeader,
|
||||
fileHeader,
|
||||
this.Index,
|
||||
Stream,
|
||||
ReaderOptions.Password
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace SharpCompress.Archives.SevenZip
|
||||
public class SevenZipArchive : AbstractArchive<SevenZipArchiveEntry, SevenZipVolume>
|
||||
{
|
||||
private ArchiveDatabase database;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor expects a filepath to an existing file.
|
||||
/// </summary>
|
||||
@@ -34,7 +35,13 @@ namespace SharpCompress.Archives.SevenZip
|
||||
public static SevenZipArchive Open(FileInfo fileInfo, ReaderOptions readerOptions = null)
|
||||
{
|
||||
fileInfo.CheckNotNull("fileInfo");
|
||||
return new SevenZipArchive(new SourceStream(fileInfo, i => ArchiveVolumeFactory.GetFilePart(i, fileInfo), readerOptions ?? new ReaderOptions()));
|
||||
return new SevenZipArchive(
|
||||
new SourceStream(
|
||||
fileInfo,
|
||||
i => ArchiveVolumeFactory.GetFilePart(i, fileInfo),
|
||||
readerOptions ?? new ReaderOptions()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -42,11 +49,20 @@ namespace SharpCompress.Archives.SevenZip
|
||||
/// </summary>
|
||||
/// <param name="fileInfos"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
public static SevenZipArchive Open(IEnumerable<FileInfo> fileInfos, ReaderOptions readerOptions = null)
|
||||
public static SevenZipArchive Open(
|
||||
IEnumerable<FileInfo> fileInfos,
|
||||
ReaderOptions readerOptions = null
|
||||
)
|
||||
{
|
||||
fileInfos.CheckNotNull(nameof(fileInfos));
|
||||
FileInfo[] files = fileInfos.ToArray();
|
||||
return new SevenZipArchive(new SourceStream(files[0], i => i < files.Length ? files[i] : null, readerOptions ?? new ReaderOptions()));
|
||||
return new SevenZipArchive(
|
||||
new SourceStream(
|
||||
files[0],
|
||||
i => i < files.Length ? files[i] : null,
|
||||
readerOptions ?? new ReaderOptions()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -54,11 +70,20 @@ namespace SharpCompress.Archives.SevenZip
|
||||
/// </summary>
|
||||
/// <param name="streams"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
public static SevenZipArchive Open(IEnumerable<Stream> streams, ReaderOptions readerOptions = null)
|
||||
public static SevenZipArchive Open(
|
||||
IEnumerable<Stream> streams,
|
||||
ReaderOptions readerOptions = null
|
||||
)
|
||||
{
|
||||
streams.CheckNotNull(nameof(streams));
|
||||
Stream[] strms = streams.ToArray();
|
||||
return new SevenZipArchive(new SourceStream(strms[0], i => i < strms.Length ? strms[i] : null, readerOptions ?? new ReaderOptions()));
|
||||
return new SevenZipArchive(
|
||||
new SourceStream(
|
||||
strms[0],
|
||||
i => i < strms.Length ? strms[i] : null,
|
||||
readerOptions ?? new ReaderOptions()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -69,7 +94,9 @@ namespace SharpCompress.Archives.SevenZip
|
||||
public static SevenZipArchive Open(Stream stream, ReaderOptions readerOptions = null)
|
||||
{
|
||||
stream.CheckNotNull("stream");
|
||||
return new SevenZipArchive(new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions()));
|
||||
return new SevenZipArchive(
|
||||
new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions())
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -77,10 +104,7 @@ namespace SharpCompress.Archives.SevenZip
|
||||
/// </summary>
|
||||
/// <param name="srcStream"></param>
|
||||
/// <param name="options"></param>
|
||||
internal SevenZipArchive(SourceStream srcStream)
|
||||
: base(ArchiveType.SevenZip, srcStream)
|
||||
{
|
||||
}
|
||||
internal SevenZipArchive(SourceStream srcStream) : base(ArchiveType.SevenZip, srcStream) { }
|
||||
|
||||
protected override IEnumerable<SevenZipVolume> LoadVolumes(SourceStream srcStream)
|
||||
{
|
||||
@@ -106,12 +130,11 @@ namespace SharpCompress.Archives.SevenZip
|
||||
}
|
||||
}
|
||||
|
||||
internal SevenZipArchive()
|
||||
: base(ArchiveType.SevenZip)
|
||||
{
|
||||
}
|
||||
internal SevenZipArchive() : base(ArchiveType.SevenZip) { }
|
||||
|
||||
protected override IEnumerable<SevenZipArchiveEntry> LoadEntries(IEnumerable<SevenZipVolume> volumes)
|
||||
protected override IEnumerable<SevenZipArchiveEntry> LoadEntries(
|
||||
IEnumerable<SevenZipVolume> volumes
|
||||
)
|
||||
{
|
||||
var stream = volumes.Single().Stream;
|
||||
LoadFactory(stream);
|
||||
@@ -119,9 +142,14 @@ namespace SharpCompress.Archives.SevenZip
|
||||
for (int i = 0; i < database._files.Count; i++)
|
||||
{
|
||||
var file = database._files[i];
|
||||
entries[i] = new SevenZipArchiveEntry(this, new SevenZipFilePart(stream, database, i, file, ReaderOptions.ArchiveEncoding));
|
||||
entries[i] = new SevenZipArchiveEntry(
|
||||
this,
|
||||
new SevenZipFilePart(stream, database, i, file, ReaderOptions.ArchiveEncoding)
|
||||
);
|
||||
}
|
||||
foreach (var group in entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder))
|
||||
foreach (
|
||||
var group in entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder)
|
||||
)
|
||||
{
|
||||
var isSolid = false;
|
||||
foreach (var entry in group)
|
||||
@@ -157,7 +185,8 @@ namespace SharpCompress.Archives.SevenZip
|
||||
}
|
||||
}
|
||||
|
||||
private static ReadOnlySpan<byte> SIGNATURE => new byte[] { (byte)'7', (byte)'z', 0xBC, 0xAF, 0x27, 0x1C };
|
||||
private static ReadOnlySpan<byte> SIGNATURE =>
|
||||
new byte[] { (byte)'7', (byte)'z', 0xBC, 0xAF, 0x27, 0x1C };
|
||||
|
||||
private static bool SignatureMatch(Stream stream)
|
||||
{
|
||||
@@ -171,7 +200,14 @@ namespace SharpCompress.Archives.SevenZip
|
||||
return new SevenZipReader(ReaderOptions, this);
|
||||
}
|
||||
|
||||
public override bool IsSolid { get { return Entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder).Count() > 1; } }
|
||||
public override bool IsSolid
|
||||
{
|
||||
get
|
||||
{
|
||||
return Entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder).Count()
|
||||
> 1;
|
||||
}
|
||||
}
|
||||
|
||||
public override long TotalSize
|
||||
{
|
||||
@@ -205,7 +241,9 @@ namespace SharpCompress.Archives.SevenZip
|
||||
{
|
||||
yield return dir;
|
||||
}
|
||||
foreach (var group in entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder))
|
||||
foreach (
|
||||
var group in entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder)
|
||||
)
|
||||
{
|
||||
currentFolder = group.Key;
|
||||
if (group.Key is null)
|
||||
@@ -214,7 +252,11 @@ namespace SharpCompress.Archives.SevenZip
|
||||
}
|
||||
else
|
||||
{
|
||||
currentStream = archive.database.GetFolderStream(stream, currentFolder, new PasswordProvider(Options.Password));
|
||||
currentStream = archive.database.GetFolderStream(
|
||||
stream,
|
||||
currentFolder,
|
||||
new PasswordProvider(Options.Password)
|
||||
);
|
||||
}
|
||||
foreach (var entry in group)
|
||||
{
|
||||
|
||||
@@ -5,8 +5,7 @@ namespace SharpCompress.Archives.SevenZip
|
||||
{
|
||||
public class SevenZipArchiveEntry : SevenZipEntry, IArchiveEntry
|
||||
{
|
||||
internal SevenZipArchiveEntry(SevenZipArchive archive, SevenZipFilePart part)
|
||||
: base(part)
|
||||
internal SevenZipArchiveEntry(SevenZipArchive archive, SevenZipFilePart part) : base(part)
|
||||
{
|
||||
Archive = archive;
|
||||
}
|
||||
@@ -25,4 +24,4 @@ namespace SharpCompress.Archives.SevenZip
|
||||
/// </summary>
|
||||
public bool IsAnti => FilePart.Header.IsAnti;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,13 @@ namespace SharpCompress.Archives.Tar
|
||||
public static TarArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
fileInfo.CheckNotNull(nameof(fileInfo));
|
||||
return new TarArchive(new SourceStream(fileInfo, i => ArchiveVolumeFactory.GetFilePart(i, fileInfo), readerOptions ?? new ReaderOptions()));
|
||||
return new TarArchive(
|
||||
new SourceStream(
|
||||
fileInfo,
|
||||
i => ArchiveVolumeFactory.GetFilePart(i, fileInfo),
|
||||
readerOptions ?? new ReaderOptions()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -42,11 +48,20 @@ namespace SharpCompress.Archives.Tar
|
||||
/// </summary>
|
||||
/// <param name="fileInfos"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
public static TarArchive Open(IEnumerable<FileInfo> fileInfos, ReaderOptions? readerOptions = null)
|
||||
public static TarArchive Open(
|
||||
IEnumerable<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
fileInfos.CheckNotNull(nameof(fileInfos));
|
||||
FileInfo[] files = fileInfos.ToArray();
|
||||
return new TarArchive(new SourceStream(files[0], i => i < files.Length ? files[i] : null, readerOptions ?? new ReaderOptions()));
|
||||
return new TarArchive(
|
||||
new SourceStream(
|
||||
files[0],
|
||||
i => i < files.Length ? files[i] : null,
|
||||
readerOptions ?? new ReaderOptions()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -54,11 +69,20 @@ namespace SharpCompress.Archives.Tar
|
||||
/// </summary>
|
||||
/// <param name="streams"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
public static TarArchive Open(IEnumerable<Stream> streams, ReaderOptions? readerOptions = null)
|
||||
public static TarArchive Open(
|
||||
IEnumerable<Stream> streams,
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
streams.CheckNotNull(nameof(streams));
|
||||
Stream[] strms = streams.ToArray();
|
||||
return new TarArchive(new SourceStream(strms[0], i => i < strms.Length ? strms[i] : null, readerOptions ?? new ReaderOptions()));
|
||||
return new TarArchive(
|
||||
new SourceStream(
|
||||
strms[0],
|
||||
i => i < strms.Length ? strms[i] : null,
|
||||
readerOptions ?? new ReaderOptions()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -69,7 +93,9 @@ namespace SharpCompress.Archives.Tar
|
||||
public static TarArchive Open(Stream stream, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
stream.CheckNotNull(nameof(stream));
|
||||
return new TarArchive(new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions()));
|
||||
return new TarArchive(
|
||||
new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions())
|
||||
);
|
||||
}
|
||||
|
||||
public static bool IsTarFile(string filePath)
|
||||
@@ -95,12 +121,13 @@ namespace SharpCompress.Archives.Tar
|
||||
{
|
||||
TarHeader tarHeader = new TarHeader(new ArchiveEncoding());
|
||||
bool readSucceeded = tarHeader.Read(new BinaryReader(stream));
|
||||
bool isEmptyArchive = tarHeader.Name.Length == 0 && tarHeader.Size == 0 && Enum.IsDefined(typeof(EntryType), tarHeader.EntryType);
|
||||
bool isEmptyArchive =
|
||||
tarHeader.Name.Length == 0
|
||||
&& tarHeader.Size == 0
|
||||
&& Enum.IsDefined(typeof(EntryType), tarHeader.EntryType);
|
||||
return readSucceeded || isEmptyArchive;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
catch { }
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -116,21 +143,21 @@ namespace SharpCompress.Archives.Tar
|
||||
/// </summary>
|
||||
/// <param name="srcStream"></param>
|
||||
/// <param name="options"></param>
|
||||
internal TarArchive(SourceStream srcStream)
|
||||
: base(ArchiveType.Tar, srcStream)
|
||||
{
|
||||
}
|
||||
internal TarArchive(SourceStream srcStream) : base(ArchiveType.Tar, srcStream) { }
|
||||
|
||||
internal TarArchive()
|
||||
: base(ArchiveType.Tar)
|
||||
{
|
||||
}
|
||||
internal TarArchive() : base(ArchiveType.Tar) { }
|
||||
|
||||
protected override IEnumerable<TarArchiveEntry> LoadEntries(IEnumerable<TarVolume> volumes)
|
||||
{
|
||||
Stream stream = volumes.Single().Stream;
|
||||
TarHeader? previousHeader = null;
|
||||
foreach (TarHeader? header in TarHeaderFactory.ReadHeader(StreamingMode.Seekable, stream, ReaderOptions.ArchiveEncoding))
|
||||
foreach (
|
||||
TarHeader? header in TarHeaderFactory.ReadHeader(
|
||||
StreamingMode.Seekable,
|
||||
stream,
|
||||
ReaderOptions.ArchiveEncoding
|
||||
)
|
||||
)
|
||||
{
|
||||
if (header != null)
|
||||
{
|
||||
@@ -142,8 +169,11 @@ namespace SharpCompress.Archives.Tar
|
||||
{
|
||||
if (previousHeader != null)
|
||||
{
|
||||
var entry = new TarArchiveEntry(this, new TarFilePart(previousHeader, stream),
|
||||
CompressionType.None);
|
||||
var entry = new TarArchiveEntry(
|
||||
this,
|
||||
new TarFilePart(previousHeader, stream),
|
||||
CompressionType.None
|
||||
);
|
||||
|
||||
var oldStreamPos = stream.Position;
|
||||
|
||||
@@ -155,7 +185,9 @@ namespace SharpCompress.Archives.Tar
|
||||
memoryStream.Position = 0;
|
||||
var bytes = memoryStream.ToArray();
|
||||
|
||||
header.Name = ReaderOptions.ArchiveEncoding.Decode(bytes).TrimNulls();
|
||||
header.Name = ReaderOptions.ArchiveEncoding
|
||||
.Decode(bytes)
|
||||
.TrimNulls();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,7 +195,11 @@ namespace SharpCompress.Archives.Tar
|
||||
|
||||
previousHeader = null;
|
||||
}
|
||||
yield return new TarArchiveEntry(this, new TarFilePart(header, stream), CompressionType.None);
|
||||
yield return new TarArchiveEntry(
|
||||
this,
|
||||
new TarFilePart(header, stream),
|
||||
CompressionType.None
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,21 +210,35 @@ namespace SharpCompress.Archives.Tar
|
||||
return new TarArchive();
|
||||
}
|
||||
|
||||
protected override TarArchiveEntry CreateEntryInternal(string filePath, Stream source,
|
||||
long size, DateTime? modified, bool closeStream)
|
||||
protected override TarArchiveEntry CreateEntryInternal(
|
||||
string filePath,
|
||||
Stream source,
|
||||
long size,
|
||||
DateTime? modified,
|
||||
bool closeStream
|
||||
)
|
||||
{
|
||||
return new TarWritableArchiveEntry(this, source, CompressionType.Unknown, filePath, size, modified,
|
||||
closeStream);
|
||||
return new TarWritableArchiveEntry(
|
||||
this,
|
||||
source,
|
||||
CompressionType.Unknown,
|
||||
filePath,
|
||||
size,
|
||||
modified,
|
||||
closeStream
|
||||
);
|
||||
}
|
||||
|
||||
protected override void SaveTo(Stream stream, WriterOptions options,
|
||||
IEnumerable<TarArchiveEntry> oldEntries,
|
||||
IEnumerable<TarArchiveEntry> newEntries)
|
||||
protected override void SaveTo(
|
||||
Stream stream,
|
||||
WriterOptions options,
|
||||
IEnumerable<TarArchiveEntry> oldEntries,
|
||||
IEnumerable<TarArchiveEntry> newEntries
|
||||
)
|
||||
{
|
||||
using (var writer = new TarWriter(stream, new TarWriterOptions(options)))
|
||||
{
|
||||
foreach (var entry in oldEntries.Concat(newEntries)
|
||||
.Where(x => !x.IsDirectory))
|
||||
foreach (var entry in oldEntries.Concat(newEntries).Where(x => !x.IsDirectory))
|
||||
{
|
||||
using (var entryStream = entry.OpenEntryStream())
|
||||
{
|
||||
|
||||
@@ -7,8 +7,11 @@ namespace SharpCompress.Archives.Tar
|
||||
{
|
||||
public class TarArchiveEntry : TarEntry, IArchiveEntry
|
||||
{
|
||||
internal TarArchiveEntry(TarArchive archive, TarFilePart part, CompressionType compressionType)
|
||||
: base(part, compressionType)
|
||||
internal TarArchiveEntry(
|
||||
TarArchive archive,
|
||||
TarFilePart part,
|
||||
CompressionType compressionType
|
||||
) : base(part, compressionType)
|
||||
{
|
||||
Archive = archive;
|
||||
}
|
||||
@@ -26,4 +29,4 @@ namespace SharpCompress.Archives.Tar
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,15 @@ namespace SharpCompress.Archives.Tar
|
||||
private readonly bool closeStream;
|
||||
private readonly Stream stream;
|
||||
|
||||
internal TarWritableArchiveEntry(TarArchive archive, Stream stream, CompressionType compressionType,
|
||||
string path, long size, DateTime? lastModified, bool closeStream)
|
||||
: base(archive, null, compressionType)
|
||||
internal TarWritableArchiveEntry(
|
||||
TarArchive archive,
|
||||
Stream stream,
|
||||
CompressionType compressionType,
|
||||
string path,
|
||||
long size,
|
||||
DateTime? lastModified,
|
||||
bool closeStream
|
||||
) : base(archive, null, compressionType)
|
||||
{
|
||||
this.stream = stream;
|
||||
Key = path;
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace SharpCompress.Archives.Zip
|
||||
{
|
||||
#nullable disable
|
||||
private readonly SeekableZipHeaderFactory headerFactory;
|
||||
|
||||
#nullable enable
|
||||
|
||||
/// <summary>
|
||||
@@ -31,10 +32,12 @@ namespace SharpCompress.Archives.Zip
|
||||
/// </summary>
|
||||
/// <param name="srcStream"></param>
|
||||
/// <param name="options"></param>
|
||||
internal ZipArchive(SourceStream srcStream)
|
||||
: base(ArchiveType.Zip, srcStream)
|
||||
internal ZipArchive(SourceStream srcStream) : base(ArchiveType.Zip, srcStream)
|
||||
{
|
||||
headerFactory = new SeekableZipHeaderFactory(srcStream.ReaderOptions.Password, srcStream.ReaderOptions.ArchiveEncoding);
|
||||
headerFactory = new SeekableZipHeaderFactory(
|
||||
srcStream.ReaderOptions.Password,
|
||||
srcStream.ReaderOptions.ArchiveEncoding
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -56,7 +59,13 @@ namespace SharpCompress.Archives.Zip
|
||||
public static ZipArchive Open(FileInfo fileInfo, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
fileInfo.CheckNotNull(nameof(fileInfo));
|
||||
return new ZipArchive(new SourceStream(fileInfo, i => ZipArchiveVolumeFactory.GetFilePart(i, fileInfo), readerOptions ?? new ReaderOptions()));
|
||||
return new ZipArchive(
|
||||
new SourceStream(
|
||||
fileInfo,
|
||||
i => ZipArchiveVolumeFactory.GetFilePart(i, fileInfo),
|
||||
readerOptions ?? new ReaderOptions()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -64,11 +73,20 @@ namespace SharpCompress.Archives.Zip
|
||||
/// </summary>
|
||||
/// <param name="fileInfos"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
public static ZipArchive Open(IEnumerable<FileInfo> fileInfos, ReaderOptions? readerOptions = null)
|
||||
public static ZipArchive Open(
|
||||
IEnumerable<FileInfo> fileInfos,
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
fileInfos.CheckNotNull(nameof(fileInfos));
|
||||
FileInfo[] files = fileInfos.ToArray();
|
||||
return new ZipArchive(new SourceStream(files[0], i => i < files.Length ? files[i] : null, readerOptions ?? new ReaderOptions()));
|
||||
return new ZipArchive(
|
||||
new SourceStream(
|
||||
files[0],
|
||||
i => i < files.Length ? files[i] : null,
|
||||
readerOptions ?? new ReaderOptions()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -76,11 +94,20 @@ namespace SharpCompress.Archives.Zip
|
||||
/// </summary>
|
||||
/// <param name="streams"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
public static ZipArchive Open(IEnumerable<Stream> streams, ReaderOptions? readerOptions = null)
|
||||
public static ZipArchive Open(
|
||||
IEnumerable<Stream> streams,
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
streams.CheckNotNull(nameof(streams));
|
||||
Stream[] strms = streams.ToArray();
|
||||
return new ZipArchive(new SourceStream(strms[0], i => i < strms.Length ? strms[i] : null, readerOptions ?? new ReaderOptions()));
|
||||
return new ZipArchive(
|
||||
new SourceStream(
|
||||
strms[0],
|
||||
i => i < strms.Length ? strms[i] : null,
|
||||
readerOptions ?? new ReaderOptions()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -91,7 +118,9 @@ namespace SharpCompress.Archives.Zip
|
||||
public static ZipArchive Open(Stream stream, ReaderOptions? readerOptions = null)
|
||||
{
|
||||
stream.CheckNotNull(nameof(stream));
|
||||
return new ZipArchive(new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions()));
|
||||
return new ZipArchive(
|
||||
new SourceStream(stream, i => null, readerOptions ?? new ReaderOptions())
|
||||
);
|
||||
}
|
||||
|
||||
public static bool IsZipFile(string filePath, string? password = null)
|
||||
@@ -113,10 +142,15 @@ namespace SharpCompress.Archives.Zip
|
||||
|
||||
public static bool IsZipFile(Stream stream, string? password = null)
|
||||
{
|
||||
StreamingZipHeaderFactory headerFactory = new StreamingZipHeaderFactory(password, new ArchiveEncoding());
|
||||
StreamingZipHeaderFactory headerFactory = new StreamingZipHeaderFactory(
|
||||
password,
|
||||
new ArchiveEncoding()
|
||||
);
|
||||
try
|
||||
{
|
||||
ZipHeader? header = headerFactory.ReadStreamHeader(stream).FirstOrDefault(x => x.ZipHeaderType != ZipHeaderType.Split);
|
||||
ZipHeader? header = headerFactory
|
||||
.ReadStreamHeader(stream)
|
||||
.FirstOrDefault(x => x.ZipHeaderType != ZipHeaderType.Split);
|
||||
if (header is null)
|
||||
{
|
||||
return false;
|
||||
@@ -135,15 +169,23 @@ namespace SharpCompress.Archives.Zip
|
||||
|
||||
public static bool IsZipMulti(Stream stream, string? password = null)
|
||||
{
|
||||
StreamingZipHeaderFactory headerFactory = new StreamingZipHeaderFactory(password, new ArchiveEncoding());
|
||||
StreamingZipHeaderFactory headerFactory = new StreamingZipHeaderFactory(
|
||||
password,
|
||||
new ArchiveEncoding()
|
||||
);
|
||||
try
|
||||
{
|
||||
ZipHeader? header = headerFactory.ReadStreamHeader(stream).FirstOrDefault(x => x.ZipHeaderType != ZipHeaderType.Split);
|
||||
ZipHeader? header = headerFactory
|
||||
.ReadStreamHeader(stream)
|
||||
.FirstOrDefault(x => x.ZipHeaderType != ZipHeaderType.Split);
|
||||
if (header is null)
|
||||
{
|
||||
if (stream.CanSeek) //could be multipart. Test for central directory - might not be z64 safe
|
||||
{
|
||||
SeekableZipHeaderFactory z = new SeekableZipHeaderFactory(password, new ArchiveEncoding());
|
||||
SeekableZipHeaderFactory z = new SeekableZipHeaderFactory(
|
||||
password,
|
||||
new ArchiveEncoding()
|
||||
);
|
||||
var x = z.ReadSeekableHeader(stream).FirstOrDefault();
|
||||
return x?.ZipHeaderType == ZipHeaderType.DirectoryEntry;
|
||||
}
|
||||
@@ -191,10 +233,7 @@ namespace SharpCompress.Archives.Zip
|
||||
return new ZipVolume(base.SrcStream, ReaderOptions, idx++).AsEnumerable();
|
||||
}
|
||||
|
||||
internal ZipArchive()
|
||||
: base(ArchiveType.Zip)
|
||||
{
|
||||
}
|
||||
internal ZipArchive() : base(ArchiveType.Zip) { }
|
||||
|
||||
protected override IEnumerable<ZipArchiveEntry> LoadEntries(IEnumerable<ZipVolume> volumes)
|
||||
{
|
||||
@@ -206,19 +245,30 @@ namespace SharpCompress.Archives.Zip
|
||||
switch (h.ZipHeaderType)
|
||||
{
|
||||
case ZipHeaderType.DirectoryEntry:
|
||||
{
|
||||
DirectoryEntryHeader deh = (DirectoryEntryHeader)h;
|
||||
Stream s;
|
||||
if (deh.RelativeOffsetOfEntryHeader + deh.CompressedSize > vols[deh.DiskNumberStart].Stream.Length)
|
||||
|
||||
{
|
||||
var v = vols.Skip(deh.DiskNumberStart).ToArray();
|
||||
s = new SourceStream(v[0].Stream, i => i < v.Length ? v[i].Stream : null, new ReaderOptions() { LeaveStreamOpen = true });
|
||||
DirectoryEntryHeader deh = (DirectoryEntryHeader)h;
|
||||
Stream s;
|
||||
if (
|
||||
deh.RelativeOffsetOfEntryHeader + deh.CompressedSize
|
||||
> vols[deh.DiskNumberStart].Stream.Length
|
||||
)
|
||||
{
|
||||
var v = vols.Skip(deh.DiskNumberStart).ToArray();
|
||||
s = new SourceStream(
|
||||
v[0].Stream,
|
||||
i => i < v.Length ? v[i].Stream : null,
|
||||
new ReaderOptions() { LeaveStreamOpen = true }
|
||||
);
|
||||
}
|
||||
else
|
||||
s = vols[deh.DiskNumberStart].Stream;
|
||||
yield return new ZipArchiveEntry(
|
||||
this,
|
||||
new SeekableZipFilePart(headerFactory, deh, s)
|
||||
);
|
||||
}
|
||||
else
|
||||
s = vols[deh.DiskNumberStart].Stream;
|
||||
yield return new ZipArchiveEntry(this, new SeekableZipFilePart(headerFactory, deh, s));
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case ZipHeaderType.DirectoryEnd:
|
||||
{
|
||||
byte[] bytes = ((DirectoryEndHeader)h).Comment ?? Array.Empty<byte>();
|
||||
@@ -235,14 +285,16 @@ namespace SharpCompress.Archives.Zip
|
||||
SaveTo(stream, new WriterOptions(CompressionType.Deflate));
|
||||
}
|
||||
|
||||
protected override void SaveTo(Stream stream, WriterOptions options,
|
||||
IEnumerable<ZipArchiveEntry> oldEntries,
|
||||
IEnumerable<ZipArchiveEntry> newEntries)
|
||||
protected override void SaveTo(
|
||||
Stream stream,
|
||||
WriterOptions options,
|
||||
IEnumerable<ZipArchiveEntry> oldEntries,
|
||||
IEnumerable<ZipArchiveEntry> newEntries
|
||||
)
|
||||
{
|
||||
using (var writer = new ZipWriter(stream, new ZipWriterOptions(options)))
|
||||
{
|
||||
foreach (var entry in oldEntries.Concat(newEntries)
|
||||
.Where(x => !x.IsDirectory))
|
||||
foreach (var entry in oldEntries.Concat(newEntries).Where(x => !x.IsDirectory))
|
||||
{
|
||||
using (var entryStream = entry.OpenEntryStream())
|
||||
{
|
||||
@@ -252,8 +304,13 @@ namespace SharpCompress.Archives.Zip
|
||||
}
|
||||
}
|
||||
|
||||
protected override ZipArchiveEntry CreateEntryInternal(string filePath, Stream source, long size, DateTime? modified,
|
||||
bool closeStream)
|
||||
protected override ZipArchiveEntry CreateEntryInternal(
|
||||
string filePath,
|
||||
Stream source,
|
||||
long size,
|
||||
DateTime? modified,
|
||||
bool closeStream
|
||||
)
|
||||
{
|
||||
return new ZipWritableArchiveEntry(this, source, filePath, size, modified, closeStream);
|
||||
}
|
||||
|
||||
@@ -6,8 +6,7 @@ namespace SharpCompress.Archives.Zip
|
||||
{
|
||||
public class ZipArchiveEntry : ZipEntry, IArchiveEntry
|
||||
{
|
||||
internal ZipArchiveEntry(ZipArchive archive, SeekableZipFilePart? part)
|
||||
: base(part)
|
||||
internal ZipArchiveEntry(ZipArchive archive, SeekableZipFilePart? part) : base(part)
|
||||
{
|
||||
Archive = archive;
|
||||
}
|
||||
@@ -27,4 +26,4 @@ namespace SharpCompress.Archives.Zip
|
||||
|
||||
public string? Comment => ((SeekableZipFilePart)Parts.Single()).Comment;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,22 @@ namespace SharpCompress.Archives.Zip
|
||||
|
||||
//load files with zip/zipx first. Swapped to end once loaded in ZipArchive
|
||||
//new style .zip, z01.. | .zipx, zx01 - if the numbers go beyond 99 then they use 100 ...1000 etc
|
||||
Match m = Regex.Match(part1.Name, @"^(.*\.)(zipx?|zx?[0-9]+)$", RegexOptions.IgnoreCase);
|
||||
Match m = Regex.Match(
|
||||
part1.Name,
|
||||
@"^(.*\.)(zipx?|zx?[0-9]+)$",
|
||||
RegexOptions.IgnoreCase
|
||||
);
|
||||
if (m.Success)
|
||||
item = new FileInfo(Path.Combine(part1.DirectoryName!, String.Concat(m.Groups[1].Value, Regex.Replace(m.Groups[2].Value, @"[^xz]", ""), index.ToString().PadLeft(2, '0'))));
|
||||
item = new FileInfo(
|
||||
Path.Combine(
|
||||
part1.DirectoryName!,
|
||||
String.Concat(
|
||||
m.Groups[1].Value,
|
||||
Regex.Replace(m.Groups[2].Value, @"[^xz]", ""),
|
||||
index.ToString().PadLeft(2, '0')
|
||||
)
|
||||
)
|
||||
);
|
||||
else //split - 001, 002 ...
|
||||
return ArchiveVolumeFactory.GetFilePart(index, part1);
|
||||
|
||||
@@ -29,6 +42,5 @@ namespace SharpCompress.Archives.Zip
|
||||
|
||||
return null; //no more items
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,9 +12,14 @@ namespace SharpCompress.Archives.Zip
|
||||
private readonly Stream stream;
|
||||
private bool isDisposed;
|
||||
|
||||
internal ZipWritableArchiveEntry(ZipArchive archive, Stream stream, string path, long size,
|
||||
DateTime? lastModified, bool closeStream)
|
||||
: base(archive, null)
|
||||
internal ZipWritableArchiveEntry(
|
||||
ZipArchive archive,
|
||||
Stream stream,
|
||||
string path,
|
||||
long size,
|
||||
DateTime? lastModified,
|
||||
bool closeStream
|
||||
) : base(archive, null)
|
||||
{
|
||||
this.stream = stream;
|
||||
Key = path;
|
||||
|
||||
@@ -26,10 +26,8 @@ namespace SharpCompress.Common
|
||||
/// <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() : this(Encoding.Default, Encoding.Default) { }
|
||||
|
||||
public ArchiveEncoding(Encoding def, Encoding password)
|
||||
{
|
||||
Default = def;
|
||||
@@ -70,7 +68,8 @@ namespace SharpCompress.Common
|
||||
|
||||
public Func<byte[], int, int, string> GetDecoder()
|
||||
{
|
||||
return CustomDecoder ?? ((bytes, index, count) => GetEncoding().GetString(bytes, index, count));
|
||||
return CustomDecoder
|
||||
?? ((bytes, index, count) => GetEncoding().GetString(bytes, index, count));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,6 @@ namespace SharpCompress.Common
|
||||
{
|
||||
public class ArchiveException : Exception
|
||||
{
|
||||
public ArchiveException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
public ArchiveException(string message) : base(message) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,4 +11,4 @@ namespace SharpCompress.Common
|
||||
|
||||
public T Item { get; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,4 +8,4 @@
|
||||
SevenZip,
|
||||
GZip
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,10 @@ namespace SharpCompress.Common
|
||||
{
|
||||
public sealed class CompressedBytesReadEventArgs : EventArgs
|
||||
{
|
||||
public CompressedBytesReadEventArgs(long compressedBytesRead, long currentFilePartCompressedBytesRead)
|
||||
public CompressedBytesReadEventArgs(
|
||||
long compressedBytesRead,
|
||||
long currentFilePartCompressedBytesRead
|
||||
)
|
||||
{
|
||||
CompressedBytesRead = compressedBytesRead;
|
||||
CurrentFilePartCompressedBytesRead = currentFilePartCompressedBytesRead;
|
||||
@@ -20,4 +23,4 @@ namespace SharpCompress.Common
|
||||
/// </summary>
|
||||
public long CurrentFilePartCompressedBytesRead { get; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,4 +16,4 @@
|
||||
Unknown,
|
||||
Deflate64
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,6 @@ namespace SharpCompress.Common
|
||||
{
|
||||
public class CryptographicException : Exception
|
||||
{
|
||||
public CryptographicException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
public CryptographicException(string message) : base(message) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,6 +73,7 @@ namespace SharpCompress.Common
|
||||
|
||||
public int VolumeIndexFirst => this.Parts?.FirstOrDefault()?.Index ?? 0;
|
||||
public int VolumeIndexLast => this.Parts?.LastOrDefault()?.Index ?? 0;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString() => Key;
|
||||
|
||||
@@ -80,9 +81,7 @@ namespace SharpCompress.Common
|
||||
|
||||
public bool IsSolid { get; set; }
|
||||
|
||||
internal virtual void Close()
|
||||
{
|
||||
}
|
||||
internal virtual void Close() { }
|
||||
|
||||
/// <summary>
|
||||
/// Entry file attribute.
|
||||
|
||||
@@ -47,13 +47,15 @@ namespace SharpCompress.Common
|
||||
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
}
|
||||
public override void Flush() { }
|
||||
|
||||
public override long Length => _stream.Length;
|
||||
|
||||
public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
|
||||
public override long Position
|
||||
{
|
||||
get => throw new NotSupportedException();
|
||||
set => throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
@@ -90,4 +92,4 @@ namespace SharpCompress.Common
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,14 +4,8 @@ namespace SharpCompress.Common
|
||||
{
|
||||
public class ExtractionException : Exception
|
||||
{
|
||||
public ExtractionException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
public ExtractionException(string message) : base(message) { }
|
||||
|
||||
public ExtractionException(string message, Exception inner)
|
||||
: base(message, inner)
|
||||
{
|
||||
}
|
||||
public ExtractionException(string message, Exception inner) : base(message, inner) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,41 +8,49 @@ namespace SharpCompress.Common
|
||||
/// <summary>
|
||||
/// Extract to specific directory, retaining filename
|
||||
/// </summary>
|
||||
public static void WriteEntryToDirectory(IEntry entry,
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options,
|
||||
Action<string, ExtractionOptions?> write)
|
||||
public static void WriteEntryToDirectory(
|
||||
IEntry entry,
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options,
|
||||
Action<string, ExtractionOptions?> write
|
||||
)
|
||||
{
|
||||
string destinationFileName;
|
||||
string fullDestinationDirectoryPath = Path.GetFullPath(destinationDirectory);
|
||||
|
||||
//check for trailing slash.
|
||||
if (fullDestinationDirectoryPath[fullDestinationDirectoryPath.Length - 1] != Path.DirectorySeparatorChar)
|
||||
if (
|
||||
fullDestinationDirectoryPath[fullDestinationDirectoryPath.Length - 1]
|
||||
!= Path.DirectorySeparatorChar
|
||||
)
|
||||
{
|
||||
fullDestinationDirectoryPath += Path.DirectorySeparatorChar;
|
||||
}
|
||||
|
||||
if (!Directory.Exists(fullDestinationDirectoryPath))
|
||||
{
|
||||
throw new ExtractionException($"Directory does not exist to extract to: {fullDestinationDirectoryPath}");
|
||||
throw new ExtractionException(
|
||||
$"Directory does not exist to extract to: {fullDestinationDirectoryPath}"
|
||||
);
|
||||
}
|
||||
|
||||
options ??= new ExtractionOptions()
|
||||
{
|
||||
Overwrite = true
|
||||
};
|
||||
options ??= new ExtractionOptions() { Overwrite = true };
|
||||
|
||||
string file = Path.GetFileName(entry.Key);
|
||||
if (options.ExtractFullPath)
|
||||
{
|
||||
string folder = Path.GetDirectoryName(entry.Key)!;
|
||||
string destdir = Path.GetFullPath(Path.Combine(fullDestinationDirectoryPath, folder));
|
||||
string destdir = Path.GetFullPath(
|
||||
Path.Combine(fullDestinationDirectoryPath, folder)
|
||||
);
|
||||
|
||||
if (!Directory.Exists(destdir))
|
||||
{
|
||||
if (!destdir.StartsWith(fullDestinationDirectoryPath, StringComparison.Ordinal))
|
||||
{
|
||||
throw new ExtractionException("Entry is trying to create a directory outside of the destination directory.");
|
||||
throw new ExtractionException(
|
||||
"Entry is trying to create a directory outside of the destination directory."
|
||||
);
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(destdir);
|
||||
@@ -52,16 +60,22 @@ namespace SharpCompress.Common
|
||||
else
|
||||
{
|
||||
destinationFileName = Path.Combine(fullDestinationDirectoryPath, file);
|
||||
|
||||
}
|
||||
|
||||
if (!entry.IsDirectory)
|
||||
{
|
||||
destinationFileName = Path.GetFullPath(destinationFileName);
|
||||
|
||||
if (!destinationFileName.StartsWith(fullDestinationDirectoryPath, StringComparison.Ordinal))
|
||||
if (
|
||||
!destinationFileName.StartsWith(
|
||||
fullDestinationDirectoryPath,
|
||||
StringComparison.Ordinal
|
||||
)
|
||||
)
|
||||
{
|
||||
throw new ExtractionException("Entry is trying to write a file outside of the destination directory.");
|
||||
throw new ExtractionException(
|
||||
"Entry is trying to write a file outside of the destination directory."
|
||||
);
|
||||
}
|
||||
write(destinationFileName, options);
|
||||
}
|
||||
@@ -71,25 +85,27 @@ namespace SharpCompress.Common
|
||||
}
|
||||
}
|
||||
|
||||
public static void WriteEntryToFile(IEntry entry, string destinationFileName,
|
||||
ExtractionOptions? options,
|
||||
Action<string, FileMode> openAndWrite)
|
||||
public static void WriteEntryToFile(
|
||||
IEntry entry,
|
||||
string destinationFileName,
|
||||
ExtractionOptions? options,
|
||||
Action<string, FileMode> openAndWrite
|
||||
)
|
||||
{
|
||||
if (entry.LinkTarget != null)
|
||||
{
|
||||
if (options?.WriteSymbolicLink is null)
|
||||
{
|
||||
throw new ExtractionException("Entry is a symbolic link but ExtractionOptions.WriteSymbolicLink delegate is null");
|
||||
throw new ExtractionException(
|
||||
"Entry is a symbolic link but ExtractionOptions.WriteSymbolicLink delegate is null"
|
||||
);
|
||||
}
|
||||
options.WriteSymbolicLink(destinationFileName, entry.LinkTarget);
|
||||
}
|
||||
else
|
||||
{
|
||||
FileMode fm = FileMode.Create;
|
||||
options ??= new ExtractionOptions()
|
||||
{
|
||||
Overwrite = true
|
||||
};
|
||||
options ??= new ExtractionOptions() { Overwrite = true };
|
||||
|
||||
if (!options.Overwrite)
|
||||
{
|
||||
@@ -101,4 +117,4 @@ namespace SharpCompress.Common
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,10 +31,11 @@ namespace SharpCompress.Common
|
||||
/// </summary>
|
||||
public delegate void SymbolicLinkWriterDelegate(string sourcePath, string targetPath);
|
||||
|
||||
public SymbolicLinkWriterDelegate WriteSymbolicLink =
|
||||
(sourcePath, targetPath) =>
|
||||
{
|
||||
Console.WriteLine($"Could not write symlink {sourcePath} -> {targetPath}, for more information please see https://github.com/dotnet/runtime/issues/24271");
|
||||
};
|
||||
public SymbolicLinkWriterDelegate WriteSymbolicLink = (sourcePath, targetPath) =>
|
||||
{
|
||||
Console.WriteLine(
|
||||
$"Could not write symlink {sourcePath} -> {targetPath}, for more information please see https://github.com/dotnet/runtime/issues/24271"
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,4 +26,4 @@ namespace SharpCompress.Common
|
||||
/// </summary>
|
||||
public long CompressedSize { get; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,35 +6,33 @@ namespace SharpCompress.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns true if the flag is set on the specified bit field.
|
||||
/// Currently only works with 32-bit bitfields.
|
||||
/// Currently only works with 32-bit bitfields.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Enumeration with Flags attribute</typeparam>
|
||||
/// <param name="bitField">Flagged variable</param>
|
||||
/// <param name="flag">Flag to test</param>
|
||||
/// <returns></returns>
|
||||
public static bool HasFlag<T>(long bitField, T flag)
|
||||
where T : struct
|
||||
public static bool HasFlag<T>(long bitField, T flag) where T : struct
|
||||
{
|
||||
return HasFlag(bitField, flag);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the flag is set on the specified bit field.
|
||||
/// Currently only works with 32-bit bitfields.
|
||||
/// Currently only works with 32-bit bitfields.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Enumeration with Flags attribute</typeparam>
|
||||
/// <param name="bitField">Flagged variable</param>
|
||||
/// <param name="flag">Flag to test</param>
|
||||
/// <returns></returns>
|
||||
public static bool HasFlag<T>(ulong bitField, T flag)
|
||||
where T : struct
|
||||
public static bool HasFlag<T>(ulong bitField, T flag) where T : struct
|
||||
{
|
||||
return HasFlag(bitField, flag);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the flag is set on the specified bit field.
|
||||
/// Currently only works with 32-bit bitfields.
|
||||
/// Currently only works with 32-bit bitfields.
|
||||
/// </summary>
|
||||
/// <param name="bitField">Flagged variable</param>
|
||||
/// <param name="flag">Flag to test</param>
|
||||
@@ -51,21 +49,20 @@ namespace SharpCompress.Common
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the flag is set on the specified bit field.
|
||||
/// Currently only works with 32-bit bitfields.
|
||||
/// Currently only works with 32-bit bitfields.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Enumeration with Flags attribute</typeparam>
|
||||
/// <param name="bitField">Flagged variable</param>
|
||||
/// <param name="flag">Flag to test</param>
|
||||
/// <returns></returns>
|
||||
public static bool HasFlag<T>(T bitField, T flag)
|
||||
where T : struct
|
||||
public static bool HasFlag<T>(T bitField, T flag) where T : struct
|
||||
{
|
||||
return HasFlag(Convert.ToInt64(bitField), Convert.ToInt64(flag));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the flag is set on the specified bit field.
|
||||
/// Currently only works with 32-bit bitfields.
|
||||
/// Currently only works with 32-bit bitfields.
|
||||
/// </summary>
|
||||
/// <param name="bitField">Flagged variable</param>
|
||||
/// <param name="flag">Flag to test</param>
|
||||
@@ -99,10 +96,9 @@ namespace SharpCompress.Common
|
||||
/// <param name="flag">Flag to change</param>
|
||||
/// <param name="on">bool</param>
|
||||
/// <returns>The flagged variable with the flag changed</returns>
|
||||
public static long SetFlag<T>(T bitField, T flag, bool on)
|
||||
where T : struct
|
||||
public static long SetFlag<T>(T bitField, T flag, bool on) where T : struct
|
||||
{
|
||||
return SetFlag(Convert.ToInt64(bitField), Convert.ToInt64(flag), on);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,4 +46,4 @@ namespace SharpCompress.Common.GZip
|
||||
yield return new GZipEntry(new GZipFilePart(stream, options.ArchiveEncoding));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,8 +129,7 @@ namespace SharpCompress.Common.GZip
|
||||
{
|
||||
list.Add(buf1[0]);
|
||||
}
|
||||
}
|
||||
while (!done);
|
||||
} while (!done);
|
||||
byte[] buffer = list.ToArray();
|
||||
return ArchiveEncoding.Decode(buffer);
|
||||
}
|
||||
|
||||
@@ -6,9 +6,7 @@ namespace SharpCompress.Common.GZip
|
||||
public class GZipVolume : Volume
|
||||
{
|
||||
public GZipVolume(Stream stream, ReaderOptions options, int index = 0)
|
||||
: base(stream, options, index)
|
||||
{
|
||||
}
|
||||
: base(stream, options, index) { }
|
||||
|
||||
public GZipVolume(FileInfo fileInfo, ReaderOptions options)
|
||||
: base(fileInfo.OpenRead(), options)
|
||||
|
||||
@@ -4,8 +4,11 @@ namespace SharpCompress.Common
|
||||
{
|
||||
internal static class EntryExtensions
|
||||
{
|
||||
internal static void PreserveExtractionOptions(this IEntry entry, string destinationFileName,
|
||||
ExtractionOptions options)
|
||||
internal static void PreserveExtractionOptions(
|
||||
this IEntry entry,
|
||||
string destinationFileName,
|
||||
ExtractionOptions options
|
||||
)
|
||||
{
|
||||
if (options.PreserveFileTime || options.PreserveAttributes)
|
||||
{
|
||||
@@ -38,7 +41,8 @@ namespace SharpCompress.Common
|
||||
{
|
||||
if (entry.Attrib.HasValue)
|
||||
{
|
||||
nf.Attributes = (FileAttributes)System.Enum.ToObject(typeof(FileAttributes), entry.Attrib.Value);
|
||||
nf.Attributes = (FileAttributes)
|
||||
System.Enum.ToObject(typeof(FileAttributes), entry.Attrib.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
{
|
||||
public class IncompleteArchiveException : ArchiveException
|
||||
{
|
||||
public IncompleteArchiveException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
public IncompleteArchiveException(string message) : base(message) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,14 +4,8 @@ namespace SharpCompress.Common
|
||||
{
|
||||
public class InvalidFormatException : ExtractionException
|
||||
{
|
||||
public InvalidFormatException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
public InvalidFormatException(string message) : base(message) { }
|
||||
|
||||
public InvalidFormatException(string message, Exception inner)
|
||||
: base(message, inner)
|
||||
{
|
||||
}
|
||||
public InvalidFormatException(string message, Exception inner) : base(message, inner) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,14 +4,9 @@ namespace SharpCompress.Common
|
||||
{
|
||||
public class MultiVolumeExtractionException : ExtractionException
|
||||
{
|
||||
public MultiVolumeExtractionException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
public MultiVolumeExtractionException(string message) : base(message) { }
|
||||
|
||||
public MultiVolumeExtractionException(string message, Exception inner)
|
||||
: base(message, inner)
|
||||
{
|
||||
}
|
||||
: base(message, inner) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
{
|
||||
public class MultipartStreamRequiredException : ExtractionException
|
||||
{
|
||||
public MultipartStreamRequiredException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
public MultipartStreamRequiredException(string message) : base(message) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
namespace SharpCompress.Common
|
||||
namespace SharpCompress.Common
|
||||
{
|
||||
public class OptionsBase
|
||||
{
|
||||
@@ -10,4 +9,4 @@ namespace SharpCompress.Common
|
||||
|
||||
public ArchiveEncoding ArchiveEncoding { get; set; } = new ArchiveEncoding();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,14 +4,9 @@ namespace SharpCompress.Common
|
||||
{
|
||||
public class PasswordProtectedException : ExtractionException
|
||||
{
|
||||
public PasswordProtectedException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
public PasswordProtectedException(string message) : base(message) { }
|
||||
|
||||
public PasswordProtectedException(string message, Exception inner)
|
||||
: base(message, inner)
|
||||
{
|
||||
}
|
||||
public PasswordProtectedException(string message, Exception inner) : base(message, inner)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,4 +29,4 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
|
||||
internal byte AvVersion { get; private set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
{
|
||||
internal class ArchiveCryptHeader : RarHeader
|
||||
{
|
||||
|
||||
private const int CRYPT_VERSION = 0; // Supported encryption version.
|
||||
private const int SIZE_SALT50 = 16;
|
||||
private const int SIZE_SALT30 = 8;
|
||||
@@ -16,7 +15,6 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
private const int CRYPT5_KDF_LG2_COUNT = 15; // LOG2 of PDKDF2 iteration count.
|
||||
private const int CRYPT5_KDF_LG2_COUNT_MAX = 24; // LOG2 of maximum accepted iteration count.
|
||||
|
||||
|
||||
private bool _usePswCheck;
|
||||
private uint _lg2Count; // Log2 of PBKDF2 repetition count.
|
||||
private byte[] _salt;
|
||||
@@ -24,9 +22,7 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
private byte[] _pswCheckCsm;
|
||||
|
||||
public ArchiveCryptHeader(RarHeader header, RarCrcBinaryReader reader)
|
||||
: base(header, reader, HeaderType.Crypt)
|
||||
{
|
||||
}
|
||||
: base(header, reader, HeaderType.Crypt) { }
|
||||
|
||||
protected override void ReadFinish(MarkingBinaryReader reader)
|
||||
{
|
||||
@@ -37,10 +33,12 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
return;
|
||||
}
|
||||
var encryptionFlags = reader.ReadRarVIntUInt32();
|
||||
_usePswCheck = FlagUtility.HasFlag(encryptionFlags, EncryptionFlagsV5.CHFL_CRYPT_PSWCHECK);
|
||||
_usePswCheck = FlagUtility.HasFlag(
|
||||
encryptionFlags,
|
||||
EncryptionFlagsV5.CHFL_CRYPT_PSWCHECK
|
||||
);
|
||||
_lg2Count = reader.ReadRarVIntByte(1);
|
||||
|
||||
|
||||
//UsePswCheck = HasHeaderFlag(EncryptionFlagsV5.CHFL_CRYPT_PSWCHECK);
|
||||
if (_lg2Count > CRYPT5_KDF_LG2_COUNT_MAX)
|
||||
{
|
||||
@@ -56,4 +54,4 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,7 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
internal sealed class ArchiveHeader : RarHeader
|
||||
{
|
||||
public ArchiveHeader(RarHeader header, RarCrcBinaryReader reader)
|
||||
: base(header, reader, HeaderType.Archive)
|
||||
{
|
||||
}
|
||||
: base(header, reader, HeaderType.Archive) { }
|
||||
|
||||
protected override void ReadFinish(MarkingBinaryReader reader)
|
||||
{
|
||||
@@ -81,8 +79,9 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
public bool IsVolume => HasFlag(IsRar5 ? ArchiveFlagsV5.VOLUME : ArchiveFlagsV4.VOLUME);
|
||||
|
||||
// RAR5: Volume number field is present. True for all volumes except first.
|
||||
public bool IsFirstVolume => IsRar5 ? VolumeNumber is null : HasFlag(ArchiveFlagsV4.FIRST_VOLUME);
|
||||
public bool IsFirstVolume =>
|
||||
IsRar5 ? VolumeNumber is null : HasFlag(ArchiveFlagsV4.FIRST_VOLUME);
|
||||
|
||||
public bool IsSolid => HasFlag(IsRar5 ? ArchiveFlagsV5.SOLID : ArchiveFlagsV4.SOLID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,4 +28,4 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
internal byte UnpMethod { get; private set; }
|
||||
internal short CommCrc { get; private set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,7 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
internal class EndArchiveHeader : RarHeader
|
||||
{
|
||||
public EndArchiveHeader(RarHeader header, RarCrcBinaryReader reader)
|
||||
: base(header, reader, HeaderType.EndArchive)
|
||||
{
|
||||
}
|
||||
: base(header, reader, HeaderType.EndArchive) { }
|
||||
|
||||
protected override void ReadFinish(MarkingBinaryReader reader)
|
||||
{
|
||||
@@ -40,4 +38,4 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
|
||||
internal short? VolumeNumber { get; private set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,7 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
private uint _fileCrc;
|
||||
|
||||
public FileHeader(RarHeader header, RarCrcBinaryReader reader, HeaderType headerType)
|
||||
: base(header, reader, headerType)
|
||||
{
|
||||
}
|
||||
: base(header, reader, headerType) { }
|
||||
|
||||
protected override void ReadFinish(MarkingBinaryReader reader)
|
||||
{
|
||||
@@ -68,7 +66,7 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
// them.
|
||||
CompressionAlgorithm = (byte)((compressionInfo & 0x3f) + 50);
|
||||
|
||||
// 7th bit (0x0040) defines the solid flag. If it is set, RAR continues to use the compression dictionary left after processing preceding files.
|
||||
// 7th bit (0x0040) defines the solid flag. If it is set, RAR continues to use the compression dictionary left after processing preceding files.
|
||||
// It can be set only for file headers and is never set for service headers.
|
||||
IsSolid = (compressionInfo & 0x40) == 0x40;
|
||||
|
||||
@@ -89,7 +87,7 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
// TODO: not sure if anything needs to be done to handle the following:
|
||||
// If Unix file name contains any high ASCII characters which cannot be correctly converted to Unicode and UTF-8
|
||||
// we map such characters to to 0xE080 - 0xE0FF private use Unicode area and insert 0xFFFE Unicode non-character
|
||||
// to resulting string to indicate that it contains mapped characters, which need to be converted back when extracting.
|
||||
// to resulting string to indicate that it contains mapped characters, which need to be converted back when extracting.
|
||||
// Concrete position of 0xFFFE is not defined, we need to search the entire string for it. Such mapped names are not
|
||||
// portable and can be correctly unpacked only on the same system where they were created.
|
||||
//
|
||||
@@ -119,6 +117,7 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
{
|
||||
//TODO
|
||||
case 1: // file encryption
|
||||
|
||||
{
|
||||
isEncryptedRar5 = true;
|
||||
|
||||
@@ -132,6 +131,7 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
// }
|
||||
// break;
|
||||
case 3: // file time
|
||||
|
||||
{
|
||||
ushort flags = reader.ReadRarVIntUInt16();
|
||||
var isWindowsTime = (flags & 1) == 0;
|
||||
@@ -190,7 +190,6 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static DateTime ReadExtendedTimeV5(MarkingBinaryReader reader, bool isWindowsTime)
|
||||
{
|
||||
if (isWindowsTime)
|
||||
@@ -213,12 +212,13 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
private void ReadFromReaderV4(MarkingBinaryReader reader)
|
||||
{
|
||||
Flags = HeaderFlags;
|
||||
IsSolid = HasFlag(FileFlagsV4.SOLID);
|
||||
WindowSize = IsDirectory ? 0U : ((size_t)0x10000) << ((Flags & FileFlagsV4.WINDOW_MASK) >> 5);
|
||||
WindowSize = IsDirectory
|
||||
? 0U
|
||||
: ((size_t)0x10000) << ((Flags & FileFlagsV4.WINDOW_MASK) >> 5);
|
||||
|
||||
uint lowUncompressedSize = reader.ReadUInt32();
|
||||
|
||||
@@ -263,12 +263,12 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
switch (HeaderCode)
|
||||
{
|
||||
case HeaderCodeV.RAR4_FILE_HEADER:
|
||||
|
||||
{
|
||||
if (HasFlag(FileFlagsV4.UNICODE))
|
||||
{
|
||||
int length = 0;
|
||||
while (length < fileNameBytes.Length
|
||||
&& fileNameBytes[length] != 0)
|
||||
while (length < fileNameBytes.Length && fileNameBytes[length] != 0)
|
||||
{
|
||||
length++;
|
||||
}
|
||||
@@ -290,6 +290,7 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
}
|
||||
break;
|
||||
case HeaderCodeV.RAR4_NEW_SUB_HEADER:
|
||||
|
||||
{
|
||||
int datasize = HeaderSize - newLhdSize - nameSize;
|
||||
if (HasFlag(FileFlagsV4.SALT))
|
||||
@@ -303,8 +304,11 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
|
||||
if (NewSubHeaderType.SUBHEAD_TYPE_RR.Equals(fileNameBytes))
|
||||
{
|
||||
RecoverySectors = SubData[8] + (SubData[9] << 8)
|
||||
+ (SubData[10] << 16) + (SubData[11] << 24);
|
||||
RecoverySectors =
|
||||
SubData[8]
|
||||
+ (SubData[9] << 8)
|
||||
+ (SubData[10] << 16)
|
||||
+ (SubData[11] << 24);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -321,7 +325,12 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
if (RemainingHeaderBytes(reader) >= 2)
|
||||
{
|
||||
ushort extendedFlags = reader.ReadUInt16();
|
||||
FileLastModifiedTime = ProcessExtendedTimeV4(extendedFlags, FileLastModifiedTime, reader, 0);
|
||||
FileLastModifiedTime = ProcessExtendedTimeV4(
|
||||
extendedFlags,
|
||||
FileLastModifiedTime,
|
||||
reader,
|
||||
0
|
||||
);
|
||||
FileCreatedTime = ProcessExtendedTimeV4(extendedFlags, null, reader, 1);
|
||||
FileLastAccessedTime = ProcessExtendedTimeV4(extendedFlags, null, reader, 2);
|
||||
FileArchivedTime = ProcessExtendedTimeV4(extendedFlags, null, reader, 3);
|
||||
@@ -336,7 +345,12 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
return l + y;
|
||||
}
|
||||
|
||||
private static DateTime? ProcessExtendedTimeV4(ushort extendedFlags, DateTime? time, MarkingBinaryReader reader, int i)
|
||||
private static DateTime? ProcessExtendedTimeV4(
|
||||
ushort extendedFlags,
|
||||
DateTime? time,
|
||||
MarkingBinaryReader reader,
|
||||
int i
|
||||
)
|
||||
{
|
||||
uint rmode = (uint)extendedFlags >> (3 - i) * 4;
|
||||
if ((rmode & 8) == 0)
|
||||
@@ -395,7 +409,7 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
{
|
||||
if (IsRar5 && !HasFlag(FileFlagsV5.HAS_CRC32))
|
||||
{
|
||||
//!!! rar5:
|
||||
//!!! rar5:
|
||||
throw new InvalidOperationException("TODO rar5");
|
||||
}
|
||||
return _fileCrc;
|
||||
@@ -437,8 +451,10 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
internal long DataStartPosition { get; set; }
|
||||
public Stream PackedStream { get; set; }
|
||||
|
||||
public bool IsSplitBefore => IsRar5 ? HasHeaderFlag(HeaderFlagsV5.SPLIT_BEFORE) : HasFlag(FileFlagsV4.SPLIT_BEFORE);
|
||||
public bool IsSplitAfter => IsRar5 ? HasHeaderFlag(HeaderFlagsV5.SPLIT_AFTER) : HasFlag(FileFlagsV4.SPLIT_AFTER);
|
||||
public bool IsSplitBefore =>
|
||||
IsRar5 ? HasHeaderFlag(HeaderFlagsV5.SPLIT_BEFORE) : HasFlag(FileFlagsV4.SPLIT_BEFORE);
|
||||
public bool IsSplitAfter =>
|
||||
IsRar5 ? HasHeaderFlag(HeaderFlagsV5.SPLIT_AFTER) : HasFlag(FileFlagsV4.SPLIT_AFTER);
|
||||
|
||||
public bool IsDirectory => HasFlag(IsRar5 ? FileFlagsV5.DIRECTORY : FileFlagsV4.DIRECTORY);
|
||||
|
||||
@@ -453,4 +469,4 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
|
||||
internal DateTime? FileArchivedTime { get; private set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,11 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
if ((length & 0x80) != 0)
|
||||
{
|
||||
int correction = GetChar(name, encPos++);
|
||||
for (length = (length & 0x7f) + 2; length > 0 && decPos < name.Length; length--, decPos++)
|
||||
for (
|
||||
length = (length & 0x7f) + 2;
|
||||
length > 0 && decPos < name.Length;
|
||||
length--, decPos++
|
||||
)
|
||||
{
|
||||
low = (GetChar(name, decPos) + correction) & 0xff;
|
||||
buf.Append((char)((highByte << 8) + low));
|
||||
@@ -62,7 +66,11 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
}
|
||||
else
|
||||
{
|
||||
for (length += 2; length > 0 && decPos < name.Length; length--, decPos++)
|
||||
for (
|
||||
length += 2;
|
||||
length > 0 && decPos < name.Length;
|
||||
length--, decPos++
|
||||
)
|
||||
{
|
||||
buf.Append((char)(GetChar(name, decPos)));
|
||||
}
|
||||
@@ -75,4 +83,4 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
return buf.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
{
|
||||
public const ushort HAS_EXTRA = 0x0001;
|
||||
public const ushort HAS_DATA = 0x0002;
|
||||
public const ushort KEEP = 0x0004; // block must be kept during an update
|
||||
public const ushort KEEP = 0x0004; // block must be kept during an update
|
||||
public const ushort SPLIT_BEFORE = 0x0008;
|
||||
public const ushort SPLIT_AFTER = 0x0010;
|
||||
public const ushort CHILD = 0x0020; // ??? Block depends on preceding file block.
|
||||
|
||||
@@ -34,7 +34,8 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
try
|
||||
{
|
||||
int start = -1;
|
||||
var b = GetByte(stream); start++;
|
||||
var b = GetByte(stream);
|
||||
start++;
|
||||
while (start <= maxScanIndex)
|
||||
{
|
||||
// Rar old signature: 52 45 7E 5E
|
||||
@@ -42,37 +43,44 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
// Rar5 signature: 52 61 72 21 1A 07 01 00
|
||||
if (b == 0x52)
|
||||
{
|
||||
b = GetByte(stream); start++;
|
||||
b = GetByte(stream);
|
||||
start++;
|
||||
if (b == 0x61)
|
||||
{
|
||||
b = GetByte(stream); start++;
|
||||
b = GetByte(stream);
|
||||
start++;
|
||||
if (b != 0x72)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
b = GetByte(stream); start++;
|
||||
b = GetByte(stream);
|
||||
start++;
|
||||
if (b != 0x21)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
b = GetByte(stream); start++;
|
||||
b = GetByte(stream);
|
||||
start++;
|
||||
if (b != 0x1a)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
b = GetByte(stream); start++;
|
||||
b = GetByte(stream);
|
||||
start++;
|
||||
if (b != 0x07)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
b = GetByte(stream); start++;
|
||||
b = GetByte(stream);
|
||||
start++;
|
||||
if (b == 1)
|
||||
{
|
||||
b = GetByte(stream); start++;
|
||||
b = GetByte(stream);
|
||||
start++;
|
||||
if (b != 0)
|
||||
{
|
||||
continue;
|
||||
@@ -87,24 +95,29 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
}
|
||||
else if (b == 0x45)
|
||||
{
|
||||
b = GetByte(stream); start++;
|
||||
b = GetByte(stream);
|
||||
start++;
|
||||
if (b != 0x7e)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
b = GetByte(stream); start++;
|
||||
b = GetByte(stream);
|
||||
start++;
|
||||
if (b != 0x5e)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new InvalidFormatException("Rar format version pre-4 is unsupported.");
|
||||
throw new InvalidFormatException(
|
||||
"Rar format version pre-4 is unsupported."
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
b = GetByte(stream); start++;
|
||||
b = GetByte(stream);
|
||||
start++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,4 +46,4 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
return other is not null && Equals(other._bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,4 +28,4 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
internal uint TotalBlocks { get; private set; }
|
||||
internal byte[]? Mark { get; private set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,11 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
private readonly HeaderType _headerType;
|
||||
private readonly bool _isRar5;
|
||||
|
||||
internal static RarHeader? TryReadBase(RarCrcBinaryReader reader, bool isRar5, ArchiveEncoding archiveEncoding)
|
||||
internal static RarHeader? TryReadBase(
|
||||
RarCrcBinaryReader reader,
|
||||
bool isRar5,
|
||||
ArchiveEncoding archiveEncoding
|
||||
)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -131,4 +135,4 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
/// </summary>
|
||||
protected long AdditionalDataSize { get; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,11 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
|
||||
public IEnumerable<IRarHeader> ReadHeaders(Stream stream)
|
||||
{
|
||||
var markHeader = MarkHeader.Read(stream, Options.LeaveStreamOpen, Options.LookForHeader);
|
||||
var markHeader = MarkHeader.Read(
|
||||
stream,
|
||||
Options.LeaveStreamOpen,
|
||||
Options.LookForHeader
|
||||
);
|
||||
_isRar5 = markHeader.IsRar5;
|
||||
yield return markHeader;
|
||||
|
||||
@@ -49,7 +53,9 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
{
|
||||
if (Options.Password is null)
|
||||
{
|
||||
throw new CryptographicException("Encrypted Rar archive has no password specified.");
|
||||
throw new CryptographicException(
|
||||
"Encrypted Rar archive has no password specified."
|
||||
);
|
||||
}
|
||||
reader = new RarCryptoBinaryReader(stream, Options.Password);
|
||||
}
|
||||
@@ -63,102 +69,113 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
{
|
||||
case HeaderCodeV.RAR5_ARCHIVE_HEADER:
|
||||
case HeaderCodeV.RAR4_ARCHIVE_HEADER:
|
||||
{
|
||||
var ah = new ArchiveHeader(header, reader);
|
||||
if (ah.IsEncrypted == true)
|
||||
{
|
||||
var ah = new ArchiveHeader(header, reader);
|
||||
if (ah.IsEncrypted == true)
|
||||
{
|
||||
//!!! rar5 we don't know yet
|
||||
IsEncrypted = true;
|
||||
}
|
||||
return ah;
|
||||
//!!! rar5 we don't know yet
|
||||
IsEncrypted = true;
|
||||
}
|
||||
return ah;
|
||||
}
|
||||
|
||||
case HeaderCodeV.RAR4_PROTECT_HEADER:
|
||||
{
|
||||
var ph = new ProtectHeader(header, reader);
|
||||
// skip the recovery record data, we do not use it.
|
||||
switch (StreamingMode)
|
||||
{
|
||||
var ph = new ProtectHeader(header, reader);
|
||||
// skip the recovery record data, we do not use it.
|
||||
switch (StreamingMode)
|
||||
{
|
||||
case StreamingMode.Seekable:
|
||||
{
|
||||
reader.BaseStream.Position += ph.DataSize;
|
||||
}
|
||||
break;
|
||||
case StreamingMode.Streaming:
|
||||
{
|
||||
reader.BaseStream.Skip(ph.DataSize);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
throw new InvalidFormatException("Invalid StreamingMode");
|
||||
}
|
||||
}
|
||||
case StreamingMode.Seekable:
|
||||
|
||||
return ph;
|
||||
{
|
||||
reader.BaseStream.Position += ph.DataSize;
|
||||
}
|
||||
break;
|
||||
case StreamingMode.Streaming:
|
||||
|
||||
{
|
||||
reader.BaseStream.Skip(ph.DataSize);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
throw new InvalidFormatException("Invalid StreamingMode");
|
||||
}
|
||||
}
|
||||
|
||||
return ph;
|
||||
}
|
||||
|
||||
case HeaderCodeV.RAR5_SERVICE_HEADER:
|
||||
{
|
||||
var fh = new FileHeader(header, reader, HeaderType.Service);
|
||||
SkipData(fh, reader);
|
||||
return fh;
|
||||
}
|
||||
{
|
||||
var fh = new FileHeader(header, reader, HeaderType.Service);
|
||||
SkipData(fh, reader);
|
||||
return fh;
|
||||
}
|
||||
|
||||
case HeaderCodeV.RAR4_NEW_SUB_HEADER:
|
||||
{
|
||||
var fh = new FileHeader(header, reader, HeaderType.NewSub);
|
||||
SkipData(fh, reader);
|
||||
return fh;
|
||||
}
|
||||
{
|
||||
var fh = new FileHeader(header, reader, HeaderType.NewSub);
|
||||
SkipData(fh, reader);
|
||||
return fh;
|
||||
}
|
||||
|
||||
case HeaderCodeV.RAR5_FILE_HEADER:
|
||||
case HeaderCodeV.RAR4_FILE_HEADER:
|
||||
{
|
||||
var fh = new FileHeader(header, reader, HeaderType.File);
|
||||
switch (StreamingMode)
|
||||
{
|
||||
var fh = new FileHeader(header, reader, HeaderType.File);
|
||||
switch (StreamingMode)
|
||||
case StreamingMode.Seekable:
|
||||
|
||||
{
|
||||
fh.DataStartPosition = reader.BaseStream.Position;
|
||||
reader.BaseStream.Position += fh.CompressedSize;
|
||||
}
|
||||
break;
|
||||
case StreamingMode.Streaming:
|
||||
|
||||
{
|
||||
var ms = new ReadOnlySubStream(
|
||||
reader.BaseStream,
|
||||
fh.CompressedSize
|
||||
);
|
||||
if (fh.R4Salt is null)
|
||||
{
|
||||
fh.PackedStream = ms;
|
||||
}
|
||||
else
|
||||
{
|
||||
fh.PackedStream = new RarCryptoWrapper(
|
||||
ms,
|
||||
Options.Password!,
|
||||
fh.R4Salt
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
case StreamingMode.Seekable:
|
||||
{
|
||||
fh.DataStartPosition = reader.BaseStream.Position;
|
||||
reader.BaseStream.Position += fh.CompressedSize;
|
||||
}
|
||||
break;
|
||||
case StreamingMode.Streaming:
|
||||
{
|
||||
var ms = new ReadOnlySubStream(reader.BaseStream, fh.CompressedSize);
|
||||
if (fh.R4Salt is null)
|
||||
{
|
||||
fh.PackedStream = ms;
|
||||
}
|
||||
else
|
||||
{
|
||||
fh.PackedStream = new RarCryptoWrapper(ms, Options.Password!, fh.R4Salt);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
throw new InvalidFormatException("Invalid StreamingMode");
|
||||
}
|
||||
throw new InvalidFormatException("Invalid StreamingMode");
|
||||
}
|
||||
return fh;
|
||||
}
|
||||
return fh;
|
||||
}
|
||||
case HeaderCodeV.RAR5_END_ARCHIVE_HEADER:
|
||||
case HeaderCodeV.RAR4_END_ARCHIVE_HEADER:
|
||||
{
|
||||
return new EndArchiveHeader(header, reader);
|
||||
}
|
||||
{
|
||||
return new EndArchiveHeader(header, reader);
|
||||
}
|
||||
case HeaderCodeV.RAR5_ARCHIVE_ENCRYPTION_HEADER:
|
||||
{
|
||||
var ch = new ArchiveCryptHeader(header, reader);
|
||||
IsEncrypted = true;
|
||||
return ch;
|
||||
}
|
||||
{
|
||||
var ch = new ArchiveCryptHeader(header, reader);
|
||||
IsEncrypted = true;
|
||||
return ch;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new InvalidFormatException("Unknown Rar Header: " + header.HeaderCode);
|
||||
}
|
||||
{
|
||||
throw new InvalidFormatException("Unknown Rar Header: " + header.HeaderCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,21 +184,23 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
switch (StreamingMode)
|
||||
{
|
||||
case StreamingMode.Seekable:
|
||||
|
||||
{
|
||||
fh.DataStartPosition = reader.BaseStream.Position;
|
||||
reader.BaseStream.Position += fh.CompressedSize;
|
||||
}
|
||||
break;
|
||||
case StreamingMode.Streaming:
|
||||
|
||||
{
|
||||
//skip the data because it's useless?
|
||||
reader.BaseStream.Skip(fh.CompressedSize);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
throw new InvalidFormatException("Invalid StreamingMode");
|
||||
}
|
||||
{
|
||||
throw new InvalidFormatException("Invalid StreamingMode");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,4 +26,4 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
|
||||
internal short UserNameSize { get; private set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,7 @@ namespace SharpCompress.Common.Rar
|
||||
{
|
||||
private uint _currentCrc;
|
||||
|
||||
public RarCrcBinaryReader(Stream stream)
|
||||
: base(stream)
|
||||
{
|
||||
}
|
||||
public RarCrcBinaryReader(Stream stream) : base(stream) { }
|
||||
|
||||
public uint GetCrc32()
|
||||
{
|
||||
@@ -47,4 +44,4 @@ namespace SharpCompress.Common.Rar
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,7 @@ namespace SharpCompress.Common.Rar
|
||||
private readonly Queue<byte> _data = new Queue<byte>();
|
||||
private long _readCount;
|
||||
|
||||
public RarCryptoBinaryReader(Stream stream, string password)
|
||||
: base(stream)
|
||||
public RarCryptoBinaryReader(Stream stream, string password) : base(stream)
|
||||
{
|
||||
_password = password;
|
||||
|
||||
@@ -108,4 +107,4 @@ namespace SharpCompress.Common.Rar
|
||||
ClearQueue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,11 @@ namespace SharpCompress.Common.Rar
|
||||
/// <summary>
|
||||
/// As the V2017 port isn't complete, add this check to use the legacy Rar code.
|
||||
/// </summary>
|
||||
internal bool IsRarV3 => FileHeader.CompressionAlgorithm == 20 || FileHeader.CompressionAlgorithm == 26 || FileHeader.CompressionAlgorithm == 29 || FileHeader.CompressionAlgorithm == 36; //Nanook - Added 20+26 as Test arc from WinRar2.8 (algo 20) was failing with 2017 code
|
||||
internal bool IsRarV3 =>
|
||||
FileHeader.CompressionAlgorithm == 20
|
||||
|| FileHeader.CompressionAlgorithm == 26
|
||||
|| FileHeader.CompressionAlgorithm == 29
|
||||
|| FileHeader.CompressionAlgorithm == 36; //Nanook - Added 20+26 as Test arc from WinRar2.8 (algo 20) was failing with 2017 code
|
||||
|
||||
/// <summary>
|
||||
/// The File's 32 bit CRC Hash
|
||||
@@ -58,8 +62,13 @@ namespace SharpCompress.Common.Rar
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Entry Path: {0} Compressed Size: {1} Uncompressed Size: {2} CRC: {3}",
|
||||
Key, CompressedSize, Size, Crc);
|
||||
return string.Format(
|
||||
"Entry Path: {0} Compressed Size: {1} Uncompressed Size: {2} CRC: {3}",
|
||||
Key,
|
||||
CompressedSize,
|
||||
Size,
|
||||
Crc
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,7 @@ namespace SharpCompress.Common.Rar
|
||||
/// </summary>
|
||||
internal abstract class RarFilePart : FilePart
|
||||
{
|
||||
internal RarFilePart(MarkHeader mh, FileHeader fh, int index)
|
||||
: base(fh.ArchiveEncoding)
|
||||
internal RarFilePart(MarkHeader mh, FileHeader fh, int index) : base(fh.ArchiveEncoding)
|
||||
{
|
||||
MarkHeader = mh;
|
||||
FileHeader = fh;
|
||||
|
||||
@@ -24,7 +24,6 @@ namespace SharpCompress.Common.Rar
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
|
||||
_rijndael = new RijndaelEngine();
|
||||
_aesInitializationVector = new byte[CRYPTO_BLOCK_SIZE];
|
||||
int rawLength = 2 * _password.Length;
|
||||
@@ -52,11 +51,14 @@ namespace SharpCompress.Common.Rar
|
||||
|
||||
data[i * (rawPassword.Length + iblock) + rawPassword.Length + 0] = (byte)i;
|
||||
data[i * (rawPassword.Length + iblock) + rawPassword.Length + 1] = (byte)(i >> 8);
|
||||
data[i * (rawPassword.Length + iblock) + rawPassword.Length + 2] = (byte)(i >> CRYPTO_BLOCK_SIZE);
|
||||
data[i * (rawPassword.Length + iblock) + rawPassword.Length + 2] = (byte)(
|
||||
i >> CRYPTO_BLOCK_SIZE
|
||||
);
|
||||
|
||||
if (i % (noOfRounds / CRYPTO_BLOCK_SIZE) == 0)
|
||||
{
|
||||
digest = SHA1.Create().ComputeHash(data, 0, (i + 1) * (rawPassword.Length + iblock));
|
||||
digest = SHA1.Create()
|
||||
.ComputeHash(data, 0, (i + 1) * (rawPassword.Length + iblock));
|
||||
_aesInitializationVector[i / (noOfRounds / CRYPTO_BLOCK_SIZE)] = digest[19];
|
||||
}
|
||||
}
|
||||
@@ -68,16 +70,18 @@ namespace SharpCompress.Common.Rar
|
||||
{
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
aesKey[i * 4 + j] = (byte)
|
||||
(((digest[i * 4] * 0x1000000) & 0xff000000 |
|
||||
(uint)((digest[i * 4 + 1] * 0x10000) & 0xff0000) |
|
||||
(uint)((digest[i * 4 + 2] * 0x100) & 0xff00) |
|
||||
(uint)(digest[i * 4 + 3] & 0xff)) >> (j * 8));
|
||||
aesKey[i * 4 + j] = (byte)(
|
||||
(
|
||||
(digest[i * 4] * 0x1000000) & 0xff000000
|
||||
| (uint)((digest[i * 4 + 1] * 0x10000) & 0xff0000)
|
||||
| (uint)((digest[i * 4 + 2] * 0x100) & 0xff00)
|
||||
| (uint)(digest[i * 4 + 3] & 0xff)
|
||||
) >> (j * 8)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
_rijndael.Init(false, new KeyParameter(aesKey));
|
||||
|
||||
}
|
||||
|
||||
public static RarRijndael InitializeFrom(string password, byte[] salt)
|
||||
@@ -106,8 +110,6 @@ namespace SharpCompress.Common.Rar
|
||||
return decryptedBytes;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
public void Dispose() { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace SharpCompress.Common.Rar
|
||||
|
||||
#nullable disable
|
||||
internal ArchiveHeader ArchiveHeader { get; private set; }
|
||||
|
||||
#nullable enable
|
||||
|
||||
internal StreamingMode Mode => _headerFactory.StreamingMode;
|
||||
@@ -40,16 +41,19 @@ namespace SharpCompress.Common.Rar
|
||||
switch (header.HeaderType)
|
||||
{
|
||||
case HeaderType.Mark:
|
||||
|
||||
{
|
||||
lastMarkHeader = (MarkHeader)header;
|
||||
}
|
||||
break;
|
||||
case HeaderType.Archive:
|
||||
|
||||
{
|
||||
ArchiveHeader = (ArchiveHeader)header;
|
||||
}
|
||||
break;
|
||||
case HeaderType.File:
|
||||
|
||||
{
|
||||
var fh = (FileHeader)header;
|
||||
if (_maxCompressionAlgorithm < fh.CompressionAlgorithm)
|
||||
@@ -58,17 +62,22 @@ namespace SharpCompress.Common.Rar
|
||||
}
|
||||
break;
|
||||
case HeaderType.Service:
|
||||
{
|
||||
var fh = (FileHeader)header;
|
||||
if (fh.FileName == "CMT")
|
||||
{
|
||||
var part = CreateFilePart(lastMarkHeader!, fh);
|
||||
var buffer = new byte[fh.CompressedSize];
|
||||
part.GetCompressedStream().Read(buffer, 0, buffer.Length);
|
||||
Comment = System.Text.Encoding.UTF8.GetString(buffer, 0, buffer.Length - 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
{
|
||||
var fh = (FileHeader)header;
|
||||
if (fh.FileName == "CMT")
|
||||
{
|
||||
var part = CreateFilePart(lastMarkHeader!, fh);
|
||||
var buffer = new byte[fh.CompressedSize];
|
||||
part.GetCompressedStream().Read(buffer, 0, buffer.Length);
|
||||
Comment = System.Text.Encoding.UTF8.GetString(
|
||||
buffer,
|
||||
0,
|
||||
buffer.Length - 1
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,7 +88,9 @@ namespace SharpCompress.Common.Rar
|
||||
{
|
||||
if (Mode == StreamingMode.Streaming)
|
||||
{
|
||||
throw new InvalidOperationException("ArchiveHeader should never been null in a streaming read.");
|
||||
throw new InvalidOperationException(
|
||||
"ArchiveHeader should never been null in a streaming read."
|
||||
);
|
||||
}
|
||||
|
||||
// we only want to load the archive header to avoid overhead but have to do the nasty thing and reset the stream
|
||||
@@ -157,7 +168,7 @@ namespace SharpCompress.Common.Rar
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public string? Comment { get; internal set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,4 +15,4 @@ namespace SharpCompress.Common
|
||||
|
||||
public ReaderProgress? ReaderProgress { get; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,10 +48,10 @@ namespace SharpCompress.Common.SevenZip
|
||||
internal bool IsEmpty()
|
||||
{
|
||||
return _packSizes.Count == 0
|
||||
&& _packCrCs.Count == 0
|
||||
&& _folders.Count == 0
|
||||
&& _numUnpackStreamsVector.Count == 0
|
||||
&& _files.Count == 0;
|
||||
&& _packCrCs.Count == 0
|
||||
&& _folders.Count == 0
|
||||
&& _numUnpackStreamsVector.Count == 0
|
||||
&& _files.Count == 0;
|
||||
}
|
||||
|
||||
private void FillStartPos()
|
||||
@@ -161,7 +161,13 @@ namespace SharpCompress.Common.SevenZip
|
||||
packSizes[j] = _packSizes[packStreamIndex + j];
|
||||
}
|
||||
|
||||
return DecoderStreamHelper.CreateDecoderStream(stream, folderStartPackPos, packSizes, folder, pw);
|
||||
return DecoderStreamHelper.CreateDecoderStream(
|
||||
stream,
|
||||
folderStartPackPos,
|
||||
packSizes,
|
||||
folder,
|
||||
pw
|
||||
);
|
||||
}
|
||||
|
||||
private long GetFolderPackStreamSize(int folderIndex, int streamIndex)
|
||||
|
||||
@@ -154,7 +154,11 @@ namespace SharpCompress.Common.SevenZip
|
||||
return ReadBitVector(length);
|
||||
}
|
||||
|
||||
private void ReadNumberVector(List<byte[]> dataVector, int numFiles, Action<int, long?> action)
|
||||
private void ReadNumberVector(
|
||||
List<byte[]> dataVector,
|
||||
int numFiles,
|
||||
Action<int, long?> action
|
||||
)
|
||||
{
|
||||
var defined = ReadOptionalBitVector(numFiles);
|
||||
|
||||
@@ -191,12 +195,24 @@ namespace SharpCompress.Common.SevenZip
|
||||
return null;
|
||||
}
|
||||
|
||||
private void ReadDateTimeVector(List<byte[]> dataVector, int numFiles, Action<int, DateTime?> action)
|
||||
private void ReadDateTimeVector(
|
||||
List<byte[]> dataVector,
|
||||
int numFiles,
|
||||
Action<int, DateTime?> action
|
||||
)
|
||||
{
|
||||
ReadNumberVector(dataVector, numFiles, (index, value) => action(index, TranslateTime(value)));
|
||||
ReadNumberVector(
|
||||
dataVector,
|
||||
numFiles,
|
||||
(index, value) => action(index, TranslateTime(value))
|
||||
);
|
||||
}
|
||||
|
||||
private void ReadAttributeVector(List<byte[]> dataVector, int numFiles, Action<int, uint?> action)
|
||||
private void ReadAttributeVector(
|
||||
List<byte[]> dataVector,
|
||||
int numFiles,
|
||||
Action<int, uint?> action
|
||||
)
|
||||
{
|
||||
BitVector boolVector = ReadOptionalBitVector(numFiles);
|
||||
using (var streamSwitch = new CStreamSwitch())
|
||||
@@ -251,7 +267,16 @@ namespace SharpCompress.Common.SevenZip
|
||||
byte[] longId = new byte[idSize];
|
||||
ReadBytes(longId, 0, idSize);
|
||||
#if DEBUG
|
||||
Log.WriteLine("MethodId: " + String.Join("", Enumerable.Range(0, idSize).Select(x => longId[x].ToString("x2")).ToArray()));
|
||||
Log.WriteLine(
|
||||
"MethodId: "
|
||||
+ String.Join(
|
||||
"",
|
||||
Enumerable
|
||||
.Range(0, idSize)
|
||||
.Select(x => longId[x].ToString("x2"))
|
||||
.ToArray()
|
||||
)
|
||||
);
|
||||
#endif
|
||||
if (idSize > 8)
|
||||
{
|
||||
@@ -269,7 +294,13 @@ namespace SharpCompress.Common.SevenZip
|
||||
coder._numInStreams = ReadNum();
|
||||
coder._numOutStreams = ReadNum();
|
||||
#if DEBUG
|
||||
Log.WriteLine("Complex Stream (In: " + coder._numInStreams + " - Out: " + coder._numOutStreams + ")");
|
||||
Log.WriteLine(
|
||||
"Complex Stream (In: "
|
||||
+ coder._numInStreams
|
||||
+ " - Out: "
|
||||
+ coder._numOutStreams
|
||||
+ ")"
|
||||
);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
@@ -287,7 +318,13 @@ namespace SharpCompress.Common.SevenZip
|
||||
coder._props = new byte[propsSize];
|
||||
ReadBytes(coder._props, 0, propsSize);
|
||||
#if DEBUG
|
||||
Log.WriteLine("Settings: " + String.Join("", coder._props.Select(bt => bt.ToString("x2")).ToArray()));
|
||||
Log.WriteLine(
|
||||
"Settings: "
|
||||
+ String.Join(
|
||||
"",
|
||||
coder._props.Select(bt => bt.ToString("x2")).ToArray()
|
||||
)
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -414,7 +451,11 @@ namespace SharpCompress.Common.SevenZip
|
||||
return digests;
|
||||
}
|
||||
|
||||
private void ReadPackInfo(out long dataOffset, out List<long> packSizes, out List<uint?> packCrCs)
|
||||
private void ReadPackInfo(
|
||||
out long dataOffset,
|
||||
out List<long> packSizes,
|
||||
out List<uint?> packCrCs
|
||||
)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- ReadPackInfo --");
|
||||
@@ -568,8 +609,12 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadSubStreamsInfo(List<CFolder> folders, out List<int> numUnpackStreamsInFolders,
|
||||
out List<long> unpackSizes, out List<uint?> digests)
|
||||
private void ReadSubStreamsInfo(
|
||||
List<CFolder> folders,
|
||||
out List<int> numUnpackStreamsInFolders,
|
||||
out List<long> unpackSizes,
|
||||
out List<uint?> digests
|
||||
)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- ReadSubStreamsInfo --");
|
||||
@@ -739,7 +784,8 @@ namespace SharpCompress.Common.SevenZip
|
||||
out List<CFolder> folders,
|
||||
out List<int> numUnpackStreamsInFolders,
|
||||
out List<long> unpackSizes,
|
||||
out List<uint?> digests)
|
||||
out List<uint?> digests
|
||||
)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- ReadStreamsInfo --");
|
||||
@@ -768,7 +814,12 @@ namespace SharpCompress.Common.SevenZip
|
||||
ReadUnpackInfo(dataVector, out folders);
|
||||
break;
|
||||
case BlockType.SubStreamsInfo:
|
||||
ReadSubStreamsInfo(folders, out numUnpackStreamsInFolders, out unpackSizes, out digests);
|
||||
ReadSubStreamsInfo(
|
||||
folders,
|
||||
out numUnpackStreamsInFolders,
|
||||
out unpackSizes,
|
||||
out digests
|
||||
);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
@@ -791,14 +842,16 @@ namespace SharpCompress.Common.SevenZip
|
||||
#endif
|
||||
try
|
||||
{
|
||||
ReadStreamsInfo(null,
|
||||
out long dataStartPos,
|
||||
out List<long> packSizes,
|
||||
out List<uint?> packCrCs,
|
||||
out List<CFolder> folders,
|
||||
out List<int> numUnpackStreamsInFolders,
|
||||
out List<long> unpackSizes,
|
||||
out List<uint?> digests);
|
||||
ReadStreamsInfo(
|
||||
null,
|
||||
out long dataStartPos,
|
||||
out List<long> packSizes,
|
||||
out List<uint?> packCrCs,
|
||||
out List<CFolder> folders,
|
||||
out List<int> numUnpackStreamsInFolders,
|
||||
out List<long> unpackSizes,
|
||||
out List<uint?> digests
|
||||
);
|
||||
|
||||
dataStartPos += baseOffset;
|
||||
|
||||
@@ -815,23 +868,35 @@ namespace SharpCompress.Common.SevenZip
|
||||
dataStartPos += packSize;
|
||||
}
|
||||
|
||||
var outStream = DecoderStreamHelper.CreateDecoderStream(_stream, oldDataStartPos, myPackSizes,
|
||||
folder, pass);
|
||||
var outStream = DecoderStreamHelper.CreateDecoderStream(
|
||||
_stream,
|
||||
oldDataStartPos,
|
||||
myPackSizes,
|
||||
folder,
|
||||
pass
|
||||
);
|
||||
|
||||
int unpackSize = checked((int)folder.GetUnpackSize());
|
||||
byte[] data = new byte[unpackSize];
|
||||
outStream.ReadExact(data, 0, data.Length);
|
||||
if (outStream.ReadByte() >= 0)
|
||||
{
|
||||
throw new InvalidOperationException("Decoded stream is longer than expected.");
|
||||
throw new InvalidOperationException(
|
||||
"Decoded stream is longer than expected."
|
||||
);
|
||||
}
|
||||
dataVector.Add(data);
|
||||
|
||||
if (folder.UnpackCrcDefined)
|
||||
{
|
||||
if (Crc.Finish(Crc.Update(Crc.INIT_CRC, data, 0, unpackSize)) != folder._unpackCrc)
|
||||
if (
|
||||
Crc.Finish(Crc.Update(Crc.INIT_CRC, data, 0, unpackSize))
|
||||
!= folder._unpackCrc
|
||||
)
|
||||
{
|
||||
throw new InvalidOperationException("Decoded stream does not match expected CRC.");
|
||||
throw new InvalidOperationException(
|
||||
"Decoded stream does not match expected CRC."
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -864,7 +929,10 @@ namespace SharpCompress.Common.SevenZip
|
||||
List<byte[]> dataVector = null;
|
||||
if (type == BlockType.AdditionalStreamsInfo)
|
||||
{
|
||||
dataVector = ReadAndDecodePackedStreams(db._startPositionAfterHeader, getTextPassword);
|
||||
dataVector = ReadAndDecodePackedStreams(
|
||||
db._startPositionAfterHeader,
|
||||
getTextPassword
|
||||
);
|
||||
type = ReadId();
|
||||
}
|
||||
|
||||
@@ -873,14 +941,16 @@ namespace SharpCompress.Common.SevenZip
|
||||
|
||||
if (type == BlockType.MainStreamsInfo)
|
||||
{
|
||||
ReadStreamsInfo(dataVector,
|
||||
out db._dataStartPosition,
|
||||
out db._packSizes,
|
||||
out db._packCrCs,
|
||||
out db._folders,
|
||||
out db._numUnpackStreamsVector,
|
||||
out unpackSizes,
|
||||
out digests);
|
||||
ReadStreamsInfo(
|
||||
dataVector,
|
||||
out db._dataStartPosition,
|
||||
out db._packSizes,
|
||||
out db._packCrCs,
|
||||
out db._folders,
|
||||
out db._numUnpackStreamsVector,
|
||||
out unpackSizes,
|
||||
out digests
|
||||
);
|
||||
|
||||
db._dataStartPosition += db._startPositionAfterHeader;
|
||||
type = ReadId();
|
||||
@@ -961,35 +1031,41 @@ namespace SharpCompress.Common.SevenZip
|
||||
#if DEBUG
|
||||
Log.Write("WinAttributes:");
|
||||
#endif
|
||||
ReadAttributeVector(dataVector, numFiles, delegate (int i, uint? attr)
|
||||
{
|
||||
// Some third party implementations established an unofficial extension
|
||||
// of the 7z archive format by placing posix file attributes in the high
|
||||
// bits of the windows file attributes. This makes use of the fact that
|
||||
// the official implementation does not perform checks on this value.
|
||||
//
|
||||
// Newer versions of the official 7z GUI client will try to parse this
|
||||
// extension, thus acknowledging the unofficial use of these bits.
|
||||
//
|
||||
// For us it is safe to just discard the upper bits if they are set and
|
||||
// keep the windows attributes from the lower bits (which should be set
|
||||
// properly even if posix file attributes are present, in order to be
|
||||
// compatible with older 7z archive readers)
|
||||
//
|
||||
// Note that the 15th bit is used by some implementations to indicate
|
||||
// presence of the extension, but not all implementations do that so
|
||||
// we can't trust that bit and must ignore it.
|
||||
//
|
||||
if (attr.HasValue && (attr.Value >> 16) != 0)
|
||||
{
|
||||
attr = attr.Value & 0x7FFFu;
|
||||
}
|
||||
ReadAttributeVector(
|
||||
dataVector,
|
||||
numFiles,
|
||||
delegate(int i, uint? attr)
|
||||
{
|
||||
// Some third party implementations established an unofficial extension
|
||||
// of the 7z archive format by placing posix file attributes in the high
|
||||
// bits of the windows file attributes. This makes use of the fact that
|
||||
// the official implementation does not perform checks on this value.
|
||||
//
|
||||
// Newer versions of the official 7z GUI client will try to parse this
|
||||
// extension, thus acknowledging the unofficial use of these bits.
|
||||
//
|
||||
// For us it is safe to just discard the upper bits if they are set and
|
||||
// keep the windows attributes from the lower bits (which should be set
|
||||
// properly even if posix file attributes are present, in order to be
|
||||
// compatible with older 7z archive readers)
|
||||
//
|
||||
// Note that the 15th bit is used by some implementations to indicate
|
||||
// presence of the extension, but not all implementations do that so
|
||||
// we can't trust that bit and must ignore it.
|
||||
//
|
||||
if (attr.HasValue && (attr.Value >> 16) != 0)
|
||||
{
|
||||
attr = attr.Value & 0x7FFFu;
|
||||
}
|
||||
|
||||
db._files[i].Attrib = attr;
|
||||
db._files[i].Attrib = attr;
|
||||
#if DEBUG
|
||||
Log.Write(" " + (attr.HasValue ? attr.Value.ToString("x8") : "n/a"));
|
||||
Log.Write(
|
||||
" " + (attr.HasValue ? attr.Value.ToString("x8") : "n/a")
|
||||
);
|
||||
#endif
|
||||
});
|
||||
}
|
||||
);
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
@@ -1049,13 +1125,24 @@ namespace SharpCompress.Common.SevenZip
|
||||
#if DEBUG
|
||||
Log.Write("StartPos:");
|
||||
#endif
|
||||
ReadNumberVector(dataVector, numFiles, delegate (int i, long? startPos)
|
||||
{
|
||||
db._files[i].StartPos = startPos;
|
||||
ReadNumberVector(
|
||||
dataVector,
|
||||
numFiles,
|
||||
delegate(int i, long? startPos)
|
||||
{
|
||||
db._files[i].StartPos = startPos;
|
||||
#if DEBUG
|
||||
Log.Write(" " + (startPos.HasValue ? startPos.Value.ToString() : "n/a"));
|
||||
Log.Write(
|
||||
" "
|
||||
+ (
|
||||
startPos.HasValue
|
||||
? startPos.Value.ToString()
|
||||
: "n/a"
|
||||
)
|
||||
);
|
||||
#endif
|
||||
});
|
||||
}
|
||||
);
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
@@ -1064,13 +1151,19 @@ namespace SharpCompress.Common.SevenZip
|
||||
#if DEBUG
|
||||
Log.Write("CTime:");
|
||||
#endif
|
||||
ReadDateTimeVector(dataVector, numFiles, delegate (int i, DateTime? time)
|
||||
{
|
||||
db._files[i].CTime = time;
|
||||
ReadDateTimeVector(
|
||||
dataVector,
|
||||
numFiles,
|
||||
delegate(int i, DateTime? time)
|
||||
{
|
||||
db._files[i].CTime = time;
|
||||
#if DEBUG
|
||||
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
|
||||
Log.Write(
|
||||
" " + (time.HasValue ? time.Value.ToString() : "n/a")
|
||||
);
|
||||
#endif
|
||||
});
|
||||
}
|
||||
);
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
@@ -1079,13 +1172,19 @@ namespace SharpCompress.Common.SevenZip
|
||||
#if DEBUG
|
||||
Log.Write("ATime:");
|
||||
#endif
|
||||
ReadDateTimeVector(dataVector, numFiles, delegate (int i, DateTime? time)
|
||||
{
|
||||
db._files[i].ATime = time;
|
||||
ReadDateTimeVector(
|
||||
dataVector,
|
||||
numFiles,
|
||||
delegate(int i, DateTime? time)
|
||||
{
|
||||
db._files[i].ATime = time;
|
||||
#if DEBUG
|
||||
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
|
||||
Log.Write(
|
||||
" " + (time.HasValue ? time.Value.ToString() : "n/a")
|
||||
);
|
||||
#endif
|
||||
});
|
||||
}
|
||||
);
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
@@ -1094,13 +1193,19 @@ namespace SharpCompress.Common.SevenZip
|
||||
#if DEBUG
|
||||
Log.Write("MTime:");
|
||||
#endif
|
||||
ReadDateTimeVector(dataVector, numFiles, delegate (int i, DateTime? time)
|
||||
{
|
||||
db._files[i].MTime = time;
|
||||
ReadDateTimeVector(
|
||||
dataVector,
|
||||
numFiles,
|
||||
delegate(int i, DateTime? time)
|
||||
{
|
||||
db._files[i].MTime = time;
|
||||
#if DEBUG
|
||||
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
|
||||
Log.Write(
|
||||
" " + (time.HasValue ? time.Value.ToString() : "n/a")
|
||||
);
|
||||
#endif
|
||||
});
|
||||
}
|
||||
);
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
@@ -1175,7 +1280,7 @@ namespace SharpCompress.Common.SevenZip
|
||||
|
||||
// TODO: Check Signature!
|
||||
_header = new byte[0x20];
|
||||
for (int offset = 0; offset < 0x20;)
|
||||
for (int offset = 0; offset < 0x20; )
|
||||
{
|
||||
int delta = stream.Read(_header, offset, 0x20 - offset);
|
||||
if (delta == 0)
|
||||
@@ -1273,7 +1378,10 @@ namespace SharpCompress.Common.SevenZip
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
var dataVector = ReadAndDecodePackedStreams(db._startPositionAfterHeader, db.PasswordProvider);
|
||||
var dataVector = ReadAndDecodePackedStreams(
|
||||
db._startPositionAfterHeader,
|
||||
db.PasswordProvider
|
||||
);
|
||||
|
||||
// compressed header without content is odd but ok
|
||||
if (dataVector.Count == 0)
|
||||
@@ -1346,7 +1454,11 @@ namespace SharpCompress.Common.SevenZip
|
||||
|
||||
public override long Length => throw new NotSupportedException();
|
||||
|
||||
public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
|
||||
public override long Position
|
||||
{
|
||||
get => throw new NotSupportedException();
|
||||
set => throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
@@ -1369,7 +1481,10 @@ namespace SharpCompress.Common.SevenZip
|
||||
|
||||
private void ProcessEmptyFiles()
|
||||
{
|
||||
while (_currentIndex < _extractStatuses.Count && _db._files[_startIndex + _currentIndex].Size == 0)
|
||||
while (
|
||||
_currentIndex < _extractStatuses.Count
|
||||
&& _db._files[_startIndex + _currentIndex].Size == 0
|
||||
)
|
||||
{
|
||||
OpenFile();
|
||||
_stream.Dispose();
|
||||
@@ -1449,8 +1564,13 @@ namespace SharpCompress.Common.SevenZip
|
||||
packSizes[j] = db._packSizes[packStreamIndex + j];
|
||||
}
|
||||
|
||||
s = DecoderStreamHelper.CreateDecoderStream(_stream, folderStartPackPos, packSizes, folderInfo,
|
||||
db.PasswordProvider);
|
||||
s = DecoderStreamHelper.CreateDecoderStream(
|
||||
_stream,
|
||||
folderStartPackPos,
|
||||
packSizes,
|
||||
folderInfo,
|
||||
db.PasswordProvider
|
||||
);
|
||||
_cachedStreams.Add(folderIndex, s);
|
||||
}
|
||||
return s;
|
||||
@@ -1482,9 +1602,7 @@ namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
bool allFilesMode = (indices is null);
|
||||
|
||||
int numItems = allFilesMode
|
||||
? db._files.Count
|
||||
: indices.Length;
|
||||
int numItems = allFilesMode ? db._files.Count : indices.Length;
|
||||
|
||||
if (numItems == 0)
|
||||
{
|
||||
@@ -1503,7 +1621,10 @@ namespace SharpCompress.Common.SevenZip
|
||||
continue;
|
||||
}
|
||||
|
||||
if (extractFolderInfoVector.Count == 0 || folderIndex != extractFolderInfoVector.Last()._folderIndex)
|
||||
if (
|
||||
extractFolderInfoVector.Count == 0
|
||||
|| folderIndex != extractFolderInfoVector.Last()._folderIndex
|
||||
)
|
||||
{
|
||||
extractFolderInfoVector.Add(new CExtractFolderInfo(-1, folderIndex));
|
||||
}
|
||||
@@ -1511,7 +1632,11 @@ namespace SharpCompress.Common.SevenZip
|
||||
CExtractFolderInfo efi = extractFolderInfoVector.Last();
|
||||
|
||||
int startIndex = db._folderStartFileIndex[folderIndex];
|
||||
for (int index = efi._extractStatuses.Count; index <= fileIndex - startIndex; index++)
|
||||
for (
|
||||
int index = efi._extractStatuses.Count;
|
||||
index <= fileIndex - startIndex;
|
||||
index++
|
||||
)
|
||||
{
|
||||
efi._extractStatuses.Add(index == fileIndex - startIndex);
|
||||
}
|
||||
@@ -1552,8 +1677,13 @@ namespace SharpCompress.Common.SevenZip
|
||||
|
||||
// TODO: If the decoding fails the last file may be extracted incompletely. Delete it?
|
||||
|
||||
Stream s = DecoderStreamHelper.CreateDecoderStream(_stream, folderStartPackPos, packSizes,
|
||||
folderInfo, db.PasswordProvider);
|
||||
Stream s = DecoderStreamHelper.CreateDecoderStream(
|
||||
_stream,
|
||||
folderStartPackPos,
|
||||
packSizes,
|
||||
folderInfo,
|
||||
db.PasswordProvider
|
||||
);
|
||||
buffer ??= new byte[4 << 10];
|
||||
for (; ; )
|
||||
{
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
internal int _inIndex;
|
||||
internal int _outIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,4 +9,4 @@ namespace SharpCompress.Common.SevenZip
|
||||
internal int _numInStreams;
|
||||
internal int _numOutStreams;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,4 +35,4 @@ namespace SharpCompress.Common.SevenZip
|
||||
HasStream = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,4 +54,4 @@
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,4 +66,4 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,21 +12,21 @@ namespace SharpCompress.Common.SevenZip
|
||||
public static uint Get32(byte[] buffer, int offset)
|
||||
{
|
||||
return buffer[offset]
|
||||
+ ((uint)buffer[offset + 1] << 8)
|
||||
+ ((uint)buffer[offset + 2] << 16)
|
||||
+ ((uint)buffer[offset + 3] << 24);
|
||||
+ ((uint)buffer[offset + 1] << 8)
|
||||
+ ((uint)buffer[offset + 2] << 16)
|
||||
+ ((uint)buffer[offset + 3] << 24);
|
||||
}
|
||||
|
||||
public static ulong Get64(byte[] buffer, int offset)
|
||||
{
|
||||
return buffer[offset]
|
||||
+ ((ulong)buffer[offset + 1] << 8)
|
||||
+ ((ulong)buffer[offset + 2] << 16)
|
||||
+ ((ulong)buffer[offset + 3] << 24)
|
||||
+ ((ulong)buffer[offset + 4] << 32)
|
||||
+ ((ulong)buffer[offset + 5] << 40)
|
||||
+ ((ulong)buffer[offset + 6] << 48)
|
||||
+ ((ulong)buffer[offset + 7] << 56);
|
||||
+ ((ulong)buffer[offset + 1] << 8)
|
||||
+ ((ulong)buffer[offset + 2] << 16)
|
||||
+ ((ulong)buffer[offset + 3] << 24)
|
||||
+ ((ulong)buffer[offset + 4] << 32)
|
||||
+ ((ulong)buffer[offset + 5] << 40)
|
||||
+ ((ulong)buffer[offset + 6] << 48)
|
||||
+ ((ulong)buffer[offset + 7] << 56);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -183,4 +183,4 @@ namespace SharpCompress.Common.SevenZip
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,8 +38,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
|
||||
public override bool IsSplitAfter => false;
|
||||
|
||||
public override int? Attrib => FilePart.Header.Attrib.HasValue ? (int?)FilePart.Header.Attrib.Value : null;
|
||||
public override int? Attrib =>
|
||||
FilePart.Header.Attrib.HasValue ? (int?)FilePart.Header.Attrib.Value : null;
|
||||
|
||||
internal override IEnumerable<FilePart> Parts => FilePart.AsEnumerable<FilePart>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,13 @@ namespace SharpCompress.Common.SevenZip
|
||||
private readonly Stream _stream;
|
||||
private readonly ArchiveDatabase _database;
|
||||
|
||||
internal SevenZipFilePart(Stream stream, ArchiveDatabase database, int index, CFileItem fileEntry, ArchiveEncoding archiveEncoding)
|
||||
: base(archiveEncoding)
|
||||
internal SevenZipFilePart(
|
||||
Stream stream,
|
||||
ArchiveDatabase database,
|
||||
int index,
|
||||
CFileItem fileEntry,
|
||||
ArchiveEncoding archiveEncoding
|
||||
) : base(archiveEncoding)
|
||||
{
|
||||
_stream = stream;
|
||||
_database = database;
|
||||
@@ -40,9 +45,15 @@ namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
return null!;
|
||||
}
|
||||
var folderStream = _database.GetFolderStream(_stream, Folder!, _database.PasswordProvider);
|
||||
var folderStream = _database.GetFolderStream(
|
||||
_stream,
|
||||
Folder!,
|
||||
_database.PasswordProvider
|
||||
);
|
||||
|
||||
int firstFileIndex = _database._folderStartFileIndex[_database._folders.IndexOf(Folder!)];
|
||||
int firstFileIndex = _database._folderStartFileIndex[
|
||||
_database._folders.IndexOf(Folder!)
|
||||
];
|
||||
int skipCount = Index - firstFileIndex;
|
||||
long skipSize = 0;
|
||||
for (int i = 0; i < skipCount; i++)
|
||||
@@ -86,22 +97,23 @@ namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
case K_LZMA:
|
||||
case K_LZMA2:
|
||||
{
|
||||
return CompressionType.LZMA;
|
||||
}
|
||||
{
|
||||
return CompressionType.LZMA;
|
||||
}
|
||||
case K_PPMD:
|
||||
{
|
||||
return CompressionType.PPMd;
|
||||
}
|
||||
{
|
||||
return CompressionType.PPMd;
|
||||
}
|
||||
case K_B_ZIP2:
|
||||
{
|
||||
return CompressionType.BZip2;
|
||||
}
|
||||
{
|
||||
return CompressionType.BZip2;
|
||||
}
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
internal bool IsEncrypted => Folder!._coders.FindIndex(c => c._methodId._id == CMethodId.K_AES_ID) != -1;
|
||||
internal bool IsEncrypted =>
|
||||
Folder!._coders.FindIndex(c => c._methodId._id == CMethodId.K_AES_ID) != -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,6 @@ namespace SharpCompress.Common.SevenZip
|
||||
public class SevenZipVolume : Volume
|
||||
{
|
||||
public SevenZipVolume(Stream stream, ReaderOptions readerFactoryOptions, int index = 0)
|
||||
: base(stream, readerFactoryOptions, index)
|
||||
{
|
||||
}
|
||||
: base(stream, readerFactoryOptions, index) { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,4 +16,4 @@
|
||||
VolumeHeader = (byte)'V',
|
||||
GlobalExtendedHeader = (byte)'g'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,15 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
{
|
||||
internal sealed class TarHeader
|
||||
{
|
||||
internal static readonly DateTime EPOCH = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
internal static readonly DateTime EPOCH = new DateTime(
|
||||
1970,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
DateTimeKind.Utc
|
||||
);
|
||||
|
||||
public TarHeader(ArchiveEncoding archiveEncoding)
|
||||
{
|
||||
@@ -79,7 +87,11 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
// var truncated = Encoding.UTF8.GetBytes(Encoding.UTF8.GetString(bytes, 0, 100));
|
||||
//
|
||||
// and then infinite recursion is occured in WriteLongFilenameHeader because truncated.Length is 102.
|
||||
Name = ArchiveEncoding.Decode(ArchiveEncoding.Encode(Name), 0, 100 - ArchiveEncoding.GetEncoding().GetMaxByteCount(1));
|
||||
Name = ArchiveEncoding.Decode(
|
||||
ArchiveEncoding.Encode(Name),
|
||||
0,
|
||||
100 - ArchiveEncoding.GetEncoding().GetMaxByteCount(1)
|
||||
);
|
||||
Write(output);
|
||||
}
|
||||
}
|
||||
@@ -126,7 +138,7 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
Size = ReadSize(buffer);
|
||||
|
||||
Mode = ReadAsciiInt64Base8(buffer, 100, 7);
|
||||
if(EntryType == EntryType.Directory)
|
||||
if (EntryType == EntryType.Directory)
|
||||
Mode |= 0b1_000_000_000;
|
||||
|
||||
UserId = ReadAsciiInt64Base8(buffer, 108, 7);
|
||||
@@ -136,8 +148,7 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
|
||||
Magic = ArchiveEncoding.Decode(buffer, 257, 6).TrimNulls();
|
||||
|
||||
if (!string.IsNullOrEmpty(Magic)
|
||||
&& "ustar".Equals(Magic))
|
||||
if (!string.IsNullOrEmpty(Magic) && "ustar".Equals(Magic))
|
||||
{
|
||||
string namePrefix = ArchiveEncoding.Decode(buffer, 345, 157);
|
||||
namePrefix = namePrefix.TrimNulls();
|
||||
@@ -146,8 +157,7 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
Name = namePrefix + "/" + Name;
|
||||
}
|
||||
}
|
||||
if (EntryType != EntryType.LongName
|
||||
&& Name.Length == 0)
|
||||
if (EntryType != EntryType.LongName && Name.Length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -261,10 +271,16 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
return Convert.ToInt64(s);
|
||||
}
|
||||
|
||||
|
||||
private static readonly byte[] eightSpaces = {
|
||||
(byte)' ', (byte)' ', (byte)' ', (byte)' ',
|
||||
(byte)' ', (byte)' ', (byte)' ', (byte)' '
|
||||
private static readonly byte[] eightSpaces =
|
||||
{
|
||||
(byte)' ',
|
||||
(byte)' ',
|
||||
(byte)' ',
|
||||
(byte)' ',
|
||||
(byte)' ',
|
||||
(byte)' ',
|
||||
(byte)' ',
|
||||
(byte)' '
|
||||
};
|
||||
|
||||
internal static int RecalculateChecksum(byte[] buf)
|
||||
|
||||
@@ -47,13 +47,17 @@ namespace SharpCompress.Common.Tar
|
||||
public long Mode => _filePart.Header.Mode;
|
||||
|
||||
public long UserID => _filePart.Header.UserId;
|
||||
|
||||
|
||||
public long GroupId => _filePart.Header.GroupId;
|
||||
|
||||
internal override IEnumerable<FilePart> Parts => _filePart.AsEnumerable<FilePart>();
|
||||
|
||||
internal static IEnumerable<TarEntry> GetEntries(StreamingMode mode, Stream stream,
|
||||
CompressionType compressionType, ArchiveEncoding archiveEncoding)
|
||||
internal static IEnumerable<TarEntry> GetEntries(
|
||||
StreamingMode mode,
|
||||
Stream stream,
|
||||
CompressionType compressionType,
|
||||
ArchiveEncoding archiveEncoding
|
||||
)
|
||||
{
|
||||
foreach (TarHeader h in TarHeaderFactory.ReadHeader(mode, stream, archiveEncoding))
|
||||
{
|
||||
@@ -71,4 +75,4 @@ namespace SharpCompress.Common.Tar
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,7 @@ namespace SharpCompress.Common.Tar
|
||||
{
|
||||
private readonly Stream _seekableStream;
|
||||
|
||||
internal TarFilePart(TarHeader header, Stream seekableStream)
|
||||
: base(header.ArchiveEncoding)
|
||||
internal TarFilePart(TarHeader header, Stream seekableStream) : base(header.ArchiveEncoding)
|
||||
{
|
||||
_seekableStream = seekableStream;
|
||||
Header = header;
|
||||
@@ -34,4 +33,4 @@ namespace SharpCompress.Common.Tar
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,11 @@ namespace SharpCompress.Common.Tar
|
||||
{
|
||||
internal static class TarHeaderFactory
|
||||
{
|
||||
internal static IEnumerable<TarHeader?> ReadHeader(StreamingMode mode, Stream stream, ArchiveEncoding archiveEncoding)
|
||||
internal static IEnumerable<TarHeader?> ReadHeader(
|
||||
StreamingMode mode,
|
||||
Stream stream,
|
||||
ArchiveEncoding archiveEncoding
|
||||
)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
@@ -24,6 +28,7 @@ namespace SharpCompress.Common.Tar
|
||||
switch (mode)
|
||||
{
|
||||
case StreamingMode.Seekable:
|
||||
|
||||
{
|
||||
header.DataStartPosition = reader.BaseStream.Position;
|
||||
|
||||
@@ -32,14 +37,15 @@ namespace SharpCompress.Common.Tar
|
||||
}
|
||||
break;
|
||||
case StreamingMode.Streaming:
|
||||
|
||||
{
|
||||
header.PackedStream = new TarReadOnlySubStream(stream, header.Size);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
throw new InvalidFormatException("Invalid StreamingMode");
|
||||
}
|
||||
{
|
||||
throw new InvalidFormatException("Invalid StreamingMode");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
@@ -60,4 +66,4 @@ namespace SharpCompress.Common.Tar
|
||||
return 512 - zeros + size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@ namespace SharpCompress.Common.Tar
|
||||
private bool _isDisposed;
|
||||
private long _amountRead;
|
||||
|
||||
public TarReadOnlySubStream(Stream stream, long bytesToRead) : base(stream, throwOnDispose: false)
|
||||
public TarReadOnlySubStream(Stream stream, long bytesToRead)
|
||||
: base(stream, throwOnDispose: false)
|
||||
{
|
||||
BytesLeftToRead = bytesToRead;
|
||||
}
|
||||
@@ -56,7 +57,11 @@ namespace SharpCompress.Common.Tar
|
||||
|
||||
public override long Length => throw new NotSupportedException();
|
||||
|
||||
public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
|
||||
public override long Position
|
||||
{
|
||||
get => throw new NotSupportedException();
|
||||
set => throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
@@ -86,7 +91,6 @@ namespace SharpCompress.Common.Tar
|
||||
++_amountRead;
|
||||
}
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
@@ -104,4 +108,4 @@ namespace SharpCompress.Common.Tar
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,6 @@ namespace SharpCompress.Common.Tar
|
||||
public class TarVolume : Volume
|
||||
{
|
||||
public TarVolume(Stream stream, ReaderOptions readerOptions, int index = 0)
|
||||
: base(stream, readerOptions, index)
|
||||
{
|
||||
}
|
||||
: base(stream, readerOptions, index) { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,10 @@ namespace SharpCompress.Common
|
||||
|
||||
public virtual int Index { get; internal set; }
|
||||
|
||||
public string FileName { get { return (_actualStream as FileStream)?.Name!; } }
|
||||
public string FileName
|
||||
{
|
||||
get { return (_actualStream as FileStream)?.Name!; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RarArchive is part of a multi-part archive.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user