Compare commits

..

25 Commits

Author SHA1 Message Date
Adam Hathcock
3009e6dcfd Mark for 0.32.2 2022-07-29 10:45:56 +01:00
Adam Hathcock
70343b17bc add more tests for uncompressed streaming zips 2022-07-29 09:47:35 +01:00
Adam Hathcock
3f6027ec2c Merge pull request #686 from Erior/477
Mitigation of problems
2022-07-29 09:41:24 +01:00
Lars Vahlenberg
5706732c55 Naive implementation of searching of DataDescriptor, not compatible with big archives (>32bit), but handles test cases. 2022-07-28 23:03:06 +02:00
Lars Vahlenberg
ad633a9dd0 missing test file from error report 2022-07-28 21:20:42 +02:00
Lars Vahlenberg
7c56df1237 Mitigation of problems 2022-07-28 20:36:28 +02:00
Adam Hathcock
c1110f2897 Merge pull request #683 from OwnageIsMagic/patch-1
WriteAll: use delegate instead of Expression
2022-07-27 10:13:50 +01:00
Adam Hathcock
647642578b Merge branch 'master' into patch-1 2022-07-27 09:49:13 +01:00
OwnageIsMagic
5ca4efac31 WriteAll: revert 109a7c1 2022-07-26 21:36:00 +03:00
Adam Hathcock
deddf12b70 Merge pull request #684 from daverant/nuget-license
Include license in nuget package
2022-07-26 16:21:41 +01:00
OwnageIsMagic
109a7c12ea WriteAll: update delegate type 2022-07-19 04:03:26 +03:00
David Rant
f955031e27 Hide license in IDE 2022-07-18 17:16:22 +01:00
David Rant
6a69c6cd02 Reference bundled package license file 2022-07-18 17:11:06 +01:00
David Rant
c1d4ac45ab Include license when packing 2022-07-18 17:10:36 +01:00
OwnageIsMagic
2946a35b0e WriteAll: use delegate instead of Expression 2022-07-18 04:36:31 +03:00
Adam Hathcock
c73a8cb18f Merge pull request #682 from adamhathcock/RarFileVolIdx_RarArcVer_GzCrc 2022-07-16 11:29:48 +01:00
Nanook
574a093038 Minor tweak that got missed in the last tidy. 2022-07-15 21:25:39 +01:00
Nanook
4eb1fe0b80 RarArchive has Min/MaxVersion. RarEntry has Volumne Indexes. GZ CRC fix. 2022-07-15 21:15:10 +01:00
Adam Hathcock
4c46cd725b Merge pull request #679 from louis-michelbergeron/master
Fix LZMADecoder Code function
2022-06-28 08:27:13 +01:00
Adam Hathcock
fdbd0e1fba Merge branch 'master' into master 2022-06-28 08:21:49 +01:00
louis-michel
5801168ce0 Merge branch 'master' of https://github.com/louis-michelbergeron/sharpcompress 2022-06-27 19:13:20 -04:00
louis-michel
d4c7551087 Fix LZMA Code function 2022-06-27 19:13:10 -04:00
Adam Hathcock
c9daf0c9f5 Merge pull request #675 from Erior/feature/#636
ReadOnlySubStream overrides and adds logic #636
2022-06-22 11:17:18 +01:00
Adam Hathcock
8cb566b031 Merge branch 'master' into feature/#636 2022-06-22 09:05:57 +01:00
Lars Vahlenberg
089b16326e ReadOnlySubStream overrides and adds logic to Read byte[], needs to have same logic for Span<byte> for consistency. 2022-06-21 19:30:07 +02:00
40 changed files with 470 additions and 102 deletions

View File

