mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-09-24 07:54:39 +00:00
Merge branch 'master' into feature/521
This commit is contained in:
@@ -10,7 +10,8 @@ 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());
|
||||
@@ -42,7 +43,7 @@ namespace SharpCompress.Archives.Rar
|
||||
|
||||
protected override IEnumerable<RarArchiveEntry> LoadEntries(IEnumerable<RarVolume> volumes)
|
||||
{
|
||||
return RarArchiveEntryFactory.GetEntries(this, volumes);
|
||||
return RarArchiveEntryFactory.GetEntries(this, volumes, ReaderOptions);
|
||||
}
|
||||
|
||||
protected override IEnumerable<RarVolume> LoadVolumes(IEnumerable<Stream> streams)
|
||||
|
||||
@@ -6,6 +6,7 @@ using SharpCompress.Common;
|
||||
using SharpCompress.Common.Rar;
|
||||
using SharpCompress.Common.Rar.Headers;
|
||||
using SharpCompress.Compressors.Rar;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Archives.Rar
|
||||
{
|
||||
@@ -13,11 +14,13 @@ namespace SharpCompress.Archives.Rar
|
||||
{
|
||||
private readonly ICollection<RarFilePart> parts;
|
||||
private readonly RarArchive archive;
|
||||
private readonly ReaderOptions readerOptions;
|
||||
|
||||
internal RarArchiveEntry(RarArchive archive, IEnumerable<RarFilePart> parts)
|
||||
internal RarArchiveEntry(RarArchive archive, IEnumerable<RarFilePart> parts, ReaderOptions readerOptions)
|
||||
{
|
||||
this.parts = parts.ToList();
|
||||
this.archive = archive;
|
||||
this.readerOptions = readerOptions;
|
||||
}
|
||||
|
||||
public override CompressionType CompressionType => CompressionType.Rar;
|
||||
@@ -69,13 +72,14 @@ namespace SharpCompress.Archives.Rar
|
||||
{
|
||||
get
|
||||
{
|
||||
return parts.Select(fp => fp.FileHeader).Any(fh => !fh.IsSplitAfter);
|
||||
var headers = parts.Select(x => x.FileHeader);
|
||||
return !headers.First().IsSplitBefore && !headers.Last().IsSplitAfter;
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckIncomplete()
|
||||
{
|
||||
if (!IsComplete)
|
||||
if (!readerOptions.DisableCheckIncomplete && !IsComplete)
|
||||
{
|
||||
throw new IncompleteArchiveException("ArchiveEntry is incomplete and cannot perform this operation.");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using SharpCompress.Common.Rar;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
namespace SharpCompress.Archives.Rar
|
||||
{
|
||||
@@ -36,11 +37,12 @@ namespace SharpCompress.Archives.Rar
|
||||
}
|
||||
|
||||
internal static IEnumerable<RarArchiveEntry> GetEntries(RarArchive archive,
|
||||
IEnumerable<RarVolume> rarParts)
|
||||
IEnumerable<RarVolume> rarParts,
|
||||
ReaderOptions readerOptions)
|
||||
{
|
||||
foreach (var groupedParts in GetMatchedFileParts(rarParts))
|
||||
{
|
||||
yield return new RarArchiveEntry(archive, groupedParts);
|
||||
yield return new RarArchiveEntry(archive, groupedParts, readerOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,6 +437,7 @@ 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 IsDirectory => HasFlag(IsRar5 ? FileFlagsV5.DIRECTORY : FileFlagsV4.DIRECTORY);
|
||||
|
||||
@@ -8,7 +8,10 @@ namespace SharpCompress.Common.Zip
|
||||
{
|
||||
internal sealed class SeekableZipHeaderFactory : ZipHeaderFactory
|
||||
{
|
||||
private const int MAX_ITERATIONS_FOR_DIRECTORY_HEADER = 4096;
|
||||
private const int MINIMUM_EOCD_LENGTH = 22;
|
||||
private const int ZIP64_EOCD_LENGTH = 20;
|
||||
// Comment may be within 64kb + structure 22 bytes
|
||||
private const int MAX_SEARCH_LENGTH_FOR_EOCD = 65557;
|
||||
private bool _zip64;
|
||||
|
||||
internal SeekableZipHeaderFactory(string? password, ArchiveEncoding archiveEncoding)
|
||||
@@ -20,14 +23,24 @@ namespace SharpCompress.Common.Zip
|
||||
{
|
||||
var reader = new BinaryReader(stream);
|
||||
|
||||
SeekBackToHeader(stream, reader, DIRECTORY_END_HEADER_BYTES);
|
||||
SeekBackToHeader(stream, reader);
|
||||
|
||||
var eocd_location = stream.Position;
|
||||
var entry = new DirectoryEndHeader();
|
||||
entry.Read(reader);
|
||||
|
||||
if (entry.IsZip64)
|
||||
{
|
||||
_zip64 = true;
|
||||
SeekBackToHeader(stream, reader, ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR);
|
||||
|
||||
// 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 )
|
||||
{
|
||||
throw new ArchiveException("Failed to locate the Zip64 Directory Locator");
|
||||
}
|
||||
|
||||
var zip64Locator = new Zip64DirectoryEndLocatorHeader();
|
||||
zip64Locator.Read(reader);
|
||||
|
||||
@@ -73,27 +86,49 @@ namespace SharpCompress.Common.Zip
|
||||
}
|
||||
}
|
||||
|
||||
private static void SeekBackToHeader(Stream stream, BinaryReader reader, uint headerSignature)
|
||||
private static bool IsMatch( byte[] haystack, int position, byte[] needle)
|
||||
{
|
||||
long offset = 0;
|
||||
uint signature;
|
||||
int iterationCount = 0;
|
||||
do
|
||||
for( int i = 0; i < needle.Length; i++ )
|
||||
{
|
||||
if ((stream.Length + offset) - 4 < 0)
|
||||
if( haystack[ position + i ] != needle[ i ] )
|
||||
{
|
||||
throw new ArchiveException("Failed to locate the Zip Header");
|
||||
}
|
||||
stream.Seek(offset - 4, SeekOrigin.End);
|
||||
signature = reader.ReadUInt32();
|
||||
offset--;
|
||||
iterationCount++;
|
||||
if (iterationCount > MAX_ITERATIONS_FOR_DIRECTORY_HEADER)
|
||||
{
|
||||
throw new ArchiveException("Could not find Zip file Directory at the end of the file. File may be corrupted.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
while (signature != headerSignature);
|
||||
|
||||
return true;
|
||||
}
|
||||
private static void SeekBackToHeader(Stream stream, BinaryReader reader)
|
||||
{
|
||||
// Minimum EOCD length
|
||||
if (stream.Length < MINIMUM_EOCD_LENGTH)
|
||||
{
|
||||
throw new ArchiveException("Could not find Zip file Directory at the end of the file. File may be corrupted.");
|
||||
}
|
||||
|
||||
int len = stream.Length < MAX_SEARCH_LENGTH_FOR_EOCD ? (int)stream.Length : MAX_SEARCH_LENGTH_FOR_EOCD;
|
||||
// We search for marker in reverse to find the first occurance
|
||||
byte[] needle = { 0x06, 0x05, 0x4b, 0x50 };
|
||||
|
||||
stream.Seek(-len, SeekOrigin.End);
|
||||
|
||||
byte[] seek = reader.ReadBytes(len);
|
||||
|
||||
// Search in reverse
|
||||
Array.Reverse(seek);
|
||||
|
||||
var max_search_area = len - MINIMUM_EOCD_LENGTH;
|
||||
|
||||
for( int pos_from_end = 0; pos_from_end < max_search_area; ++pos_from_end)
|
||||
{
|
||||
if( IsMatch(seek, pos_from_end, needle) )
|
||||
{
|
||||
stream.Seek(-pos_from_end, SeekOrigin.End);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new ArchiveException("Failed to locate the Zip Header");
|
||||
}
|
||||
|
||||
internal LocalEntryHeader GetLocalHeader(Stream stream, DirectoryEntryHeader directoryEntryHeader)
|
||||
|
||||
@@ -10,5 +10,7 @@ namespace SharpCompress.Readers
|
||||
public bool LookForHeader { get; set; }
|
||||
|
||||
public string? Password { get; set; }
|
||||
|
||||
public bool DisableCheckIncomplete { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
<PropertyGroup>
|
||||
<AssemblyTitle>SharpCompress - Pure C# Decompression/Compression</AssemblyTitle>
|
||||
<NeutralLanguage>en-US</NeutralLanguage>
|
||||
<VersionPrefix>0.27.1</VersionPrefix>
|
||||
<AssemblyVersion>0.27.1</AssemblyVersion>
|
||||
<FileVersion>0.27.1</FileVersion>
|
||||
<VersionPrefix>0.28.0</VersionPrefix>
|
||||
<AssemblyVersion>0.28.0</AssemblyVersion>
|
||||
<FileVersion>0.28.0</FileVersion>
|
||||
<Authors>Adam Hathcock</Authors>
|
||||
<TargetFrameworks>netstandard2.0;netstandard2.1;netcoreapp3.1;net5.0</TargetFrameworks>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
|
||||
@@ -253,7 +253,7 @@ namespace SharpCompress.Writers.Zip
|
||||
|
||||
BinaryPrimitives.WriteUInt64LittleEndian(intBuf, (ulong)recordlen);
|
||||
OutputStream.Write(intBuf); // Size of zip64 end of central directory record
|
||||
BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 0);
|
||||
BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 45);
|
||||
OutputStream.Write(intBuf.Slice(0, 2)); // Made by
|
||||
BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 45);
|
||||
OutputStream.Write(intBuf.Slice(0, 2)); // Version needed
|
||||
@@ -278,8 +278,8 @@ namespace SharpCompress.Writers.Zip
|
||||
OutputStream.Write(intBuf.Slice(0, 4)); // Entry disk
|
||||
BinaryPrimitives.WriteUInt64LittleEndian(intBuf, (ulong)streamPosition + size);
|
||||
OutputStream.Write(intBuf); // Offset to the zip64 central directory
|
||||
BinaryPrimitives.WriteUInt32LittleEndian(intBuf, 0);
|
||||
OutputStream.Write(intBuf); // Number of disks
|
||||
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;
|
||||
|
||||
@@ -564,5 +564,17 @@ namespace SharpCompress.Test.Zip
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Zip_LongComment_Read()
|
||||
{
|
||||
string zipPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.LongComment.zip");
|
||||
|
||||
using(ZipArchive za = ZipArchive.Open(zipPath))
|
||||
{
|
||||
var count = za.Entries.Count;
|
||||
Assert.Equal(1, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BIN
tests/TestArchives/Archives/Zip.LongComment.zip
Normal file
BIN
tests/TestArchives/Archives/Zip.LongComment.zip
Normal file
Binary file not shown.
Reference in New Issue
Block a user