mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-02-05 13:34:59 +00:00
Compare commits
49 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eee8309db8 | ||
|
|
155cfab792 | ||
|
|
e1c36afdec | ||
|
|
6b0d6a41ca | ||
|
|
dab157bb71 | ||
|
|
8d17d09455 | ||
|
|
05208ccd9b | ||
|
|
a1e7c0068d | ||
|
|
e6bec19946 | ||
|
|
ec2be2869f | ||
|
|
ce5432ed73 | ||
|
|
b6e0ad89ce | ||
|
|
2745bfa19b | ||
|
|
3cdc4b38a6 | ||
|
|
fc1ca808d7 | ||
|
|
6983e66037 | ||
|
|
01f7336d09 | ||
|
|
1561bba538 | ||
|
|
3ecf8a5e0c | ||
|
|
e2095fc416 | ||
|
|
8398d40106 | ||
|
|
134fa8892f | ||
|
|
ea5c8dc063 | ||
|
|
0209d00164 | ||
|
|
a8d065dc9e | ||
|
|
7bd9711ade | ||
|
|
61802eadb4 | ||
|
|
b425659058 | ||
|
|
3e32e3d7b1 | ||
|
|
1b661c9df1 | ||
|
|
54fc26b93d | ||
|
|
161f99bbad | ||
|
|
c012db0776 | ||
|
|
8ee257d299 | ||
|
|
f9522107c3 | ||
|
|
e07046a37a | ||
|
|
ad6d0d9ae8 | ||
|
|
fdc33e91bd | ||
|
|
a34f5a855c | ||
|
|
6474741af1 | ||
|
|
c10bd840c5 | ||
|
|
e6dded826b | ||
|
|
8a022c4b18 | ||
|
|
cfef228afc | ||
|
|
237ff9f055 | ||
|
|
020f862814 | ||
|
|
fa6107200d | ||
|
|
eb81f972c4 | ||
|
|
93c1ff396e |
6
.github/workflows/dotnetcore.yml
vendored
6
.github/workflows/dotnetcore.yml
vendored
@@ -12,13 +12,9 @@ jobs:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: 5.0.101
|
||||
dotnet-version: 5.0.401
|
||||
- run: dotnet run -p build/build.csproj
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ${{ matrix.os }}-sharpcompress.nupkg
|
||||
path: artifacts/*
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ${{ matrix.os }}-sharpcompress.snupkg
|
||||
path: artifacts/*
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
| Tar.XZ | LZMA2 | Decompress | TarArchive | TarReader | TarWriter (3) |
|
||||
| GZip (single file) | DEFLATE | Both | GZipArchive | GZipReader | GZipWriter |
|
||||
| 7Zip (4) | LZMA, LZMA2, BZip2, PPMd, BCJ, BCJ2, Deflate | Decompress | SevenZipArchive | N/A | N/A |
|
||||
| LZip (single file) (5) | LZip (LZMA) | Both | LZipArchive | LZipReader | LZipWriter |
|
||||
|
||||
1. SOLID Rars are only supported in the RarReader API.
|
||||
2. Zip format supports pkware and WinzipAES encryption. However, encrypted LZMA is not supported. Zip64 reading/writing is supported but only with seekable streams as the Zip spec doesn't support Zip64 data in post data descriptors. Deflate64 is only supported for reading.
|
||||
|
||||
@@ -49,20 +49,20 @@ class Program
|
||||
Target(Build, DependsOn(Format),
|
||||
framework =>
|
||||
{
|
||||
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && framework == "net46")
|
||||
{
|
||||
return;
|
||||
}
|
||||
Run("dotnet", "build src/SharpCompress/SharpCompress.csproj -c Release");
|
||||
});
|
||||
|
||||
Target(Test, DependsOn(Build), ForEach("net5.0"),
|
||||
Target(Test, DependsOn(Build), ForEach("net5.0", "net461"),
|
||||
framework =>
|
||||
{
|
||||
IEnumerable<string> GetFiles(string d)
|
||||
{
|
||||
return Glob.Files(".", d);
|
||||
}
|
||||
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && framework == "net461")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var file in GetFiles("**/*.Test.csproj"))
|
||||
{
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Bullseye" Version="3.6.0" />
|
||||
<PackageReference Include="Bullseye" Version="3.8.0" />
|
||||
<PackageReference Include="Glob" Version="1.1.8" />
|
||||
<PackageReference Include="SimpleExec" Version="6.4.0" />
|
||||
<PackageReference Include="SimpleExec" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"sdk": {
|
||||
"version": "5.0.101"
|
||||
"version": "5.0.300",
|
||||
"rollForward": "latestFeature"
|
||||
}
|
||||
}
|
||||
420
src/SharpCompress/Algorithms/Adler32.cs
Normal file
420
src/SharpCompress/Algorithms/Adler32.cs
Normal file
@@ -0,0 +1,420 @@
|
||||
// Copyright (c) Six Labors.
|
||||
// Licensed under the Apache License, Version 2.0.
|
||||
|
||||
#if !NETSTANDARD2_0 && !NETSTANDARD2_1 && !NETFRAMEWORK
|
||||
#define SUPPORTS_RUNTIME_INTRINSICS
|
||||
#define SUPPORTS_HOTPATH
|
||||
#endif
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
#if SUPPORTS_RUNTIME_INTRINSICS
|
||||
using System.Runtime.Intrinsics;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
#endif
|
||||
|
||||
#pragma warning disable IDE0007 // Use implicit type
|
||||
namespace SharpCompress.Algorithms
|
||||
{
|
||||
/// <summary>
|
||||
/// Calculates the 32 bit Adler checksum of a given buffer according to
|
||||
/// RFC 1950. ZLIB Compressed Data Format Specification version 3.3)
|
||||
/// </summary>
|
||||
internal static class Adler32 // From https://github.com/SixLabors/ImageSharp/blob/main/src/ImageSharp/Compression/Zlib/Adler32.cs
|
||||
{
|
||||
/// <summary>
|
||||
/// Global inlining options. Helps temporarily disable inlining for better profiler output.
|
||||
/// </summary>
|
||||
private static class InliningOptions // From https://github.com/SixLabors/ImageSharp/blob/main/src/ImageSharp/Common/Helpers/InliningOptions.cs
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="MethodImplOptions.AggressiveInlining"/> regardless of the build conditions.
|
||||
/// </summary>
|
||||
public const MethodImplOptions AlwaysInline = MethodImplOptions.AggressiveInlining;
|
||||
#if PROFILING
|
||||
public const MethodImplOptions HotPath = MethodImplOptions.NoInlining;
|
||||
public const MethodImplOptions ShortMethod = MethodImplOptions.NoInlining;
|
||||
#else
|
||||
#if SUPPORTS_HOTPATH
|
||||
public const MethodImplOptions HotPath = MethodImplOptions.AggressiveOptimization;
|
||||
#else
|
||||
public const MethodImplOptions HotPath = MethodImplOptions.AggressiveInlining;
|
||||
#endif
|
||||
public const MethodImplOptions ShortMethod = MethodImplOptions.AggressiveInlining;
|
||||
#endif
|
||||
public const MethodImplOptions ColdPath = MethodImplOptions.NoInlining;
|
||||
}
|
||||
|
||||
#if SUPPORTS_RUNTIME_INTRINSICS
|
||||
/// <summary>
|
||||
/// Provides optimized static methods for trigonometric, logarithmic,
|
||||
/// and other common mathematical functions.
|
||||
/// </summary>
|
||||
private static class Numerics // From https://github.com/SixLabors/ImageSharp/blob/main/src/ImageSharp/Common/Helpers/Numerics.cs
|
||||
{
|
||||
/// <summary>
|
||||
/// Reduces elements of the vector into one sum.
|
||||
/// </summary>
|
||||
/// <param name="accumulator">The accumulator to reduce.</param>
|
||||
/// <returns>The sum of all elements.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int ReduceSum(Vector256<int> accumulator)
|
||||
{
|
||||
// Add upper lane to lower lane.
|
||||
Vector128<int> vsum = Sse2.Add(accumulator.GetLower(), accumulator.GetUpper());
|
||||
|
||||
// Add odd to even.
|
||||
vsum = Sse2.Add(vsum, Sse2.Shuffle(vsum, 0b_11_11_01_01));
|
||||
|
||||
// Add high to low.
|
||||
vsum = Sse2.Add(vsum, Sse2.Shuffle(vsum, 0b_11_10_11_10));
|
||||
|
||||
return Sse2.ConvertToInt32(vsum);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reduces even elements of the vector into one sum.
|
||||
/// </summary>
|
||||
/// <param name="accumulator">The accumulator to reduce.</param>
|
||||
/// <returns>The sum of even elements.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
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
|
||||
|
||||
// Vector128<int>.ToScalar() isn't optimized pre-net5.0 https://github.com/dotnet/runtime/pull/37882
|
||||
return Sse2.ConvertToInt32(vsum);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// The default initial seed value of a Adler32 checksum calculation.
|
||||
/// </summary>
|
||||
public const uint SeedValue = 1U;
|
||||
|
||||
// Largest prime smaller than 65536
|
||||
private const uint BASE = 65521;
|
||||
|
||||
// NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
|
||||
private const uint NMAX = 5552;
|
||||
|
||||
#if SUPPORTS_RUNTIME_INTRINSICS
|
||||
private const int MinBufferSize = 64;
|
||||
|
||||
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
|
||||
};
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the Adler32 checksum with the bytes taken from the span.
|
||||
/// </summary>
|
||||
/// <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);
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the Adler32 checksum with the bytes taken from the span and seed.
|
||||
/// </summary>
|
||||
/// <param name="adler">The input Adler32 value.</param>
|
||||
/// <param name="buffer">The readonly span of bytes.</param>
|
||||
/// <returns>The <see cref="uint"/>.</returns>
|
||||
[MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)]
|
||||
public static uint Calculate(uint adler, ReadOnlySpan<byte> buffer)
|
||||
{
|
||||
if (buffer.IsEmpty)
|
||||
{
|
||||
return adler;
|
||||
}
|
||||
|
||||
#if SUPPORTS_RUNTIME_INTRINSICS
|
||||
if (Avx2.IsSupported && buffer.Length >= MinBufferSize)
|
||||
{
|
||||
return CalculateAvx2(adler, buffer);
|
||||
}
|
||||
|
||||
if (Ssse3.IsSupported && buffer.Length >= MinBufferSize)
|
||||
{
|
||||
return CalculateSse(adler, buffer);
|
||||
}
|
||||
|
||||
return CalculateScalar(adler, buffer);
|
||||
#else
|
||||
return CalculateScalar(adler, buffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Based on https://github.com/chromium/chromium/blob/master/third_party/zlib/adler32_simd.c
|
||||
#if SUPPORTS_RUNTIME_INTRINSICS
|
||||
[MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)]
|
||||
private static unsafe uint CalculateSse(uint adler, ReadOnlySpan<byte> buffer)
|
||||
{
|
||||
uint s1 = adler & 0xFFFF;
|
||||
uint s2 = (adler >> 16) & 0xFFFF;
|
||||
|
||||
// Process the data in blocks.
|
||||
uint length = (uint)buffer.Length;
|
||||
uint blocks = length / BlockSize;
|
||||
length -= blocks * BlockSize;
|
||||
|
||||
fixed (byte* bufferPtr = &MemoryMarshal.GetReference(buffer))
|
||||
{
|
||||
fixed (byte* tapPtr = &MemoryMarshal.GetReference(Tap1Tap2))
|
||||
{
|
||||
byte* localBufferPtr = bufferPtr;
|
||||
|
||||
// _mm_setr_epi8 on x86
|
||||
Vector128<sbyte> tap1 = Sse2.LoadVector128((sbyte*)tapPtr);
|
||||
Vector128<sbyte> tap2 = Sse2.LoadVector128((sbyte*)(tapPtr + 0x10));
|
||||
Vector128<byte> zero = Vector128<byte>.Zero;
|
||||
var ones = Vector128.Create((short)1);
|
||||
|
||||
while (blocks > 0)
|
||||
{
|
||||
uint n = NMAX / BlockSize; /* The NMAX constraint. */
|
||||
if (n > blocks)
|
||||
{
|
||||
n = blocks;
|
||||
}
|
||||
|
||||
blocks -= n;
|
||||
|
||||
// Process n blocks of data. At most NMAX data bytes can be
|
||||
// processed before s2 must be reduced modulo BASE.
|
||||
Vector128<uint> v_ps = Vector128.CreateScalar(s1 * n);
|
||||
Vector128<uint> v_s2 = Vector128.CreateScalar(s2);
|
||||
Vector128<uint> v_s1 = Vector128<uint>.Zero;
|
||||
|
||||
do
|
||||
{
|
||||
// Load 32 input bytes.
|
||||
Vector128<byte> bytes1 = Sse3.LoadDquVector128(localBufferPtr);
|
||||
Vector128<byte> bytes2 = Sse3.LoadDquVector128(localBufferPtr + 0x10);
|
||||
|
||||
// Add previous block byte sum to v_ps.
|
||||
v_ps = Sse2.Add(v_ps, v_s1);
|
||||
|
||||
// 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());
|
||||
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());
|
||||
Vector128<short> mad2 = Ssse3.MultiplyAddAdjacent(bytes2, tap2);
|
||||
v_s2 = Sse2.Add(v_s2, Sse2.MultiplyAddAdjacent(mad2, ones).AsUInt32());
|
||||
|
||||
localBufferPtr += BlockSize;
|
||||
}
|
||||
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
|
||||
|
||||
v_s1 = Sse2.Add(v_s1, Sse2.Shuffle(v_s1, S1032));
|
||||
|
||||
s1 += v_s1.ToScalar();
|
||||
|
||||
v_s2 = Sse2.Add(v_s2, Sse2.Shuffle(v_s2, S2301));
|
||||
v_s2 = Sse2.Add(v_s2, Sse2.Shuffle(v_s2, S1032));
|
||||
|
||||
s2 = v_s2.ToScalar();
|
||||
|
||||
// Reduce.
|
||||
s1 %= BASE;
|
||||
s2 %= BASE;
|
||||
}
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
HandleLeftOver(localBufferPtr, length, ref s1, ref s2);
|
||||
}
|
||||
|
||||
return s1 | (s2 << 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Based on: https://github.com/zlib-ng/zlib-ng/blob/develop/arch/x86/adler32_avx2.c
|
||||
[MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)]
|
||||
public static unsafe uint CalculateAvx2(uint adler, ReadOnlySpan<byte> buffer)
|
||||
{
|
||||
uint s1 = adler & 0xFFFF;
|
||||
uint s2 = (adler >> 16) & 0xFFFF;
|
||||
uint length = (uint)buffer.Length;
|
||||
|
||||
fixed (byte* bufferPtr = &MemoryMarshal.GetReference(buffer))
|
||||
{
|
||||
byte* localBufferPtr = bufferPtr;
|
||||
|
||||
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);
|
||||
|
||||
// Process n blocks of data. At most NMAX data bytes can be
|
||||
// processed before s2 must be reduced modulo BASE.
|
||||
var vs1 = Vector256.CreateScalar(s1);
|
||||
var vs2 = Vector256.CreateScalar(s2);
|
||||
|
||||
while (length >= 32)
|
||||
{
|
||||
int k = length < NMAX ? (int)length : (int)NMAX;
|
||||
k -= k % 32;
|
||||
length -= (uint)k;
|
||||
|
||||
Vector256<uint> vs10 = vs1;
|
||||
Vector256<uint> vs3 = Vector256<uint>.Zero;
|
||||
|
||||
while (k >= 32)
|
||||
{
|
||||
// Load 32 input bytes.
|
||||
Vector256<byte> block = Avx.LoadVector256(localBufferPtr);
|
||||
|
||||
// Sum of abs diff, resulting in 2 x int32's
|
||||
Vector256<ushort> vs1sad = Avx2.SumAbsoluteDifferences(block, zero);
|
||||
|
||||
vs1 = Avx2.Add(vs1, vs1sad.AsUInt32());
|
||||
vs3 = Avx2.Add(vs3, vs10);
|
||||
|
||||
// sum 32 uint8s to 16 shorts.
|
||||
Vector256<short> vshortsum2 = Avx2.MultiplyAddAdjacent(block, dot2v);
|
||||
|
||||
// sum 16 shorts to 8 uint32s.
|
||||
Vector256<int> vsum2 = Avx2.MultiplyAddAdjacent(vshortsum2, dot3v);
|
||||
|
||||
vs2 = Avx2.Add(vsum2.AsUInt32(), vs2);
|
||||
vs10 = vs1;
|
||||
|
||||
localBufferPtr += BlockSize;
|
||||
k -= 32;
|
||||
}
|
||||
|
||||
// Defer the multiplication with 32 to outside of the loop.
|
||||
vs3 = Avx2.ShiftLeftLogical(vs3, 5);
|
||||
vs2 = Avx2.Add(vs2, vs3);
|
||||
|
||||
s1 = (uint)Numerics.EvenReduceSum(vs1.AsInt32());
|
||||
s2 = (uint)Numerics.ReduceSum(vs2.AsInt32());
|
||||
|
||||
s1 %= BASE;
|
||||
s2 %= BASE;
|
||||
|
||||
vs1 = Vector256.CreateScalar(s1);
|
||||
vs2 = Vector256.CreateScalar(s2);
|
||||
}
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
HandleLeftOver(localBufferPtr, length, ref s1, ref s2);
|
||||
}
|
||||
|
||||
return s1 | (s2 << 16);
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe void HandleLeftOver(byte* localBufferPtr, uint length, ref uint s1, ref uint s2)
|
||||
{
|
||||
if (length >= 16)
|
||||
{
|
||||
s2 += s1 += localBufferPtr[0];
|
||||
s2 += s1 += localBufferPtr[1];
|
||||
s2 += s1 += localBufferPtr[2];
|
||||
s2 += s1 += localBufferPtr[3];
|
||||
s2 += s1 += localBufferPtr[4];
|
||||
s2 += s1 += localBufferPtr[5];
|
||||
s2 += s1 += localBufferPtr[6];
|
||||
s2 += s1 += localBufferPtr[7];
|
||||
s2 += s1 += localBufferPtr[8];
|
||||
s2 += s1 += localBufferPtr[9];
|
||||
s2 += s1 += localBufferPtr[10];
|
||||
s2 += s1 += localBufferPtr[11];
|
||||
s2 += s1 += localBufferPtr[12];
|
||||
s2 += s1 += localBufferPtr[13];
|
||||
s2 += s1 += localBufferPtr[14];
|
||||
s2 += s1 += localBufferPtr[15];
|
||||
|
||||
localBufferPtr += 16;
|
||||
length -= 16;
|
||||
}
|
||||
|
||||
while (length-- > 0)
|
||||
{
|
||||
s2 += s1 += *localBufferPtr++;
|
||||
}
|
||||
|
||||
if (s1 >= BASE)
|
||||
{
|
||||
s1 -= BASE;
|
||||
}
|
||||
|
||||
s2 %= BASE;
|
||||
}
|
||||
#endif
|
||||
|
||||
[MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)]
|
||||
private static unsafe uint CalculateScalar(uint adler, ReadOnlySpan<byte> buffer)
|
||||
{
|
||||
uint s1 = adler & 0xFFFF;
|
||||
uint s2 = (adler >> 16) & 0xFFFF;
|
||||
uint k;
|
||||
|
||||
fixed (byte* bufferPtr = buffer)
|
||||
{
|
||||
var localBufferPtr = bufferPtr;
|
||||
uint length = (uint)buffer.Length;
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
k = length < NMAX ? length : NMAX;
|
||||
length -= k;
|
||||
|
||||
while (k >= 16)
|
||||
{
|
||||
s2 += s1 += localBufferPtr[0];
|
||||
s2 += s1 += localBufferPtr[1];
|
||||
s2 += s1 += localBufferPtr[2];
|
||||
s2 += s1 += localBufferPtr[3];
|
||||
s2 += s1 += localBufferPtr[4];
|
||||
s2 += s1 += localBufferPtr[5];
|
||||
s2 += s1 += localBufferPtr[6];
|
||||
s2 += s1 += localBufferPtr[7];
|
||||
s2 += s1 += localBufferPtr[8];
|
||||
s2 += s1 += localBufferPtr[9];
|
||||
s2 += s1 += localBufferPtr[10];
|
||||
s2 += s1 += localBufferPtr[11];
|
||||
s2 += s1 += localBufferPtr[12];
|
||||
s2 += s1 += localBufferPtr[13];
|
||||
s2 += s1 += localBufferPtr[14];
|
||||
s2 += s1 += localBufferPtr[15];
|
||||
|
||||
localBufferPtr += 16;
|
||||
k -= 16;
|
||||
}
|
||||
|
||||
while (k-- > 0)
|
||||
{
|
||||
s2 += s1 += *localBufferPtr++;
|
||||
}
|
||||
|
||||
s1 %= BASE;
|
||||
s2 %= BASE;
|
||||
}
|
||||
|
||||
return (s2 << 16) | s1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,285 +0,0 @@
|
||||
// Copyright (c) Six Labors and contributors.
|
||||
// Licensed under the GNU Affero General Public License, Version 3.
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
#if !NETSTANDARD2_0 && !NETSTANDARD2_1
|
||||
using System.Runtime.Intrinsics;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
#endif
|
||||
|
||||
namespace SharpCompress.Algorithms
|
||||
{
|
||||
/// <summary>
|
||||
/// Calculates the 32 bit Adler checksum of a given buffer according to
|
||||
/// RFC 1950. ZLIB Compressed Data Format Specification version 3.3)
|
||||
/// </summary>
|
||||
internal static class Adler32
|
||||
{
|
||||
/// <summary>
|
||||
/// The default initial seed value of a Adler32 checksum calculation.
|
||||
/// </summary>
|
||||
public const uint SeedValue = 1U;
|
||||
|
||||
#if !NETSTANDARD2_0 && !NETSTANDARD2_1
|
||||
private const int MinBufferSize = 64;
|
||||
#endif
|
||||
|
||||
// Largest prime smaller than 65536
|
||||
private const uint BASE = 65521;
|
||||
|
||||
// NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
|
||||
private const uint NMAX = 5552;
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the Adler32 checksum with the bytes taken from the span.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The readonly span of bytes.</param>
|
||||
/// <returns>The <see cref="uint"/>.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint Calculate(ReadOnlySpan<byte> buffer)
|
||||
{
|
||||
return Calculate(SeedValue, buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the Adler32 checksum with the bytes taken from the span and seed.
|
||||
/// </summary>
|
||||
/// <param name="adler">The input Adler32 value.</param>
|
||||
/// <param name="buffer">The readonly span of bytes.</param>
|
||||
/// <returns>The <see cref="uint"/>.</returns>
|
||||
public static uint Calculate(uint adler, ReadOnlySpan<byte> buffer)
|
||||
{
|
||||
if (buffer.IsEmpty)
|
||||
{
|
||||
return SeedValue;
|
||||
}
|
||||
|
||||
#if !NETSTANDARD2_0 && !NETSTANDARD2_1
|
||||
if (Sse3.IsSupported && buffer.Length >= MinBufferSize)
|
||||
{
|
||||
return CalculateSse(adler, buffer);
|
||||
}
|
||||
|
||||
return CalculateScalar(adler, buffer);
|
||||
#else
|
||||
return CalculateScalar(adler, buffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Based on https://github.com/chromium/chromium/blob/master/third_party/zlib/adler32_simd.c
|
||||
#if !NETSTANDARD2_0 && !NETSTANDARD2_1
|
||||
private static unsafe uint CalculateSse(uint adler, ReadOnlySpan<byte> buffer)
|
||||
{
|
||||
uint s1 = adler & 0xFFFF;
|
||||
uint s2 = (adler >> 16) & 0xFFFF;
|
||||
|
||||
// Process the data in blocks.
|
||||
const int BLOCK_SIZE = 1 << 5;
|
||||
|
||||
uint length = (uint)buffer.Length;
|
||||
uint blocks = length / BLOCK_SIZE;
|
||||
length -= blocks * BLOCK_SIZE;
|
||||
|
||||
int index = 0;
|
||||
fixed (byte* bufferPtr = &buffer[0])
|
||||
{
|
||||
index += (int)blocks * BLOCK_SIZE;
|
||||
var localBufferPtr = bufferPtr;
|
||||
|
||||
// _mm_setr_epi8 on x86
|
||||
var tap1 = Vector128.Create(32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17);
|
||||
var tap2 = Vector128.Create(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1);
|
||||
Vector128<byte> zero = Vector128<byte>.Zero;
|
||||
var ones = Vector128.Create((short)1);
|
||||
|
||||
while (blocks > 0)
|
||||
{
|
||||
uint n = NMAX / BLOCK_SIZE; /* The NMAX constraint. */
|
||||
if (n > blocks)
|
||||
{
|
||||
n = blocks;
|
||||
}
|
||||
|
||||
blocks -= n;
|
||||
|
||||
// Process n blocks of data. At most NMAX data bytes can be
|
||||
// processed before s2 must be reduced modulo BASE.
|
||||
Vector128<int> v_ps = Vector128.CreateScalar(s1 * n).AsInt32();
|
||||
Vector128<int> v_s2 = Vector128.CreateScalar(s2).AsInt32();
|
||||
Vector128<int> v_s1 = Vector128<int>.Zero;
|
||||
|
||||
do
|
||||
{
|
||||
// Load 32 input bytes.
|
||||
Vector128<byte> bytes1 = Sse3.LoadDquVector128(localBufferPtr);
|
||||
Vector128<byte> bytes2 = Sse3.LoadDquVector128(localBufferPtr + 16);
|
||||
|
||||
// Add previous block byte sum to v_ps.
|
||||
v_ps = Sse2.Add(v_ps, v_s1);
|
||||
|
||||
// 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).AsInt32());
|
||||
Vector128<short> mad1 = Ssse3.MultiplyAddAdjacent(bytes1, tap1);
|
||||
v_s2 = Sse2.Add(v_s2, Sse2.MultiplyAddAdjacent(mad1, ones));
|
||||
|
||||
v_s1 = Sse2.Add(v_s1, Sse2.SumAbsoluteDifferences(bytes2, zero).AsInt32());
|
||||
Vector128<short> mad2 = Ssse3.MultiplyAddAdjacent(bytes2, tap2);
|
||||
v_s2 = Sse2.Add(v_s2, Sse2.MultiplyAddAdjacent(mad2, ones));
|
||||
|
||||
localBufferPtr += BLOCK_SIZE;
|
||||
}
|
||||
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
|
||||
|
||||
v_s1 = Sse2.Add(v_s1, Sse2.Shuffle(v_s1, S2301));
|
||||
v_s1 = Sse2.Add(v_s1, Sse2.Shuffle(v_s1, S1032));
|
||||
|
||||
s1 += (uint)v_s1.ToScalar();
|
||||
|
||||
v_s2 = Sse2.Add(v_s2, Sse2.Shuffle(v_s2, S2301));
|
||||
v_s2 = Sse2.Add(v_s2, Sse2.Shuffle(v_s2, S1032));
|
||||
|
||||
s2 = (uint)v_s2.ToScalar();
|
||||
|
||||
// Reduce.
|
||||
s1 %= BASE;
|
||||
s2 %= BASE;
|
||||
}
|
||||
}
|
||||
|
||||
ref byte bufferRef = ref MemoryMarshal.GetReference(buffer);
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
if (length >= 16)
|
||||
{
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
length -= 16;
|
||||
}
|
||||
|
||||
while (length-- > 0)
|
||||
{
|
||||
s2 += s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
}
|
||||
|
||||
if (s1 >= BASE)
|
||||
{
|
||||
s1 -= BASE;
|
||||
}
|
||||
|
||||
s2 %= BASE;
|
||||
}
|
||||
|
||||
return s1 | (s2 << 16);
|
||||
}
|
||||
#endif
|
||||
|
||||
private static uint CalculateScalar(uint adler, ReadOnlySpan<byte> buffer)
|
||||
{
|
||||
uint s1 = adler & 0xFFFF;
|
||||
uint s2 = (adler >> 16) & 0xFFFF;
|
||||
uint k;
|
||||
|
||||
ref byte bufferRef = ref MemoryMarshal.GetReference<byte>(buffer);
|
||||
uint length = (uint)buffer.Length;
|
||||
int index = 0;
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
k = length < NMAX ? length : NMAX;
|
||||
length -= k;
|
||||
|
||||
while (k >= 16)
|
||||
{
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
k -= 16;
|
||||
}
|
||||
|
||||
if (k != 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
s1 += Unsafe.Add(ref bufferRef, index++);
|
||||
s2 += s1;
|
||||
}
|
||||
while (--k != 0);
|
||||
}
|
||||
|
||||
s1 %= BASE;
|
||||
s2 %= BASE;
|
||||
}
|
||||
|
||||
return (s2 << 16) | s1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ using SharpCompress.Readers.Rar;
|
||||
|
||||
namespace SharpCompress.Archives.Rar
|
||||
{
|
||||
public class
|
||||
public class
|
||||
RarArchive : AbstractArchive<RarArchiveEntry, RarVolume>
|
||||
{
|
||||
internal Lazy<IRarUnpack> UnpackV2017 { get; } = new Lazy<IRarUnpack>(() => new SharpCompress.Compressors.Rar.UnpackV2017.Unpack());
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace SharpCompress.Common
|
||||
Password = password;
|
||||
}
|
||||
|
||||
#if !NET461
|
||||
#if !NETFRAMEWORK
|
||||
static ArchiveEncoding()
|
||||
{
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
|
||||
@@ -14,14 +14,25 @@ namespace SharpCompress.Common
|
||||
Action<string, ExtractionOptions?> write)
|
||||
{
|
||||
string destinationFileName;
|
||||
string file = Path.GetFileName(entry.Key);
|
||||
string fullDestinationDirectoryPath = Path.GetFullPath(destinationDirectory);
|
||||
|
||||
//check for trailing slash.
|
||||
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}");
|
||||
}
|
||||
|
||||
options ??= new ExtractionOptions()
|
||||
{
|
||||
Overwrite = true
|
||||
};
|
||||
|
||||
string file = Path.GetFileName(entry.Key);
|
||||
if (options.ExtractFullPath)
|
||||
{
|
||||
string folder = Path.GetDirectoryName(entry.Key)!;
|
||||
|
||||
@@ -10,7 +10,7 @@ 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 == 29 || FileHeader.CompressionAlgorithm == 36;
|
||||
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
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace SharpCompress.Common.SevenZip
|
||||
|
||||
public override DateTime? ArchivedTime => null;
|
||||
|
||||
public override bool IsEncrypted => false;
|
||||
public override bool IsEncrypted => FilePart.IsEncrypted;
|
||||
|
||||
public override bool IsDirectory => FilePart.Header.IsDir;
|
||||
|
||||
|
||||
@@ -102,5 +102,7 @@ namespace SharpCompress.Common.SevenZip
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
internal bool IsEncrypted => Folder!._coders.FindIndex(c => c._methodId._id == CMethodId.K_AES_ID) != -1;
|
||||
}
|
||||
}
|
||||
@@ -63,6 +63,8 @@ namespace SharpCompress.Common.Zip.Headers
|
||||
var zip64ExtraData = Extra.OfType<Zip64ExtendedInformationExtraField>().FirstOrDefault();
|
||||
if (zip64ExtraData != null)
|
||||
{
|
||||
zip64ExtraData.Process(UncompressedSize, CompressedSize, RelativeOffsetOfEntryHeader, DiskNumberStart);
|
||||
|
||||
if (CompressedSize == uint.MaxValue)
|
||||
{
|
||||
CompressedSize = zip64ExtraData.CompressedSize;
|
||||
|
||||
@@ -53,6 +53,8 @@ namespace SharpCompress.Common.Zip.Headers
|
||||
var zip64ExtraData = Extra.OfType<Zip64ExtendedInformationExtraField>().FirstOrDefault();
|
||||
if (zip64ExtraData != null)
|
||||
{
|
||||
zip64ExtraData.Process(UncompressedSize, CompressedSize, 0, 0);
|
||||
|
||||
if (CompressedSize == uint.MaxValue)
|
||||
{
|
||||
CompressedSize = zip64ExtraData.CompressedSize;
|
||||
|
||||
@@ -66,46 +66,74 @@ namespace SharpCompress.Common.Zip.Headers
|
||||
public Zip64ExtendedInformationExtraField(ExtraDataType type, ushort length, byte[] dataBytes)
|
||||
: base(type, length, dataBytes)
|
||||
{
|
||||
Process();
|
||||
}
|
||||
|
||||
private void Process()
|
||||
// From the spec, values are only in the extradata if the standard
|
||||
// value is set to 0xFFFFFFFF (or 0xFFFF for the Disk Start Number).
|
||||
// Values, if present, must appear in the following order:
|
||||
// - Original Size
|
||||
// - Compressed Size
|
||||
// - Relative Header Offset
|
||||
// - Disk Start Number
|
||||
public void Process(long uncompressedFileSize, long compressedFileSize, long relativeHeaderOffset, ushort diskNumber)
|
||||
{
|
||||
if (DataBytes.Length >= 8)
|
||||
var bytesRequired = ((uncompressedFileSize == uint.MaxValue) ? 8 : 0)
|
||||
+ ((compressedFileSize == uint.MaxValue) ? 8 : 0)
|
||||
+ ((relativeHeaderOffset == uint.MaxValue) ? 8 : 0)
|
||||
+ ((diskNumber == ushort.MaxValue) ? 4 : 0);
|
||||
var currentIndex = 0;
|
||||
|
||||
if (bytesRequired > DataBytes.Length)
|
||||
{
|
||||
UncompressedSize = BinaryPrimitives.ReadInt64LittleEndian(DataBytes);
|
||||
throw new ArchiveException("Zip64 extended information extra field is not large enough for the required information");
|
||||
}
|
||||
|
||||
if (DataBytes.Length >= 16)
|
||||
if (uncompressedFileSize == uint.MaxValue)
|
||||
{
|
||||
CompressedSize = BinaryPrimitives.ReadInt64LittleEndian(DataBytes.AsSpan(8));
|
||||
UncompressedSize = BinaryPrimitives.ReadInt64LittleEndian(DataBytes.AsSpan(currentIndex));
|
||||
currentIndex += 8;
|
||||
}
|
||||
|
||||
if (DataBytes.Length >= 24)
|
||||
if (compressedFileSize == uint.MaxValue)
|
||||
{
|
||||
RelativeOffsetOfEntryHeader = BinaryPrimitives.ReadInt64LittleEndian(DataBytes.AsSpan(16));
|
||||
CompressedSize = BinaryPrimitives.ReadInt64LittleEndian(DataBytes.AsSpan(currentIndex));
|
||||
currentIndex += 8;
|
||||
}
|
||||
|
||||
if (DataBytes.Length >= 28)
|
||||
if (relativeHeaderOffset == uint.MaxValue)
|
||||
{
|
||||
VolumeNumber = BinaryPrimitives.ReadUInt32LittleEndian(DataBytes.AsSpan(24));
|
||||
RelativeOffsetOfEntryHeader = BinaryPrimitives.ReadInt64LittleEndian(DataBytes.AsSpan(currentIndex));
|
||||
currentIndex += 8;
|
||||
}
|
||||
|
||||
switch (DataBytes.Length)
|
||||
if (diskNumber == ushort.MaxValue)
|
||||
{
|
||||
case 8:
|
||||
case 16:
|
||||
case 24:
|
||||
case 28:
|
||||
break;
|
||||
default:
|
||||
throw new ArchiveException($"Unexpected size of of Zip64 extended information extra field: {DataBytes.Length}");
|
||||
VolumeNumber = BinaryPrimitives.ReadUInt32LittleEndian(DataBytes.AsSpan(currentIndex));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uncompressed file size. Only valid after <see cref="Process(long, long, long, ushort)"/> has been called and if the
|
||||
/// original entry header had a corresponding 0xFFFFFFFF value.
|
||||
/// </summary>
|
||||
public long UncompressedSize { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Compressed file size. Only valid after <see cref="Process(long, long, long, ushort)"/> has been called and if the
|
||||
/// original entry header had a corresponding 0xFFFFFFFF value.
|
||||
/// </summary>
|
||||
public long CompressedSize { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Relative offset of the entry header. Only valid after <see cref="Process(long, long, long, ushort)"/> has been called and if the
|
||||
/// original entry header had a corresponding 0xFFFFFFFF value.
|
||||
/// </summary>
|
||||
public long RelativeOffsetOfEntryHeader { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Volume number. Only valid after <see cref="Process(long, long, long, ushort)"/> has been called and if the
|
||||
/// original entry header had a corresponding 0xFFFF value.
|
||||
/// </summary>
|
||||
public uint VolumeNumber { get; private set; }
|
||||
}
|
||||
|
||||
|
||||
@@ -105,6 +105,6 @@ namespace SharpCompress.Common.Zip.Headers
|
||||
|
||||
internal ZipFilePart Part { get; set; }
|
||||
|
||||
internal bool IsZip64 => CompressedSize == uint.MaxValue;
|
||||
internal bool IsZip64 => CompressedSize >= uint.MaxValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace SharpCompress.Common.Zip
|
||||
// ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR should be before the EOCD
|
||||
stream.Seek(eocd_location - ZIP64_EOCD_LENGTH - 4, SeekOrigin.Begin);
|
||||
uint zip64_locator = reader.ReadUInt32();
|
||||
if( zip64_locator != ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR )
|
||||
if (zip64_locator != ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR)
|
||||
{
|
||||
throw new ArchiveException("Failed to locate the Zip64 Directory Locator");
|
||||
}
|
||||
@@ -86,11 +86,11 @@ namespace SharpCompress.Common.Zip
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsMatch( byte[] haystack, int position, byte[] needle)
|
||||
private static bool IsMatch(byte[] haystack, int position, byte[] needle)
|
||||
{
|
||||
for( int i = 0; i < needle.Length; i++ )
|
||||
for (int i = 0; i < needle.Length; i++)
|
||||
{
|
||||
if( haystack[ position + i ] != needle[ i ] )
|
||||
if (haystack[position + i] != needle[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -117,11 +117,12 @@ namespace SharpCompress.Common.Zip
|
||||
// Search in reverse
|
||||
Array.Reverse(seek);
|
||||
|
||||
var max_search_area = len - MINIMUM_EOCD_LENGTH;
|
||||
// don't exclude the minimum eocd region, otherwise you fail to locate the header in empty zip files
|
||||
var max_search_area = len; // - MINIMUM_EOCD_LENGTH;
|
||||
|
||||
for( int pos_from_end = 0; pos_from_end < max_search_area; ++pos_from_end)
|
||||
for (int pos_from_end = 0; pos_from_end < max_search_area; ++pos_from_end)
|
||||
{
|
||||
if( IsMatch(seek, pos_from_end, needle) )
|
||||
if (IsMatch(seek, pos_from_end, needle))
|
||||
{
|
||||
stream.Seek(-pos_from_end, SeekOrigin.End);
|
||||
return;
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace SharpCompress.Compressors.BZip2
|
||||
stream.SetLength(value);
|
||||
}
|
||||
|
||||
#if !NET461 && !NETSTANDARD2_0
|
||||
#if !NETFRAMEWORK && !NETSTANDARD2_0
|
||||
|
||||
public override int Read(Span<byte> buffer)
|
||||
{
|
||||
@@ -123,4 +123,4 @@ namespace SharpCompress.Compressors.BZip2
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -502,13 +502,37 @@ namespace SharpCompress.Compressors.Deflate
|
||||
throw new ZlibException("Cannot Read after Writing.");
|
||||
}
|
||||
|
||||
int rc = 0;
|
||||
|
||||
// set up the output of the deflate/inflate codec:
|
||||
_z.OutputBuffer = buffer;
|
||||
_z.NextOut = offset;
|
||||
_z.AvailableBytesOut = count;
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (nomoreinput && _wantCompress)
|
||||
{
|
||||
return 0; // workitem 8557
|
||||
// no more input data available; therefore we flush to
|
||||
// try to complete the read
|
||||
rc = _z.Deflate(FlushType.Finish);
|
||||
|
||||
if (rc != ZlibConstants.Z_OK && rc != ZlibConstants.Z_STREAM_END)
|
||||
{
|
||||
throw new ZlibException(String.Format("Deflating: rc={0} msg={1}", rc, _z.Message));
|
||||
}
|
||||
|
||||
rc = (count - _z.AvailableBytesOut);
|
||||
|
||||
// calculate CRC after reading
|
||||
if (crc != null)
|
||||
{
|
||||
crc.SlurpBlock(buffer, offset, rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
if (buffer is null)
|
||||
{
|
||||
@@ -527,13 +551,6 @@ namespace SharpCompress.Compressors.Deflate
|
||||
throw new ArgumentOutOfRangeException(nameof(count));
|
||||
}
|
||||
|
||||
int rc = 0;
|
||||
|
||||
// set up the output of the deflate/inflate codec:
|
||||
_z.OutputBuffer = buffer;
|
||||
_z.NextOut = offset;
|
||||
_z.AvailableBytesOut = count;
|
||||
|
||||
// This is necessary in case _workingBuffer has been resized. (new byte[])
|
||||
// (The first reference to _workingBuffer goes through the private accessor which
|
||||
// may initialize it.)
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace SharpCompress.Compressors.LZMA
|
||||
public override void SetLength(long value) => throw new NotImplementedException();
|
||||
|
||||
|
||||
#if !NET461 && !NETSTANDARD2_0
|
||||
#if !NETFRAMEWORK && !NETSTANDARD2_0
|
||||
|
||||
public override int Read(Span<byte> buffer)
|
||||
{
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace SharpCompress.Crypto
|
||||
|
||||
public override void SetLength(long value) => throw new NotSupportedException();
|
||||
|
||||
#if !NET461 && !NETSTANDARD2_0
|
||||
#if !NETFRAMEWORK && !NETSTANDARD2_0
|
||||
|
||||
public override void Write(ReadOnlySpan<byte> buffer)
|
||||
{
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace SharpCompress.IO
|
||||
Stream.Write(buffer, offset, count);
|
||||
}
|
||||
|
||||
#if !NET461 && !NETSTANDARD2_0
|
||||
#if !NETFRAMEWORK && !NETSTANDARD2_0
|
||||
|
||||
public override int Read(Span<byte> buffer)
|
||||
{
|
||||
@@ -72,4 +72,4 @@ namespace SharpCompress.IO
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
#if NET461 || NETSTANDARD2_0
|
||||
#if NETFRAMEWORK || NETSTANDARD2_0
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.IO;
|
||||
|
||||
namespace System.IO
|
||||
namespace SharpCompress
|
||||
{
|
||||
public static class StreamExtensions
|
||||
internal static class StreamExtensions
|
||||
{
|
||||
public static int Read(this Stream stream, Span<byte> buffer)
|
||||
internal static int Read(this Stream stream, Span<byte> buffer)
|
||||
{
|
||||
byte[] temp = ArrayPool<byte>.Shared.Rent(buffer.Length);
|
||||
|
||||
try
|
||||
{
|
||||
int read = stream.Read(buffer);
|
||||
int read = stream.Read(temp, 0, buffer.Length);
|
||||
|
||||
temp.AsSpan(0, read).CopyTo(buffer);
|
||||
|
||||
@@ -24,7 +26,7 @@ namespace System.IO
|
||||
}
|
||||
}
|
||||
|
||||
public static void Write(this Stream stream, ReadOnlySpan<byte> buffer)
|
||||
internal static void Write(this Stream stream, ReadOnlySpan<byte> buffer)
|
||||
{
|
||||
byte[] temp = ArrayPool<byte>.Shared.Rent(buffer.Length);
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
#if NET461 || NETSTANDARD2_0
|
||||
#if NETFRAMEWORK || NETSTANDARD2_0
|
||||
|
||||
namespace System
|
||||
namespace SharpCompress
|
||||
{
|
||||
public static class StringExtensions
|
||||
internal static class StringExtensions
|
||||
{
|
||||
public static bool EndsWith(this string text, char value)
|
||||
internal static bool EndsWith(this string text, char value)
|
||||
{
|
||||
return text.Length > 0 && text[text.Length - 1] == value;
|
||||
}
|
||||
|
||||
public static bool Contains(this string text, char value)
|
||||
internal static bool Contains(this string text, char value)
|
||||
{
|
||||
return text.IndexOf(value) > -1;
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
<PropertyGroup>
|
||||
<AssemblyTitle>SharpCompress - Pure C# Decompression/Compression</AssemblyTitle>
|
||||
<NeutralLanguage>en-US</NeutralLanguage>
|
||||
<VersionPrefix>0.28.0</VersionPrefix>
|
||||
<AssemblyVersion>0.28.0</AssemblyVersion>
|
||||
<FileVersion>0.28.0</FileVersion>
|
||||
<VersionPrefix>0.31.0</VersionPrefix>
|
||||
<AssemblyVersion>0.31.0</AssemblyVersion>
|
||||
<FileVersion>0.31.0</FileVersion>
|
||||
<Authors>Adam Hathcock</Authors>
|
||||
<TargetFrameworks>netstandard2.0;netstandard2.1;netcoreapp3.1;net5.0</TargetFrameworks>
|
||||
<TargetFrameworks>net461;netstandard2.0;netstandard2.1;netcoreapp3.1;net5.0</TargetFrameworks>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
|
||||
<AssemblyName>SharpCompress</AssemblyName>
|
||||
@@ -18,7 +18,7 @@
|
||||
<PackageLicense>https://github.com/adamhathcock/sharpcompress/blob/master/LICENSE.txt</PackageLicense>
|
||||
<GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>
|
||||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
|
||||
<Description>SharpCompress is a compression library for NET Standard 2.0/2.1//NET 4.6 that can unrar, decompress 7zip, decompress xz, zip/unzip, tar/untar lzip/unlzip, bzip2/unbzip2 and gzip/ungzip with forward-only reading and file random access APIs. Write support for zip/tar/bzip2/gzip is implemented.</Description>
|
||||
<Description>SharpCompress is a compression library for NET Standard 2.0/2.1/NET 5.0 that can unrar, decompress 7zip, decompress xz, zip/unzip, tar/untar lzip/unlzip, bzip2/unbzip2 and gzip/ungzip with forward-only reading and file random access APIs. Write support for zip/tar/bzip2/gzip is implemented.</Description>
|
||||
<LangVersion>9</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
@@ -37,5 +37,8 @@
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" />
|
||||
<PackageReference Include="System.Memory" Version="4.5.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(VersionlessImplicitFrameworkDefine)' == 'NETFRAMEWORK' ">
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" />
|
||||
<PackageReference Include="System.Memory" Version="4.5.4" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -281,6 +281,21 @@ namespace SharpCompress
|
||||
return ArrayPool<byte>.Shared.Rent(81920);
|
||||
}
|
||||
|
||||
public static bool ReadFully(this Stream stream, byte[] buffer)
|
||||
{
|
||||
int total = 0;
|
||||
int read;
|
||||
while ((read = stream.Read(buffer, total, buffer.Length - total)) > 0)
|
||||
{
|
||||
total += read;
|
||||
if (total >= buffer.Length)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return (total >= buffer.Length);
|
||||
}
|
||||
|
||||
public static bool ReadFully(this Stream stream, Span<byte> buffer)
|
||||
{
|
||||
int total = 0;
|
||||
|
||||
@@ -87,18 +87,15 @@ namespace SharpCompress.Writers.Tar
|
||||
header.Name = NormalizeFilename(filename);
|
||||
header.Size = realSize;
|
||||
header.Write(OutputStream);
|
||||
|
||||
size = source.TransferTo(OutputStream);
|
||||
PadTo512(size.Value, false);
|
||||
PadTo512(size.Value);
|
||||
}
|
||||
|
||||
private void PadTo512(long size, bool forceZeros)
|
||||
private void PadTo512(long size)
|
||||
{
|
||||
int zeros = (int)size % 512;
|
||||
if (zeros == 0 && !forceZeros)
|
||||
{
|
||||
return;
|
||||
}
|
||||
zeros = 512 - zeros;
|
||||
int zeros = unchecked((int)(((size + 511L) & ~511L) - size));
|
||||
|
||||
OutputStream.Write(stackalloc byte[zeros]);
|
||||
}
|
||||
|
||||
@@ -108,8 +105,7 @@ namespace SharpCompress.Writers.Tar
|
||||
{
|
||||
if (finalizeArchiveOnClose)
|
||||
{
|
||||
PadTo512(0, true);
|
||||
PadTo512(0, true);
|
||||
OutputStream.Write(stackalloc byte[1024]);
|
||||
}
|
||||
switch (OutputStream)
|
||||
{
|
||||
|
||||
@@ -238,13 +238,13 @@ namespace SharpCompress.Writers.Zip
|
||||
private void WriteEndRecord(ulong size)
|
||||
{
|
||||
|
||||
var zip64 = isZip64 || entries.Count > ushort.MaxValue || streamPosition >= uint.MaxValue || size >= uint.MaxValue;
|
||||
var zip64EndOfCentralDirectoryNeeded = entries.Count > ushort.MaxValue || streamPosition >= uint.MaxValue || size >= uint.MaxValue;
|
||||
|
||||
var sizevalue = size >= uint.MaxValue ? uint.MaxValue : (uint)size;
|
||||
var streampositionvalue = streamPosition >= uint.MaxValue ? uint.MaxValue : (uint)streamPosition;
|
||||
|
||||
Span<byte> intBuf = stackalloc byte[8];
|
||||
if (zip64)
|
||||
if (zip64EndOfCentralDirectoryNeeded)
|
||||
{
|
||||
var recordlen = 2 + 2 + 4 + 4 + 8 + 8 + 8 + 8;
|
||||
|
||||
@@ -281,8 +281,7 @@ namespace SharpCompress.Writers.Zip
|
||||
BinaryPrimitives.WriteUInt32LittleEndian(intBuf, 1);
|
||||
OutputStream.Write(intBuf.Slice(0, 4)); // Number of disks
|
||||
|
||||
streamPosition += recordlen + (4 + 4 + 8 + 4);
|
||||
streampositionvalue = streamPosition >= uint.MaxValue ? uint.MaxValue : (uint)streampositionvalue;
|
||||
streamPosition += 4 + 8 + recordlen + (4 + 4 + 8 + 4);
|
||||
}
|
||||
|
||||
// Write normal end of central directory record
|
||||
|
||||
@@ -360,6 +360,31 @@ namespace SharpCompress.Test.Rar
|
||||
ArchiveFileRead("Rar5.solid.rar");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Rar2_Multi_ArchiveStreamRead()
|
||||
{
|
||||
DoRar_Multi_ArchiveStreamRead(new string[] {
|
||||
"Rar2.multi.rar",
|
||||
"Rar2.multi.r00",
|
||||
"Rar2.multi.r01",
|
||||
"Rar2.multi.r02",
|
||||
"Rar2.multi.r03",
|
||||
"Rar2.multi.r04",
|
||||
"Rar2.multi.r05"}, false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Rar2_Multi_ArchiveFileRead()
|
||||
{
|
||||
ArchiveFileRead("Rar2.multi.rar"); //r00, r01...
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Rar2_ArchiveFileRead()
|
||||
{
|
||||
ArchiveFileRead("Rar2.rar");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Rar_Multi_ArchiveFileRead()
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net5.0</TargetFrameworks>
|
||||
<TargetFrameworks>net5.0;net461</TargetFrameworks>
|
||||
<AssemblyName>SharpCompress.Test</AssemblyName>
|
||||
<AssemblyOriginatorKeyFile>../../SharpCompress.snk</AssemblyOriginatorKeyFile>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
@@ -12,13 +12,13 @@
|
||||
<ProjectReference Include="..\..\src\SharpCompress\SharpCompress.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="FluentAssertions" Version="6.2.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="Xunit.SkippableFact" Version="1.4.13" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition=" '$(VersionlessImplicitFrameworkDefine)' != 'NETFRAMEWORK' ">
|
||||
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
88
tests/SharpCompress.Test/Streams/ZlibBaseStreamTests.cs
Normal file
88
tests/SharpCompress.Test/Streams/ZlibBaseStreamTests.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using FluentAssertions;
|
||||
using SharpCompress.Compressors;
|
||||
using SharpCompress.Compressors.Deflate;
|
||||
using SharpCompress.IO;
|
||||
using Xunit;
|
||||
|
||||
namespace SharpCompress.Test.Streams
|
||||
{
|
||||
public class ZLibBaseStreamTests
|
||||
{
|
||||
[Fact]
|
||||
public void TestChunkedZlibCompressesEverything()
|
||||
{
|
||||
byte[] plainData = new byte[] { 0xf7, 0x1b, 0xda, 0x0f, 0xb6, 0x2b, 0x3d, 0x91, 0xd7, 0xe1, 0xb5, 0x11, 0x34, 0x5a, 0x51, 0x3f, 0x8b, 0xce, 0x49, 0xd2 };
|
||||
byte[] buf = new byte[plainData.Length * 2];
|
||||
|
||||
MemoryStream plainStream1 = new MemoryStream(plainData);
|
||||
DeflateStream compressor1 = new DeflateStream(plainStream1, CompressionMode.Compress);
|
||||
// This is enough to read the entire data
|
||||
int realCompressedSize = compressor1.Read(buf, 0, plainData.Length * 2);
|
||||
|
||||
MemoryStream plainStream2 = new MemoryStream(plainData);
|
||||
DeflateStream compressor2 = new DeflateStream(plainStream2, CompressionMode.Compress);
|
||||
int total = 0;
|
||||
int r = -1; // Jumpstart
|
||||
while (r != 0)
|
||||
{
|
||||
// Reading in chunks
|
||||
r = compressor2.Read(buf, 0, plainData.Length);
|
||||
total += r;
|
||||
}
|
||||
|
||||
Assert.Equal(total, realCompressedSize);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Zlib_should_read_the_previously_written_message()
|
||||
{
|
||||
var message = new string('a', 131073); // 131073 causes the failure, but 131072 (-1) doesn't
|
||||
var bytes = Encoding.ASCII.GetBytes(message);
|
||||
|
||||
using (var inputStream = new MemoryStream(bytes))
|
||||
{
|
||||
using (var compressedStream = new MemoryStream())
|
||||
using (var byteBufferStream = new BufferedStream(inputStream)) // System.IO
|
||||
{
|
||||
Compress(byteBufferStream, compressedStream, compressionLevel: 1);
|
||||
compressedStream.Position = 0;
|
||||
|
||||
using (var decompressedStream = new MemoryStream())
|
||||
{
|
||||
Decompress(compressedStream, decompressedStream);
|
||||
|
||||
byteBufferStream.Position = 0;
|
||||
var result = Encoding.ASCII.GetString(GetBytes(byteBufferStream));
|
||||
result.Should().Be(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Compress(Stream input, Stream output, int compressionLevel)
|
||||
{
|
||||
using (var zlibStream = new ZlibStream(new NonDisposingStream(output), CompressionMode.Compress, (CompressionLevel)compressionLevel))
|
||||
{
|
||||
zlibStream.FlushMode = FlushType.Sync;
|
||||
input.CopyTo(zlibStream);
|
||||
}
|
||||
}
|
||||
|
||||
private void Decompress(Stream input, Stream output)
|
||||
{
|
||||
using (var zlibStream = new ZlibStream(new NonDisposingStream(input), CompressionMode.Decompress))
|
||||
{
|
||||
zlibStream.CopyTo(output);
|
||||
}
|
||||
}
|
||||
|
||||
byte[] GetBytes(BufferedStream stream)
|
||||
{
|
||||
byte[] bytes = new byte[stream.Length];
|
||||
stream.Read(bytes, 0, (int)stream.Length);
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -190,7 +190,7 @@ namespace SharpCompress.Test.Tar
|
||||
}
|
||||
}
|
||||
|
||||
#if !NET461
|
||||
#if !NETFRAMEWORK
|
||||
[Fact]
|
||||
public void Tar_GZip_With_Symlink_Entries()
|
||||
{
|
||||
|
||||
@@ -290,6 +290,28 @@ namespace SharpCompress.Test.Zip
|
||||
Directory.Delete(SCRATCH_FILES_PATH, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an empty zip file and attempts to read it right afterwards.
|
||||
/// Ensures that parsing file headers works even in that case
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Zip_Create_Empty_And_Read()
|
||||
{
|
||||
var archive = ZipArchive.Create();
|
||||
|
||||
var archiveStream = new MemoryStream();
|
||||
|
||||
archive.SaveTo(archiveStream, CompressionType.LZMA);
|
||||
|
||||
archiveStream.Position = 0;
|
||||
|
||||
var readArchive = ArchiveFactory.Open(archiveStream);
|
||||
|
||||
var count = readArchive.Entries.Count();
|
||||
|
||||
Assert.Equal(0, count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Zip_Create_New_Add_Remove()
|
||||
{
|
||||
@@ -570,11 +592,29 @@ namespace SharpCompress.Test.Zip
|
||||
{
|
||||
string zipPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.LongComment.zip");
|
||||
|
||||
using(ZipArchive za = ZipArchive.Open(zipPath))
|
||||
using (ZipArchive za = ZipArchive.Open(zipPath))
|
||||
{
|
||||
var count = za.Entries.Count;
|
||||
Assert.Equal(1, count);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Zip_Zip64_CompressedSizeExtraOnly_Read()
|
||||
{
|
||||
string zipPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.zip64.compressedonly.zip");
|
||||
|
||||
using (ZipArchive za = ZipArchive.Open(zipPath))
|
||||
{
|
||||
var firstEntry = za.Entries.First(x => x.Key == "test/test.txt");
|
||||
|
||||
using (var memoryStream = new MemoryStream())
|
||||
using (var firstStream = firstEntry.OpenEntryStream())
|
||||
{
|
||||
firstStream.CopyTo(memoryStream);
|
||||
Assert.Equal(15, memoryStream.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,6 +269,34 @@ namespace SharpCompress.Test.Zip
|
||||
VerifyFiles();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Zip_Deflate_ZipCrypto_Read()
|
||||
{
|
||||
int count = 0;
|
||||
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "zipcrypto.zip")))
|
||||
using (var reader = ZipReader.Open(stream, new ReaderOptions()
|
||||
{
|
||||
Password = "test"
|
||||
}))
|
||||
{
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
Assert.Equal(CompressionType.None, reader.Entry.CompressionType);
|
||||
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions()
|
||||
{
|
||||
ExtractFullPath = true,
|
||||
Overwrite = true
|
||||
});
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
Assert.Equal(8, count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestSharpCompressWithEmptyStream()
|
||||
{
|
||||
|
||||
BIN
tests/TestArchives/Archives/Rar2.multi.r00
Normal file
BIN
tests/TestArchives/Archives/Rar2.multi.r00
Normal file
Binary file not shown.
BIN
tests/TestArchives/Archives/Rar2.multi.r01
Normal file
BIN
tests/TestArchives/Archives/Rar2.multi.r01
Normal file
Binary file not shown.
BIN
tests/TestArchives/Archives/Rar2.multi.r02
Normal file
BIN
tests/TestArchives/Archives/Rar2.multi.r02
Normal file
Binary file not shown.
BIN
tests/TestArchives/Archives/Rar2.multi.r03
Normal file
BIN
tests/TestArchives/Archives/Rar2.multi.r03
Normal file
Binary file not shown.
BIN
tests/TestArchives/Archives/Rar2.multi.r04
Normal file
BIN
tests/TestArchives/Archives/Rar2.multi.r04
Normal file
Binary file not shown.
BIN
tests/TestArchives/Archives/Rar2.multi.r05
Normal file
BIN
tests/TestArchives/Archives/Rar2.multi.r05
Normal file
Binary file not shown.
BIN
tests/TestArchives/Archives/Rar2.multi.rar
Normal file
BIN
tests/TestArchives/Archives/Rar2.multi.rar
Normal file
Binary file not shown.
BIN
tests/TestArchives/Archives/Rar2.rar
Normal file
BIN
tests/TestArchives/Archives/Rar2.rar
Normal file
Binary file not shown.
BIN
tests/TestArchives/Archives/Zip.zip64.compressedonly.zip
Normal file
BIN
tests/TestArchives/Archives/Zip.zip64.compressedonly.zip
Normal file
Binary file not shown.
BIN
tests/TestArchives/Archives/zipcrypto.zip
Normal file
BIN
tests/TestArchives/Archives/zipcrypto.zip
Normal file
Binary file not shown.
Reference in New Issue
Block a user