@@ -89,7 +89,8 @@ namespace SharpCompress.Archives.GZip
protected override IEnumerable<GZipVolume> LoadVolumes(SourceStream srcStream)
{
srcStream.LoadAllParts();
return srcStream.Streams.Select(a => new GZipVolume(a, ReaderOptions));
int idx = 0;
return srcStream.Streams.Select(a => new GZipVolume(a, ReaderOptions, idx++));
}
public static bool IsGZipFile(string filePath)
{

View File

@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SharpCompress.Common.Rar;
@@ -13,8 +13,8 @@ namespace SharpCompress.Archives.Rar
/// </summary>
internal class FileInfoRarArchiveVolume : RarVolume
{
internal FileInfoRarArchiveVolume(FileInfo fileInfo, ReaderOptions options)
: base(StreamingMode.Seekable, fileInfo.OpenRead(), FixOptions(options))
internal FileInfoRarArchiveVolume(FileInfo fileInfo, ReaderOptions options, int index = 0)
: base(StreamingMode.Seekable, fileInfo.OpenRead(), FixOptions(options), index)
{
FileInfo = fileInfo;
FileParts = GetVolumeFileParts().ToArray().ToReadOnly();

View File

@@ -1,4 +1,4 @@
using System.IO;
using System.IO;
using SharpCompress.Common.Rar.Headers;
namespace SharpCompress.Archives.Rar
@@ -6,7 +6,7 @@ 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.Stream, password)
: base(mh, fh, volume.Index, volume.Stream, password)
{
FileInfo = fi;
}

View File

@@ -37,16 +37,17 @@ namespace SharpCompress.Archives.Rar
{
base.SrcStream.LoadAllParts(); //request all streams
Stream[] streams = base.SrcStream.Streams.ToArray();
int idx = 0;
if (streams.Length > 1 && IsRarFile(streams[1], ReaderOptions)) //test part 2 - true = multipart not split
{
base.SrcStream.IsVolumes = true;
streams[1].Position = 0;
base.SrcStream.Position = 0;
return srcStream.Streams.Select(a => new StreamRarArchiveVolume(a, ReaderOptions));
return srcStream.Streams.Select(a => new StreamRarArchiveVolume(a, ReaderOptions, idx++));
}
else //split mode or single file
return new StreamRarArchiveVolume(base.SrcStream, ReaderOptions).AsEnumerable();
return new StreamRarArchiveVolume(base.SrcStream, ReaderOptions, idx++).AsEnumerable();
}
protected override IReader CreateReaderForSolidExtraction()
@@ -58,6 +59,9 @@ namespace SharpCompress.Archives.Rar
public override bool IsSolid => Volumes.First().IsSolidArchive;
public virtual int MinVersion => Volumes.First().MinVersion;
public virtual int MaxVersion => Volumes.First().MaxVersion;
#region Creation
/// <summary>
/// Constructor with a FileInfo object to an existing file.

View File

@@ -86,4 +86,4 @@ namespace SharpCompress.Archives.Rar
}
}
}
}
}

View File

@@ -1,4 +1,4 @@
using System.IO;
using System.IO;
using SharpCompress.Common.Rar;
using SharpCompress.Common.Rar.Headers;
@@ -9,8 +9,8 @@ namespace SharpCompress.Archives.Rar
private readonly Stream stream;
private readonly string? password;
internal SeekableFilePart(MarkHeader mh, FileHeader fh, Stream stream, string? password)
: base(mh, fh)
internal SeekableFilePart(MarkHeader mh, FileHeader fh, int index, Stream stream, string? password)
: base(mh, fh, index)
{
this.stream = stream;
this.password = password;
@@ -28,4 +28,4 @@ namespace SharpCompress.Archives.Rar
internal override string FilePartName => "Unknown Stream - File Entry: " + FileHeader.FileName;
}
}
}

View File

@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Common.Rar;
using SharpCompress.Common.Rar.Headers;
@@ -9,8 +9,8 @@ namespace SharpCompress.Archives.Rar
{
internal class StreamRarArchiveVolume : RarVolume
{
internal StreamRarArchiveVolume(Stream stream, ReaderOptions options)
: base(StreamingMode.Seekable, stream, options)
internal StreamRarArchiveVolume(Stream stream, ReaderOptions options, int index = 0)
: base(StreamingMode.Seekable, stream, options, index)
{
}
@@ -21,7 +21,7 @@ namespace SharpCompress.Archives.Rar
internal override RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader)
{
return new SeekableFilePart(markHeader, fileHeader, Stream, ReaderOptions.Password);
return new SeekableFilePart(markHeader, fileHeader, this.Index, Stream, ReaderOptions.Password);
}
}
}
}

View File

@@ -85,7 +85,8 @@ namespace SharpCompress.Archives.SevenZip
protected override IEnumerable<SevenZipVolume> LoadVolumes(SourceStream srcStream)
{
base.SrcStream.LoadAllParts(); //request all streams
return new SevenZipVolume(srcStream, ReaderOptions).AsEnumerable(); //simple single volume or split, multivolume not supported
int idx = 0;
return new SevenZipVolume(srcStream, ReaderOptions, idx++).AsEnumerable(); //simple single volume or split, multivolume not supported
}
public static bool IsSevenZipFile(string filePath)

View File

@@ -107,7 +107,8 @@ namespace SharpCompress.Archives.Tar
protected override IEnumerable<TarVolume> LoadVolumes(SourceStream srcStream)
{
base.SrcStream.LoadAllParts(); //request all streams
return new TarVolume(srcStream, ReaderOptions).AsEnumerable(); //simple single volume or split, multivolume not supported
int idx = 0;
return new TarVolume(srcStream, ReaderOptions, idx++).AsEnumerable(); //simple single volume or split, multivolume not supported
}
/// <summary>

View File

