Skip to content

Commit

Permalink
Merge branch 'master' into memory-downgrade
Browse files Browse the repository at this point in the history
  • Loading branch information
adamhathcock committed Jun 4, 2021
2 parents e6dded8 + e07046a commit f952210
Show file tree
Hide file tree
Showing 10 changed files with 116 additions and 23 deletions.
2 changes: 2 additions & 0 deletions src/SharpCompress/Common/Zip/Headers/DirectoryEntryHeader.cs
Expand Up @@ -63,6 +63,8 @@ internal override void Read(BinaryReader reader)
var zip64ExtraData = Extra.OfType<Zip64ExtendedInformationExtraField>().FirstOrDefault();
if (zip64ExtraData != null)
{
zip64ExtraData.Process(UncompressedSize, CompressedSize, RelativeOffsetOfEntryHeader, DiskNumberStart);

if (CompressedSize == uint.MaxValue)
{
CompressedSize = zip64ExtraData.CompressedSize;
Expand Down
2 changes: 2 additions & 0 deletions src/SharpCompress/Common/Zip/Headers/LocalEntryHeader.cs
Expand Up @@ -53,6 +53,8 @@ internal override void Read(BinaryReader reader)
var zip64ExtraData = Extra.OfType<Zip64ExtendedInformationExtraField>().FirstOrDefault();
if (zip64ExtraData != null)
{
zip64ExtraData.Process(UncompressedSize, CompressedSize, 0, 0);

if (CompressedSize == uint.MaxValue)
{
CompressedSize = zip64ExtraData.CompressedSize;
Expand Down
Expand Up @@ -66,46 +66,74 @@ internal sealed class Zip64ExtendedInformationExtraField : ExtraData
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; }
}

Expand Down
2 changes: 1 addition & 1 deletion src/SharpCompress/Common/Zip/Headers/ZipFileEntry.cs
Expand Up @@ -105,6 +105,6 @@ protected void LoadExtra(byte[] extra)

internal ZipFilePart Part { get; set; }

internal bool IsZip64 => CompressedSize == uint.MaxValue;
internal bool IsZip64 => CompressedSize >= uint.MaxValue;
}
}
6 changes: 3 additions & 3 deletions src/SharpCompress/SharpCompress.csproj
Expand Up @@ -2,9 +2,9 @@
<PropertyGroup>
<AssemblyTitle>SharpCompress - Pure C# Decompression/Compression</AssemblyTitle>
<NeutralLanguage>en-US</NeutralLanguage>
<VersionPrefix>0.28.1</VersionPrefix>
<AssemblyVersion>0.28.1</AssemblyVersion>
<FileVersion>0.28.1</FileVersion>
<VersionPrefix>0.28.2</VersionPrefix>
<AssemblyVersion>0.28.2</AssemblyVersion>
<FileVersion>0.28.2</FileVersion>
<Authors>Adam Hathcock</Authors>
<TargetFrameworks>netstandard2.0;netstandard2.1;netcoreapp3.1;net5.0</TargetFrameworks>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
Expand Down
17 changes: 16 additions & 1 deletion src/SharpCompress/Utility.cs
Expand Up @@ -280,7 +280,22 @@ private static byte[] GetTransferByteArray()
{
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;
Expand Down
18 changes: 18 additions & 0 deletions tests/SharpCompress.Test/Zip/ZipArchiveTests.cs
Expand Up @@ -576,5 +576,23 @@ public void Zip_LongComment_Read()
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);
}
}
}
}
}
28 changes: 28 additions & 0 deletions tests/SharpCompress.Test/Zip/ZipReaderTests.cs
Expand Up @@ -268,6 +268,34 @@ public void Zip_Deflate_WinzipAES_Read()
}
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()
Expand Down
Binary file not shown.
Binary file added tests/TestArchives/Archives/zipcrypto.zip
Binary file not shown.

0 comments on commit f952210

Please sign in to comment.