@@ -168,6 +168,7 @@ namespace SharpCompress.Archives.Zip
base.SrcStream.Position = 0;
List<Stream> streams = base.SrcStream.Streams.ToList();
int idx = 0;
if (streams.Count > 1) //test part 2 - true = multipart not split
{
streams[1].Position += 4; //skip the POST_DATA_DESCRIPTOR to prevent an exception
@@ -182,12 +183,12 @@ namespace SharpCompress.Archives.Zip
streams.Add(tmp);
//streams[0].Position = 4; //skip the POST_DATA_DESCRIPTOR to prevent an exception
return streams.Select(a => new ZipVolume(a, ReaderOptions));
return streams.Select(a => new ZipVolume(a, ReaderOptions, idx++));
}
}
//split mode or single file
return new ZipVolume(base.SrcStream, ReaderOptions).AsEnumerable();
return new ZipVolume(base.SrcStream, ReaderOptions, idx++).AsEnumerable();
}
internal ZipArchive()

View File

@@ -1,5 +1,6 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
namespace SharpCompress.Common
{
@@ -70,6 +71,8 @@ namespace SharpCompress.Common
/// </summary>
public abstract bool IsSplitAfter { get; }
public int VolumeIndexFirst => this.Parts?.FirstOrDefault()?.Index ?? 0;
public int VolumeIndexLast => this.Parts?.LastOrDefault()?.Index ?? 0;
/// <inheritdoc/>
public override string ToString() => Key;

View File

@@ -1,4 +1,4 @@
using System.IO;
using System.IO;
namespace SharpCompress.Common
{
@@ -12,6 +12,7 @@ namespace SharpCompress.Common
internal ArchiveEncoding ArchiveEncoding { get; }
internal abstract string FilePartName { get; }
public int Index { get; set; }
internal abstract Stream GetCompressedStream();
internal abstract Stream? GetRawStream();

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.IO;
@@ -31,8 +31,8 @@ namespace SharpCompress.Common.GZip
internal long EntryStartPosition { get; }
internal DateTime? DateModified { get; private set; }
internal int? Crc { get; private set; }
internal int? UncompressedSize { get; private set; }
internal uint? Crc { get; private set; }
internal uint? UncompressedSize { get; private set; }
internal override string FilePartName => _name!;
@@ -52,8 +52,8 @@ namespace SharpCompress.Common.GZip
Span<byte> trailer = stackalloc byte[8];
int n = _stream.Read(trailer);
Crc = BinaryPrimitives.ReadInt32LittleEndian(trailer);
UncompressedSize = BinaryPrimitives.ReadInt32LittleEndian(trailer.Slice(4));
Crc = BinaryPrimitives.ReadUInt32LittleEndian(trailer);
UncompressedSize = BinaryPrimitives.ReadUInt32LittleEndian(trailer.Slice(4));
}
private void ReadAndValidateGzipHeader()

View File

@@ -1,12 +1,12 @@
using System.IO;
using System.IO;
using SharpCompress.Readers;
namespace SharpCompress.Common.GZip
{
public class GZipVolume : Volume
{
public GZipVolume(Stream stream, ReaderOptions options)
: base(stream, options)
public GZipVolume(Stream stream, ReaderOptions options, int index = 0)
: base(stream, options, index)
{
}
@@ -20,4 +20,4 @@ namespace SharpCompress.Common.GZip
public override bool IsMultiVolume => true;
}
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System;
using System.Collections.Generic;
namespace SharpCompress.Common
{
@@ -15,9 +16,11 @@ namespace SharpCompress.Common
bool IsEncrypted { get; }
bool IsSplitAfter { get; }
bool IsSolid { get; }
int VolumeIndexFirst { get; }
int VolumeIndexLast { get; }
DateTime? LastAccessedTime { get; }
DateTime? LastModifiedTime { get; }
long Size { get; }
int? Attrib { get; }
}
}
}

View File

@@ -1,8 +1,11 @@
using System;
using System;
namespace SharpCompress.Common
{
public interface IVolume : IDisposable
{
int Index { get; }
string FileName { get; }
}
}
}

View File

@@ -1,4 +1,4 @@
using System.IO;
using System.IO;
using SharpCompress.Common.Rar.Headers;
namespace SharpCompress.Common.Rar
@@ -8,11 +8,12 @@ namespace SharpCompress.Common.Rar
/// </summary>
internal abstract class RarFilePart : FilePart
{
internal RarFilePart(MarkHeader mh, FileHeader fh)
internal RarFilePart(MarkHeader mh, FileHeader fh, int index)
: base(fh.ArchiveEncoding)
{
MarkHeader = mh;
FileHeader = fh;
Index = index;
}
internal MarkHeader MarkHeader { get; }
@@ -24,4 +25,4 @@ namespace SharpCompress.Common.Rar
return null;
}
}
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -14,9 +14,10 @@ namespace SharpCompress.Common.Rar
public abstract class RarVolume : Volume
{
private readonly RarHeaderFactory _headerFactory;
internal int _maxCompressionAlgorithm;
internal RarVolume(StreamingMode mode, Stream stream, ReaderOptions options)
: base(stream, options)
internal RarVolume(StreamingMode mode, Stream stream, ReaderOptions options, int index = 0)
: base(stream, options, index)
{
_headerFactory = new RarHeaderFactory(mode, options);
}
@@ -51,6 +52,8 @@ namespace SharpCompress.Common.Rar
case HeaderType.File:
{
var fh = (FileHeader)header;
if (_maxCompressionAlgorithm < fh.CompressionAlgorithm)
_maxCompressionAlgorithm = fh.CompressionAlgorithm;
yield return CreateFilePart(lastMarkHeader!, fh);
}
break;
@@ -110,5 +113,37 @@ namespace SharpCompress.Common.Rar
return ArchiveHeader.IsSolid;
}
}
public int MinVersion
{
get
{
EnsureArchiveHeaderLoaded();
if (_maxCompressionAlgorithm >= 50)
return 5; //5-6
else if (_maxCompressionAlgorithm >= 29)
return 3; //3-4
else if (_maxCompressionAlgorithm >= 20)
return 2; //2
else
return 1;
}
}
public int MaxVersion
{
get
{
EnsureArchiveHeaderLoaded();
if (_maxCompressionAlgorithm >= 50)
return 6; //5-6
else if (_maxCompressionAlgorithm >= 29)
return 4; //3-4
else if (_maxCompressionAlgorithm >= 20)
return 2; //2
else
return 1;
}
}
}
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.IO;
using System.Linq;
using SharpCompress.IO;
@@ -26,7 +26,6 @@ namespace SharpCompress.Common.SevenZip
internal CFileItem Header { get; }
internal CFolder? Folder { get; }
internal int Index { get; }
internal override string FilePartName => Header.Name;
@@ -105,4 +104,4 @@ namespace SharpCompress.Common.SevenZip
internal bool IsEncrypted => Folder!._coders.FindIndex(c => c._methodId._id == CMethodId.K_AES_ID) != -1;
}
}
}

View File

@@ -1,13 +1,13 @@
using System.IO;
using System.IO;
using SharpCompress.Readers;
namespace SharpCompress.Common.SevenZip
{
public class SevenZipVolume : Volume
{
public SevenZipVolume(Stream stream, ReaderOptions readerFactoryOptions)
: base(stream, readerFactoryOptions)
public SevenZipVolume(Stream stream, ReaderOptions readerFactoryOptions, int index = 0)
: base(stream, readerFactoryOptions, index)
{
}
}
}
}

View File

@@ -1,13 +1,13 @@
using System.IO;
using System.IO;
using SharpCompress.Readers;
namespace SharpCompress.Common.Tar
{
public class TarVolume : Volume
{
public TarVolume(Stream stream, ReaderOptions readerOptions)
: base(stream, readerOptions)
public TarVolume(Stream stream, ReaderOptions readerOptions, int index = 0)
: base(stream, readerOptions, index)
{
}
}
}
}

View File

@@ -9,8 +9,9 @@ namespace SharpCompress.Common
{
private readonly Stream _actualStream;
internal Volume(Stream stream, ReaderOptions readerOptions)
internal Volume(Stream stream, ReaderOptions readerOptions, int index = 0)
{
Index = index;
ReaderOptions = readerOptions;
if (readerOptions.LeaveStreamOpen)
{
@@ -29,6 +30,10 @@ namespace SharpCompress.Common
/// </summary>
public virtual bool IsFirstVolume => true;
public virtual int Index { get; internal set; }
public string FileName { get { return (_actualStream as FileStream)?.Name!; } }
/// <summary>
/// RarArchive is part of a multi-part archive.
/// </summary>

View File

@@ -43,12 +43,38 @@ namespace SharpCompress.Common.Zip
{
_decompressionStream ??= GetCompressedStream();
_decompressionStream.Skip();
if (_decompressionStream is DeflateStream deflateStream)
if( Header.CompressionMethod != ZipCompressionMethod.None )
{
rewindableStream.Rewind(deflateStream.InputBuffer);
_decompressionStream.Skip();
if (_decompressionStream is DeflateStream deflateStream)
{
rewindableStream.Rewind(deflateStream.InputBuffer);
}
}
else
{
// We would need to search for the magic word
rewindableStream.Position -= 4;
var pos = rewindableStream.Position;
while( Utility.Find(rewindableStream, new byte[] { 0x50,0x4b,0x07,0x08 } ) )
{
// We should probably check CRC32 for positive matching as well
var size = rewindableStream.Position - pos;
var br = new BinaryReader(rewindableStream);
br.ReadUInt32();
br.ReadUInt32(); // CRC32
var compressed_size = br.ReadUInt32();
var uncompressed_size = br.ReadUInt32();
if (compressed_size == size && compressed_size == uncompressed_size )
{
rewindableStream.Position -= 16;
break;
}
rewindableStream.Position -= 12;
}
}
Skipped = true;
}
var reader = new BinaryReader(rewindableStream);

View File

@@ -1,15 +1,15 @@
using System.IO;
using System.IO;
using SharpCompress.Readers;
namespace SharpCompress.Common.Zip
{
public class ZipVolume : Volume
{
public ZipVolume(Stream stream, ReaderOptions readerOptions)
: base(stream, readerOptions)
public ZipVolume(Stream stream, ReaderOptions readerOptions, int index = 0)
: base(stream, readerOptions, index)
{
}
public string? Comment { get; internal set; }
}
}
}

View File

@@ -297,14 +297,6 @@ namespace SharpCompress.Compressors.LZMA
_outWindow.ReleaseStream();
rangeDecoder.ReleaseStream();
if (!rangeDecoder.IsFinished || (inSize > 0 && rangeDecoder._total != inSize))
{
throw new DataErrorException();
}
if (_outWindow.HasPending)
{
throw new DataErrorException();
}
_outWindow = null;
}
@@ -480,4 +472,4 @@ namespace SharpCompress.Compressors.LZMA
public override void SetLength(long value) {}
*/
}
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.IO;
namespace SharpCompress.IO
@@ -65,6 +65,19 @@ namespace SharpCompress.IO
return value;
}
#if !NETFRAMEWORK && !NETSTANDARD2_0
public override int Read(Span<byte> buffer)
{
var slice_len = BytesLeftToRead < buffer.Length ? BytesLeftToRead : buffer.Length;
var read = Stream.Read(buffer.Slice(0,(int)slice_len));
if (read > 0)
{
BytesLeftToRead -= read;
}
return read;
}
#endif
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
@@ -80,4 +93,4 @@ namespace SharpCompress.IO
throw new NotSupportedException();
}
}
}
}

View File

@@ -132,7 +132,6 @@ namespace SharpCompress.Readers
private void Skip()
{
var part = Entry.Parts.First();
part.Skipped = true;
if (ArchiveType != ArchiveType.Rar
&& !Entry.IsSolid
@@ -145,6 +144,7 @@ namespace SharpCompress.Readers
{
var bytesToAdvance = Entry.CompressedSize;
rawStream.Skip(bytesToAdvance);
part.Skipped = true;
return;
}
}

View File

@@ -1,4 +1,4 @@
using System.IO;
using System.IO;
using SharpCompress.Common.Rar;
using SharpCompress.Common.Rar.Headers;
@@ -6,8 +6,8 @@ namespace SharpCompress.Readers.Rar
{
internal class NonSeekableStreamFilePart : RarFilePart
{
internal NonSeekableStreamFilePart(MarkHeader mh, FileHeader fh)
: base(mh, fh)
internal NonSeekableStreamFilePart(MarkHeader mh, FileHeader fh, int index = 0)
: base(mh, fh, index)
{
}
@@ -18,4 +18,4 @@ namespace SharpCompress.Readers.Rar
internal override string FilePartName => "Unknown Stream - File Entry: " + FileHeader.FileName;
}
}
}

View File

@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.IO;
using SharpCompress.Common.Rar;
using SharpCompress.Common.Rar.Headers;
@@ -8,14 +8,14 @@ namespace SharpCompress.Readers.Rar
{
public class RarReaderVolume : RarVolume
{
internal RarReaderVolume(Stream stream, ReaderOptions options)
: base(StreamingMode.Streaming, stream, options)
internal RarReaderVolume(Stream stream, ReaderOptions options, int index = 0)
: base(StreamingMode.Streaming, stream, options, index)
{
}
internal override RarFilePart CreateFilePart(MarkHeader markHeader, FileHeader fileHeader)
{
return new NonSeekableStreamFilePart(markHeader, fileHeader);
return new NonSeekableStreamFilePart(markHeader, fileHeader, this.Index);
}
internal override IEnumerable<RarFilePart> ReadFileParts()
@@ -23,4 +23,4 @@ namespace SharpCompress.Readers.Rar
return GetVolumeFileParts();
}
}
}
}

View File

@@ -2,9 +2,9 @@
<PropertyGroup>
<AssemblyTitle>SharpCompress - Pure C# Decompression/Compression</AssemblyTitle>
<NeutralLanguage>en-US</NeutralLanguage>
<VersionPrefix>0.32.1</VersionPrefix>
<AssemblyVersion>0.32.1</AssemblyVersion>
<FileVersion>0.32.1</FileVersion>
<VersionPrefix>0.32.2</VersionPrefix>
<AssemblyVersion>0.32.2</AssemblyVersion>
<FileVersion>0.32.2</FileVersion>
<Authors>Adam Hathcock</Authors>
<TargetFrameworks>net461;netstandard2.0;netstandard2.1;netcoreapp3.1;net6.0</TargetFrameworks>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
@@ -15,7 +15,7 @@
<PackageId>SharpCompress</PackageId>
<PackageTags>rar;unrar;zip;unzip;bzip2;gzip;tar;7zip;lzip;xz</PackageTags>
<PackageProjectUrl>https://github.com/adamhathcock/sharpcompress</PackageProjectUrl>
<PackageLicense>https://github.com/adamhathcock/sharpcompress/blob/master/LICENSE.txt</PackageLicense>
<PackageLicenseFile>LICENSE.txt</PackageLicenseFile>
<GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<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>
@@ -30,6 +30,9 @@
<RunAnalyzersDuringBuild>False</RunAnalyzersDuringBuild>
</PropertyGroup>
<ItemGroup>
<None Include="..\..\LICENSE.txt" Pack="true" Visible="false" PackagePath=""/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
</ItemGroup>

View File

@@ -165,6 +165,41 @@ namespace SharpCompress
}
}
public static bool Find(this Stream source, byte[] array)
{
byte[] buffer = GetTransferByteArray();
try
{
var pos = source.Position;
int count = 0;
var len = source.Read(buffer, 0, buffer.Length);
source.Position = pos + len;
do
{
for (int i = 0; i < len; i++)
{
if (array[count] == buffer[i])
{
count++;
if (count == array.Length)
{
source.Position = source.Position - len + i - array.Length +1;
return true;
}
}
}
}
while ((len = source.Read(buffer, 0, buffer.Length)) > 0);
}
finally
{
ArrayPool<byte>.Shared.Return(buffer);
}
return false;
}
public static DateTime DosDateToDateTime(UInt16 iDate, UInt16 iTime)
{
int year = iDate / 512 + 1980;

View File

@@ -37,7 +37,7 @@ namespace SharpCompress.Writers
public static void WriteAll(this IWriter writer,
string directory,
string searchPattern = "*",
Expression<Func<string, bool>>? fileSearchFunc = null,
Func<string, bool>? fileSearchFunc = null,
SearchOption option = SearchOption.TopDirectoryOnly)
{
if (!Directory.Exists(directory))
@@ -49,10 +49,10 @@ namespace SharpCompress.Writers
{
fileSearchFunc = n => true;
}
foreach (var file in Directory.EnumerateFiles(directory, searchPattern, option).Where(fileSearchFunc.Compile()))
foreach (var file in Directory.EnumerateFiles(directory, searchPattern, option).Where(fileSearchFunc))
{
writer.Write(file.Substring(directory.Length), file);
}
}
}
}
}

View File

@@ -173,6 +173,38 @@ namespace SharpCompress.Test
VerifyFiles();
}
protected void ArchiveOpenEntryVolumeIndexTest(int[][] results, ReaderOptions readerOptions = null, params string[] testArchives)
{
ArchiveOpenEntryVolumeIndexTest(results, readerOptions, testArchives.Select(x => Path.Combine(TEST_ARCHIVES_PATH, x)));
}
protected void ArchiveOpenEntryVolumeIndexTest(int[][] results, ReaderOptions readerOptions, IEnumerable<string> testArchives)
{
string[] src = testArchives.ToArray();
using (var archive = ArchiveFactory.Open(testArchives.Select(f => new FileInfo(f)), null))
{
try
{
int idx = 0;
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
{
Assert.Equal(entry.VolumeIndexFirst, results[idx][0]);
Assert.Equal(entry.VolumeIndexLast, results[idx][1]);
Assert.Equal(src[entry.VolumeIndexFirst], archive.Volumes.First(a => a.Index == entry.VolumeIndexFirst).FileName);
Assert.Equal(src[entry.VolumeIndexLast], archive.Volumes.First(a => a.Index == entry.VolumeIndexLast).FileName);
idx++;
}
}
catch (IndexOutOfRangeException)
{
throw;
}
}
}
protected void ArchiveFileRead(string testArchive, ReaderOptions readerOptions = null)
{

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.IO;
using System.Linq;
using SharpCompress.Archives;
@@ -107,5 +107,21 @@ namespace SharpCompress.Test.GZip
Assert.Equal(size, tarStream.Length);
}
}
[Fact]
public void TestGzCrcWithMostSignificaltBitNotNegative()
{
using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz")))
{
using (var archive = GZipArchive.Open(stream))
{
//process all entries in solid archive until the one we want to test
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
{
Assert.InRange(entry.Crc, 0L, 0xFFFFFFFFL);
}
}
}
}
}
}

View File

@@ -435,6 +435,42 @@ namespace SharpCompress.Test.Rar
ArchiveFileRead("Rar2.rar");
}
[Fact]
public void Rar2_ArchiveVersionTest()
{
string testArchive = Path.Combine(TEST_ARCHIVES_PATH, "Rar2.rar");
using (var archive = RarArchive.Open(testArchive))
{
Assert.Equal(2, archive.MinVersion);
Assert.Equal(2, archive.MaxVersion);
}
}
[Fact]
public void Rar4_ArchiveVersionTest()
{
string testArchive = Path.Combine(TEST_ARCHIVES_PATH, "Rar4.multi.part01.rar");
using (var archive = RarArchive.Open(testArchive))
{
Assert.Equal(3, archive.MinVersion);
Assert.Equal(4, archive.MaxVersion);
}
}
[Fact]
public void Rar5_ArchiveVersionTest()
{
string testArchive = Path.Combine(TEST_ARCHIVES_PATH, "Rar5.solid.rar");
using (var archive = RarArchive.Open(testArchive))
{
Assert.Equal(5, archive.MinVersion);
Assert.Equal(6, archive.MaxVersion);
}
}
[Fact]
public void Rar4_Multi_ArchiveFileRead()
{
@@ -575,6 +611,25 @@ namespace SharpCompress.Test.Rar
"Rar4.multi.part07.rar");
}
[Fact]
public void Rar4_Multi_ArchiveOpenEntryVolumeIndexTest()
{
ArchiveOpenEntryVolumeIndexTest(
new[] {
new[] { 0, 1 }, //exe - Rar4.multi.part01.rar to Rar4.multi.part02.rar
new[] { 1, 5 }, //jpg - Rar4.multi.part02.rar to Rar4.multi.part06.rar
new[] { 5, 6 } //txt - Rar4.multi.part06.rar to Rar4.multi.part07.rar
},
null,
"Rar4.multi.part01.rar",
"Rar4.multi.part02.rar",
"Rar4.multi.part03.rar",
"Rar4.multi.part04.rar",
"Rar4.multi.part05.rar",
"Rar4.multi.part06.rar",
"Rar4.multi.part07.rar");
}
[Fact]
public void Rar_Multi_ArchiveFileRead()
{

View File

@@ -1,4 +1,6 @@
using System.IO;
using System;
using System.IO;
using SharpCompress.Compressors.LZMA;
using Xunit;
@@ -9,12 +11,72 @@ namespace SharpCompress.Test.Streams
[Fact]
public void TestLzma2Decompress1Byte()
{
byte[] properties = new byte[] { 0x01 };
byte[] compressedData = new byte[] { 0x01, 0x00, 0x00, 0x58, 0x00 };
MemoryStream lzma2Stream = new MemoryStream(compressedData);
var properties = new byte[] { 0x01 };
var compressedData = new byte[] { 0x01, 0x00, 0x00, 0x58, 0x00 };
var lzma2Stream = new MemoryStream(compressedData);
LzmaStream decompressor = new LzmaStream(properties, lzma2Stream, 5, 1);
var decompressor = new LzmaStream(properties, lzma2Stream, 5, 1);
Assert.Equal('X', decompressor.ReadByte());
}
private static byte[] lzmaData { get; } = new byte[] {
0x5D, 0x00, 0x20, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x24, 0x18, 0x2F, 0xEB, 0x20, 0x78, 0xBA, 0x78, 0x70, 0xDC, 0x43, 0x2C, 0x32, 0xC9,
0xC3, 0x97, 0x4D, 0x10, 0x74, 0xE2, 0x20, 0xBF, 0x5A, 0xB4, 0xB3, 0xC4, 0x31, 0x80, 0x26,
0x3E, 0x6A, 0xEA, 0x51, 0xFC, 0xE4, 0x8D, 0x54, 0x96, 0x05, 0xCC, 0x78, 0x59, 0xAC, 0xD4,
0x21, 0x65, 0x8F, 0xA9, 0xC8, 0x0D, 0x9B, 0xE2, 0xC2, 0xF9, 0x7C, 0x3C, 0xDD, 0x4D, 0x38,
0x04, 0x0B, 0xF8, 0x0B, 0x68, 0xA5, 0x93, 0x6C, 0x64, 0xAC, 0xCF, 0x71, 0x68, 0xE8, 0x69,
0x25, 0xC6, 0x17, 0x28, 0xF1, 0x7C, 0xF1, 0xDC, 0x47, 0x51, 0x4D, 0x1E, 0x0E, 0x0B, 0x80,
0x37, 0x24, 0x58, 0x80, 0xF7, 0xB4, 0xAC, 0x54, 0xF1, 0x0F, 0x7F, 0x0F, 0x0F, 0xF5, 0x9C,
0xDE, 0x54, 0x4F, 0xA3, 0x7B, 0x20, 0xC5, 0xA8, 0x18, 0x3B, 0xED, 0xDC, 0x04, 0xF6, 0xFB,
0x86, 0xE0, 0xAB, 0xB6, 0x87, 0x99, 0x92, 0x43, 0x7B, 0x2C, 0xCC, 0x31, 0x83, 0x90, 0xFF,
0xF1, 0x76, 0x03, 0x90
};
private static byte[] lzmaResultData { get; } = new byte[] {
0x01, 0x00, 0xFD, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x61, 0x18, 0x5F, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x02, 0x00, 0xB4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x3D, 0x61, 0xE5, 0x5E, 0x03,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x12, 0x00, 0x00, 0x00, 0x02, 0x00, 0xB4, 0x01, 0x00, 0x00, 0x00, 0x00, 0xE2, 0x61, 0x18,
0x5F, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00,
0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFD, 0x01, 0x00, 0x00, 0x00, 0x00, 0x14,
0x62, 0x18, 0x5F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x02, 0x00, 0xB4, 0x01, 0x00, 0x00, 0x00,
0x00, 0x7F, 0x61, 0xE5, 0x5E, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0xCB, 0x15, 0x00, 0x00, 0x02, 0x00, 0xB4, 0x01, 0x00,
0x00, 0x00, 0x00, 0x7F, 0x61, 0xE5, 0x5E, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0xCB, 0x15, 0x00, 0x00, 0x02, 0x00, 0xB4,
0x01, 0x00, 0x00, 0x00, 0x00, 0x3D, 0x61, 0xE5, 0x5E, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x02,
0x00, 0xB4, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x96, 0x40, 0x5C, 0x08, 0x00, 0x00, 0x00,
0x60, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x83, 0x12,
0x00, 0xD4, 0x99, 0x00, 0x00, 0x43, 0x95, 0x00, 0x00, 0xEB, 0x7A, 0x00, 0x00, 0x40, 0x6F,
0x00, 0x00, 0xD2, 0x6F, 0x00, 0x00, 0x67, 0x74, 0x00, 0x00, 0x02, 0x69, 0x00, 0x00, 0x76,
0x79, 0x00, 0x00, 0x98, 0x66, 0x00, 0x00, 0x23, 0x25, 0x00, 0x00, 0x01, 0x00, 0xFD, 0x01,
0x00, 0x00, 0x00, 0x00, 0x3B, 0x2F, 0xC0, 0x5F, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x03, 0x00, 0x00, 0x00, 0x69, 0x00, 0x3D, 0x00, 0x0A, 0x00, 0x00, 0x00
};
[Fact]
public void TestLzmaBuffer()
{
var input = new MemoryStream(lzmaData);
using (var output = new MemoryStream())
{
var properties = new byte[5];
input.Read(properties, 0, 5);
var fileLengthBytes = new byte[8];
input.Read(fileLengthBytes, 0, 8);
var fileLength = BitConverter.ToInt64(fileLengthBytes, 0);
var coder = new Decoder();
coder.SetDecoderProperties(properties);
coder.Code(input, output, input.Length, fileLength, null);
Assert.Equal(output.ToArray(), lzmaResultData);
}
}
}
}
}

View File

@@ -680,6 +680,28 @@ namespace SharpCompress.Test.Zip
firstStream.CopyTo(memoryStream);
Assert.Equal(199, memoryStream.Length);
}
var len1 = 0;
var buffer1 = new byte[firstEntry.Size + 256];
using (var firstStream = firstEntry.OpenEntryStream())
{
len1 = firstStream.Read(buffer1, 0, buffer.Length);
}
Assert.Equal(199, len1);
#if !NETFRAMEWORK && !NETSTANDARD2_0
var len2 = 0;
var buffer2 = new byte[firstEntry.Size + 256];
using (var firstStream = firstEntry.OpenEntryStream())
{
len2 = firstStream.Read(buffer2.AsSpan());
}
Assert.Equal(len1, len2);
Assert.Equal(buffer1, buffer2);
#endif
}
}
@@ -716,13 +738,20 @@ namespace SharpCompress.Test.Zip
[Fact]
public void Zip_Uncompressed_Skip_All()
{
string zipPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.uncompressed.zip");
var keys = new string[] { "Folder/File1.txt", "Folder/File2.rtf", "Folder2/File1.txt", "Folder2/File2.txt", "DEADBEEF" };
var zipPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.uncompressed.zip");
using (var stream = File.Open(zipPath, FileMode.Open, FileAccess.Read))
{
IArchive archive = ArchiveFactory.Open(stream);
IReader reader = archive.ExtractAllEntries();
int x = 0;
while (reader.MoveToNextEntry())
;
{
Assert.Equal(keys[x], reader.Entry.Key);
x++;
}
Assert.Equal(4, x);
}
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.IO;
using SharpCompress.Common;
using SharpCompress.IO;
@@ -368,5 +368,52 @@ namespace SharpCompress.Test.Zip
}
}
[Fact]
public void Zip_ReaderMoveToNextEntry()
{
var keys = new string[] { "version", "sizehint", "data/0/metadata", "data/0/records" };
using (var fileStream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "test_477.zip")))
using (var reader = ZipReader.Open(fileStream))
{
foreach( var key in keys)
{
reader.MoveToNextEntry();
Assert.Equal(reader.Entry.Key, key);
}
}
}
[Fact]
public void Issue_685()
{
var count = 0;
using (var fileStream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Issue_685.zip")))
using (var reader = ZipReader.Open(fileStream))
{
while (reader.MoveToNextEntry())
{
count++;
reader.OpenEntryStream().Dispose(); // Uncomment for workaround
}
Assert.Equal(4, count);
}
}
[Fact]
public void Zip_Uncompressed_Skip_All()
{
var zipPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.uncompressed.zip");
using (var stream = File.Open(zipPath, FileMode.Open, FileAccess.Read))
{
using (var reader = ReaderFactory.Open(stream))
{
while (reader.MoveToNextEntry()) { }
}
}
}
}
}

Binary file not shown.

Binary file not shown.