mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-02-04 05:25:00 +00:00
Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b3a4fed8be | ||
|
|
d0b4af6666 | ||
|
|
81ab5c189d | ||
|
|
6ef3be4b5c | ||
|
|
9f90a1d651 | ||
|
|
ce9a3fd1ef | ||
|
|
7c6f05058e | ||
|
|
a8c3a7439e | ||
|
|
839b3ab0cf | ||
|
|
44d54db80e | ||
|
|
a67d7bc429 | ||
|
|
079a818c6c | ||
|
|
6be6ef0b5c | ||
|
|
8e51d9d646 | ||
|
|
ea206f4f02 | ||
|
|
f175a2a252 | ||
|
|
3f7e559b86 | ||
|
|
2959b4d701 | ||
|
|
031286c5eb | ||
|
|
e181fa8c4a | ||
|
|
7b035bec5d | ||
|
|
f39d2bf53a | ||
|
|
7c8e407182 | ||
|
|
a09136d46b | ||
|
|
5fe1363ee1 | ||
|
|
b41823fc10 | ||
|
|
0a64fe28b0 | ||
|
|
e320ccfa9a | ||
|
|
9628ff9456 | ||
|
|
d540f78cfc | ||
|
|
66420cd299 | ||
|
|
dd0594471f | ||
|
|
844ba228ee | ||
|
|
7efc701b32 | ||
|
|
d7e29f7c4d | ||
|
|
f26ba91386 | ||
|
|
c73ac2039c | ||
|
|
671f9cd0cb | ||
|
|
131b5b9714 | ||
|
|
74af0889b9 | ||
|
|
e5ee399045 | ||
| deeb7a0f64 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -13,3 +13,4 @@ project.lock.json
|
||||
test/TestArchives/Scratch
|
||||
.vs
|
||||
tools
|
||||
.vscode
|
||||
|
||||
11
FORMATS.md
11
FORMATS.md
@@ -1,25 +1,28 @@
|
||||
# Archive Formats
|
||||
|
||||
## Accessing Archives
|
||||
|
||||
Archive classes allow random access to a seekable stream.
|
||||
Reader classes allow forward-only reading
|
||||
Writer classes allow forward-only Writing
|
||||
|
||||
## Supported Format Table
|
||||
|
||||
| Archive Format | Compression Format(s) | Compress/Decompress | Archive API | Reader API | Writer API |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| Rar | Rar | Decompress (1) | RarArchive | RarReader | N/A |
|
||||
| Zip (2) | None, DEFLATE, BZip2, LZMA/LZMA2, PPMd | Both | ZipArchive | ZipReader | ZipWriter |
|
||||
| Tar | None, BZip2, GZip | Both | TarArchive | TarReader | TarWriter (3) |
|
||||
| Tar | None, BZip2, GZip, LZip | Both | TarArchive | TarReader | TarWriter (3) |
|
||||
| GZip (single file) | GZip | Both | GZipArchive | GZipReader | GZipWriter |
|
||||
| 7Zip (4) | LZMA, LZMA2, BZip2, PPMd, BCJ, BCJ2, Deflate | Decompress | SevenZipArchive | N/A | N/A |
|
||||
|
||||
1. SOLID Rars are only supported in the RarReader API.
|
||||
2. Zip format supports pkware and WinzipAES encryption. However, encrypted LZMA is not supported.
|
||||
2. Zip format supports pkware and WinzipAES encryption. However, encrypted LZMA is not supported. Zip64 reading is supported.
|
||||
3. The Tar format requires a file size in the header. If no size is specified to the TarWriter and the stream is not seekable, then an exception will be thrown.
|
||||
4. The 7Zip format doesn't allow for reading as a forward-only stream so 7Zip is only supported through the Archive API
|
||||
|
||||
## Compressors
|
||||
|
||||
For those who want to directly compress/decompress bits
|
||||
|
||||
| Compressor | Compress/Decompress |
|
||||
@@ -28,4 +31,6 @@ For those who want to directly compress/decompress bits
|
||||
| GZipStream | Both |
|
||||
| DeflateStream | Both |
|
||||
| LZMAStream | Both |
|
||||
| PPMdStream | Both |
|
||||
| PPMdStream | Both |
|
||||
| ADCStream | Decompress |
|
||||
| LZipStream | Decompress |
|
||||
|
||||
39
README.md
39
README.md
@@ -9,7 +9,7 @@ The major feature is support for non-seekable streams so large files can be proc
|
||||
## Need Help?
|
||||
Post Issues on Github!
|
||||
|
||||
Check the [Supported Formats](FORMATS.md) and [basic usage.](USAGE.md)
|
||||
Check the [Supported Formats](FORMATS.md) and [Basic Usage.](USAGE.md)
|
||||
|
||||
## A Simple Request
|
||||
|
||||
@@ -25,31 +25,64 @@ I'm always looking for help or ideas. Please submit code or email with ideas. Un
|
||||
|
||||
* RAR 5 support
|
||||
* 7Zip writing
|
||||
* Zip64
|
||||
* Zip64 (Need writing and extend Reading)
|
||||
* Multi-volume Zip support.
|
||||
* RAR5 support
|
||||
|
||||
## Version Log
|
||||
|
||||
### Version 0.15.2
|
||||
|
||||
* [Fix invalid headers](https://github.com/adamhathcock/sharpcompress/pull/210) - fixes an issue creating large-ish zip archives that was introduced with zip64 reading.
|
||||
|
||||
### Version 0.15.1
|
||||
|
||||
* [Zip64 extending information and ZipReader](https://github.com/adamhathcock/sharpcompress/pull/206)
|
||||
|
||||
### Version 0.15.0
|
||||
|
||||
* [Add zip64 support for ZipArchive extraction](https://github.com/adamhathcock/sharpcompress/pull/205)
|
||||
|
||||
### Version 0.14.1
|
||||
|
||||
* [.NET Assemblies aren't strong named](https://github.com/adamhathcock/sharpcompress/issues/158)
|
||||
* [Pkware encryption for Zip files didn't allow for multiple reads of an entry](https://github.com/adamhathcock/sharpcompress/issues/197)
|
||||
* [GZip Entry couldn't be read multiple times](https://github.com/adamhathcock/sharpcompress/issues/198)
|
||||
|
||||
### Version 0.14.0
|
||||
|
||||
* [Support for LZip reading in for Tars](https://github.com/adamhathcock/sharpcompress/pull/191)
|
||||
|
||||
### Version 0.13.1
|
||||
|
||||
* [Fix null password on ReaderFactory. Fix null options on SevenZipArchive](https://github.com/adamhathcock/sharpcompress/pull/188)
|
||||
* [Make PpmdProperties lazy to avoid unnecessary allocations.](https://github.com/adamhathcock/sharpcompress/pull/185)
|
||||
|
||||
### Version 0.13.0
|
||||
|
||||
* Breaking change: Big refactor of Options on API.
|
||||
* 7Zip supports Deflate
|
||||
|
||||
### Version 0.12.4
|
||||
|
||||
* Forward only zip issue fix https://github.com/adamhathcock/sharpcompress/issues/160
|
||||
* Try to fix frameworks again by copying targets from JSON.NET
|
||||
|
||||
### Version 0.12.3
|
||||
|
||||
* 7Zip fixes https://github.com/adamhathcock/sharpcompress/issues/73
|
||||
* Maybe all profiles will work with project.json now
|
||||
|
||||
### Version 0.12.2
|
||||
|
||||
* Support Profile 259 again
|
||||
|
||||
### Version 0.12.1
|
||||
|
||||
* Support Silverlight 5
|
||||
|
||||
### Version 0.12.0
|
||||
|
||||
* .NET Core RTM!
|
||||
* Bug fix for Tar long paths
|
||||
|
||||
@@ -102,8 +135,6 @@ I'm always looking for help or ideas. Please submit code or email with ideas. Un
|
||||
* Embedded some BouncyCastle crypto classes to allow RAR Decryption and Winzip AES Decryption in Portable and Windows Store DLLs
|
||||
* Built in Release (I think)
|
||||
|
||||
Some Help/Discussion: https://sharpcompress.codeplex.com/discussions
|
||||
|
||||
7Zip implementation based on: https://code.google.com/p/managed-lzma/
|
||||
|
||||
LICENSE
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.24720.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F18F1765-4A02-42FD-9BEF-F0E2FCBD9D17}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
global.json = global.json
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SharpCompress", "src\SharpCompress\SharpCompress.xproj", "{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{3C5BE746-03E5-4895-9988-0B57F162F86C}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{0F0901FF-E8D9-426A-B5A2-17C7F47C1529}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SharpCompress.Test", "test\SharpCompress.Test\SharpCompress.Test.xproj", "{3B80E585-A2F3-4666-8F69-C7FFDA0DD7E5}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998} = {FD19DDD8-72B2-4024-8665-0D1F7A2AA998}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3B80E585-A2F3-4666-8F69-C7FFDA0DD7E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3B80E585-A2F3-4666-8F69-C7FFDA0DD7E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3B80E585-A2F3-4666-8F69-C7FFDA0DD7E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3B80E585-A2F3-4666-8F69-C7FFDA0DD7E5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998} = {3C5BE746-03E5-4895-9988-0B57F162F86C}
|
||||
{3B80E585-A2F3-4666-8F69-C7FFDA0DD7E5} = {0F0901FF-E8D9-426A-B5A2-17C7F47C1529}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.24720.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F18F1765-4A02-42FD-9BEF-F0E2FCBD9D17}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
global.json = global.json
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SharpCompress", "src\SharpCompress\SharpCompress.xproj", "{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{3C5BE746-03E5-4895-9988-0B57F162F86C}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{0F0901FF-E8D9-426A-B5A2-17C7F47C1529}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SharpCompress.Test", "test\SharpCompress.Test\SharpCompress.Test.xproj", "{3B80E585-A2F3-4666-8F69-C7FFDA0DD7E5}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998} = {FD19DDD8-72B2-4024-8665-0D1F7A2AA998}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3B80E585-A2F3-4666-8F69-C7FFDA0DD7E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3B80E585-A2F3-4666-8F69-C7FFDA0DD7E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3B80E585-A2F3-4666-8F69-C7FFDA0DD7E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3B80E585-A2F3-4666-8F69-C7FFDA0DD7E5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{FD19DDD8-72B2-4024-8665-0D1F7A2AA998} = {3C5BE746-03E5-4895-9988-0B57F162F86C}
|
||||
{3B80E585-A2F3-4666-8F69-C7FFDA0DD7E5} = {0F0901FF-E8D9-426A-B5A2-17C7F47C1529}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
BIN
SharpCompress.snk
Normal file
BIN
SharpCompress.snk
Normal file
Binary file not shown.
6
USAGE.md
6
USAGE.md
@@ -80,7 +80,7 @@ using (var archive = RarArchive.Open("Test.rar"))
|
||||
### Use ReaderFactory to autodetect archive type and Open the entry stream
|
||||
|
||||
```C#
|
||||
using (Stream stream = File.OpenRead("Tar.tar.bz2")))
|
||||
using (Stream stream = File.OpenRead("Tar.tar.bz2"))
|
||||
using (var reader = ReaderFactory.Open(stream))
|
||||
{
|
||||
while (reader.MoveToNextEntry())
|
||||
@@ -101,7 +101,7 @@ using (var reader = ReaderFactory.Open(stream))
|
||||
### Use ReaderFactory to autodetect archive type and Open the entry stream
|
||||
|
||||
```C#
|
||||
using (Stream stream = File.OpenRead("Tar.tar.bz2")))
|
||||
using (Stream stream = File.OpenRead("Tar.tar.bz2"))
|
||||
using (var reader = ReaderFactory.Open(stream))
|
||||
{
|
||||
while (reader.MoveToNextEntry())
|
||||
@@ -128,4 +128,4 @@ using (var writer = WriterFactory.Open(stream, ArchiveType.Tar, new WriterOption
|
||||
{
|
||||
writer.WriteAll("D:\\temp", "*", SearchOption.AllDirectories);
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
version: '0.13.{build}'
|
||||
version: '0.15.{build}'
|
||||
|
||||
init:
|
||||
- git config --global core.autocrlf true
|
||||
|
||||
@@ -14,6 +14,12 @@ namespace SharpCompress.Archives.GZip
|
||||
|
||||
public virtual Stream OpenEntryStream()
|
||||
{
|
||||
//this is to reset the stream to be read multiple times
|
||||
var part = Parts.Single() as GZipFilePart;
|
||||
if (part.GetRawStream().Position != part.EntryStartPosition)
|
||||
{
|
||||
part.GetRawStream().Position = part.EntryStartPosition;
|
||||
}
|
||||
return Parts.Single().GetCompressedStream();
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace SharpCompress.Archives.SevenZip
|
||||
/// </summary>
|
||||
/// <param name="fileInfo"></param>
|
||||
/// <param name="readerOptions"></param>
|
||||
public static SevenZipArchive Open(FileInfo fileInfo, ReaderOptions readerOptions)
|
||||
public static SevenZipArchive Open(FileInfo fileInfo, ReaderOptions readerOptions = null)
|
||||
{
|
||||
fileInfo.CheckNotNull("fileInfo");
|
||||
return new SevenZipArchive(fileInfo, readerOptions ?? new ReaderOptions());
|
||||
@@ -44,7 +44,7 @@ namespace SharpCompress.Archives.SevenZip
|
||||
public static SevenZipArchive Open(Stream stream, ReaderOptions readerOptions = null)
|
||||
{
|
||||
stream.CheckNotNull("stream");
|
||||
return new SevenZipArchive(stream, readerOptions);
|
||||
return new SevenZipArchive(stream, readerOptions ?? new ReaderOptions());
|
||||
}
|
||||
|
||||
#if !NO_FILE
|
||||
|
||||
@@ -4,6 +4,22 @@ using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: AssemblyTitle("SharpCompress")]
|
||||
[assembly: AssemblyProduct("SharpCompress")]
|
||||
[assembly: InternalsVisibleTo("SharpCompress.Test")]
|
||||
[assembly: InternalsVisibleTo("SharpCompress.Test.Portable")]
|
||||
[assembly: CLSCompliant(true)]
|
||||
[assembly: InternalsVisibleTo("SharpCompress.Test" + SharpCompress.AssemblyInfo.PublicKeySuffix)]
|
||||
[assembly: InternalsVisibleTo("SharpCompress.Test.Portable" + SharpCompress.AssemblyInfo.PublicKeySuffix)]
|
||||
[assembly: CLSCompliant(true)]
|
||||
|
||||
namespace SharpCompress
|
||||
{
|
||||
/// <summary>
|
||||
/// Just a static class to house the public key, to avoid repetition.
|
||||
/// </summary>
|
||||
internal static class AssemblyInfo
|
||||
{
|
||||
internal const string PublicKeySuffix =
|
||||
",PublicKey=002400000480000094000000060200000024000052534131000400000100010059acfa17d26c44" +
|
||||
"7a4d03f16eaa72c9187c04f16e6569dd168b080e39a6f5c9fd00f28c768cd8e9a089d5a0e1b34c" +
|
||||
"cd971488e7afe030ce5ce8df2053cf12ec89f6d38065c434c09ee6af3ee284c5dc08f44774b679" +
|
||||
"bf39298e57efe30d4b00aecf9e4f6f8448b2cb0146d8956dfcab606cc64a0ac38c60a7d78b0d65" +
|
||||
"d3b98dc0";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
LZMA,
|
||||
BCJ,
|
||||
BCJ2,
|
||||
LZip,
|
||||
Unknown
|
||||
}
|
||||
}
|
||||
@@ -16,9 +16,12 @@ namespace SharpCompress.Common.GZip
|
||||
internal GZipFilePart(Stream stream)
|
||||
{
|
||||
ReadAndValidateGzipHeader(stream);
|
||||
EntryStartPosition = stream.Position;
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
internal long EntryStartPosition { get; }
|
||||
|
||||
internal DateTime? DateModified { get; private set; }
|
||||
|
||||
internal override string FilePartName { get { return name; } }
|
||||
|
||||
@@ -8,10 +8,10 @@ namespace SharpCompress.Common
|
||||
{
|
||||
private readonly Stream actualStream;
|
||||
|
||||
internal Volume(Stream stream, ReaderOptions readerFactoryOptions)
|
||||
internal Volume(Stream stream, ReaderOptions readerOptions)
|
||||
{
|
||||
actualStream = stream;
|
||||
ReaderOptions = readerFactoryOptions;
|
||||
ReaderOptions = readerOptions;
|
||||
}
|
||||
|
||||
internal Stream Stream { get { return new NonDisposingStream(actualStream); } }
|
||||
|
||||
@@ -48,5 +48,15 @@ namespace SharpCompress.Common.Zip.Headers
|
||||
public byte[] Comment { get; private set; }
|
||||
|
||||
public ushort TotalNumberOfEntries { get; private set; }
|
||||
|
||||
public bool IsZip64
|
||||
{
|
||||
get
|
||||
{
|
||||
return TotalNumberOfEntriesInDisk == ushort.MaxValue
|
||||
|| DirectorySize == uint.MaxValue
|
||||
|| DirectoryStartOffsetRelativeToDisk == uint.MaxValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.IO;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace SharpCompress.Common.Zip.Headers
|
||||
@@ -41,6 +42,23 @@ namespace SharpCompress.Common.Zip.Headers
|
||||
{
|
||||
Name = ((ExtraUnicodePathExtraField)unicodePathExtra).UnicodeName;
|
||||
}
|
||||
|
||||
var zip64ExtraData = Extra.OfType<Zip64ExtendedInformationExtraField>().FirstOrDefault();
|
||||
if (zip64ExtraData != null)
|
||||
{
|
||||
if (CompressedSize == uint.MaxValue)
|
||||
{
|
||||
CompressedSize = zip64ExtraData.CompressedSize;
|
||||
}
|
||||
if (UncompressedSize == uint.MaxValue)
|
||||
{
|
||||
UncompressedSize = zip64ExtraData.UncompressedSize;
|
||||
}
|
||||
if (RelativeOffsetOfEntryHeader == uint.MaxValue)
|
||||
{
|
||||
RelativeOffsetOfEntryHeader = zip64ExtraData.RelativeOffsetOfEntryHeader;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal override void Write(BinaryWriter writer)
|
||||
@@ -52,8 +70,8 @@ namespace SharpCompress.Common.Zip.Headers
|
||||
writer.Write(LastModifiedTime);
|
||||
writer.Write(LastModifiedDate);
|
||||
writer.Write(Crc);
|
||||
writer.Write(CompressedSize);
|
||||
writer.Write(UncompressedSize);
|
||||
writer.Write((uint)CompressedSize);
|
||||
writer.Write((uint)UncompressedSize);
|
||||
|
||||
byte[] nameBytes = EncodeString(Name);
|
||||
writer.Write((ushort)nameBytes.Length);
|
||||
@@ -77,7 +95,7 @@ namespace SharpCompress.Common.Zip.Headers
|
||||
|
||||
public ushort VersionNeededToExtract { get; set; }
|
||||
|
||||
public uint RelativeOffsetOfEntryHeader { get; set; }
|
||||
public long RelativeOffsetOfEntryHeader { get; set; }
|
||||
|
||||
public uint ExternalFileAttributes { get; set; }
|
||||
|
||||
|
||||
@@ -32,6 +32,19 @@ namespace SharpCompress.Common.Zip.Headers
|
||||
{
|
||||
Name = ((ExtraUnicodePathExtraField)unicodePathExtra).UnicodeName;
|
||||
}
|
||||
|
||||
var zip64ExtraData = Extra.OfType<Zip64ExtendedInformationExtraField>().FirstOrDefault();
|
||||
if (zip64ExtraData != null)
|
||||
{
|
||||
if (CompressedSize == uint.MaxValue)
|
||||
{
|
||||
CompressedSize = zip64ExtraData.CompressedSize;
|
||||
}
|
||||
if (UncompressedSize == uint.MaxValue)
|
||||
{
|
||||
UncompressedSize = zip64ExtraData.UncompressedSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal override void Write(BinaryWriter writer)
|
||||
@@ -42,8 +55,8 @@ namespace SharpCompress.Common.Zip.Headers
|
||||
writer.Write(LastModifiedTime);
|
||||
writer.Write(LastModifiedDate);
|
||||
writer.Write(Crc);
|
||||
writer.Write(CompressedSize);
|
||||
writer.Write(UncompressedSize);
|
||||
writer.Write((uint)CompressedSize);
|
||||
writer.Write((uint)UncompressedSize);
|
||||
|
||||
byte[] nameBytes = EncodeString(Name);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using SharpCompress.Converters;
|
||||
|
||||
namespace SharpCompress.Common.Zip.Headers
|
||||
{
|
||||
@@ -11,7 +12,8 @@ namespace SharpCompress.Common.Zip.Headers
|
||||
|
||||
// Third Party Mappings
|
||||
// -Info-ZIP Unicode Path Extra Field
|
||||
UnicodePathExtraField = 0x7075
|
||||
UnicodePathExtraField = 0x7075,
|
||||
Zip64ExtendedInformationExtraField = 0x0001
|
||||
}
|
||||
|
||||
internal class ExtraData
|
||||
@@ -47,6 +49,73 @@ namespace SharpCompress.Common.Zip.Headers
|
||||
}
|
||||
}
|
||||
|
||||
internal class Zip64ExtendedInformationExtraField : ExtraData
|
||||
{
|
||||
|
||||
public Zip64ExtendedInformationExtraField(ExtraDataType type, ushort length, byte[] dataBytes)
|
||||
{
|
||||
Type = type;
|
||||
Length = length;
|
||||
DataBytes = dataBytes;
|
||||
Process();
|
||||
}
|
||||
|
||||
//From the spec values are only in the extradata if the standard
|
||||
//value is set to 0xFFFF, but if one of the sizes are present, both are.
|
||||
//Hence if length == 4 volume only
|
||||
// if length == 8 offset only
|
||||
// if length == 12 offset + volume
|
||||
// if length == 16 sizes only
|
||||
// if length == 20 sizes + volume
|
||||
// if length == 24 sizes + offset
|
||||
// if length == 28 everything.
|
||||
//It is unclear how many of these are used in the wild.
|
||||
|
||||
private void Process()
|
||||
{
|
||||
switch (DataBytes.Length)
|
||||
{
|
||||
case 4:
|
||||
VolumeNumber = DataConverter.LittleEndian.GetUInt32(DataBytes, 0);
|
||||
return;
|
||||
case 8:
|
||||
RelativeOffsetOfEntryHeader = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 0);
|
||||
return;
|
||||
case 12:
|
||||
RelativeOffsetOfEntryHeader = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 0);
|
||||
VolumeNumber = DataConverter.LittleEndian.GetUInt32(DataBytes, 8);
|
||||
return;
|
||||
case 16:
|
||||
UncompressedSize = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 0);
|
||||
CompressedSize = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 8);
|
||||
return;
|
||||
case 20:
|
||||
UncompressedSize = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 0);
|
||||
CompressedSize = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 8);
|
||||
VolumeNumber = DataConverter.LittleEndian.GetUInt32(DataBytes, 16);
|
||||
return;
|
||||
case 24:
|
||||
UncompressedSize = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 0);
|
||||
CompressedSize = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 8);
|
||||
RelativeOffsetOfEntryHeader = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 16);
|
||||
return;
|
||||
case 28:
|
||||
UncompressedSize = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 0);
|
||||
CompressedSize = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 8);
|
||||
RelativeOffsetOfEntryHeader = (long)DataConverter.LittleEndian.GetUInt64(DataBytes, 16);
|
||||
VolumeNumber = DataConverter.LittleEndian.GetUInt32(DataBytes, 24);
|
||||
return;
|
||||
default:
|
||||
throw new ArchiveException("Unexpected size of of Zip64 extended information extra field");
|
||||
}
|
||||
}
|
||||
|
||||
public long UncompressedSize { get; private set; }
|
||||
public long CompressedSize { get; private set; }
|
||||
public long RelativeOffsetOfEntryHeader { get; private set; }
|
||||
public uint VolumeNumber { get; private set; }
|
||||
}
|
||||
|
||||
internal static class LocalEntryHeaderExtraFactory
|
||||
{
|
||||
internal static ExtraData Create(ExtraDataType type, ushort length, byte[] extraData)
|
||||
@@ -60,6 +129,13 @@ namespace SharpCompress.Common.Zip.Headers
|
||||
Length = length,
|
||||
DataBytes = extraData
|
||||
};
|
||||
case ExtraDataType.Zip64ExtendedInformationExtraField:
|
||||
return new Zip64ExtendedInformationExtraField
|
||||
(
|
||||
type,
|
||||
length,
|
||||
extraData
|
||||
);
|
||||
default:
|
||||
return new ExtraData
|
||||
{
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace SharpCompress.Common.Zip.Headers
|
||||
{
|
||||
internal class Zip64DirectoryEndHeader : ZipHeader
|
||||
{
|
||||
public Zip64DirectoryEndHeader()
|
||||
: base(ZipHeaderType.Zip64DirectoryEnd)
|
||||
{
|
||||
}
|
||||
|
||||
internal override void Read(BinaryReader reader)
|
||||
{
|
||||
SizeOfDirectoryEndRecord = (long)reader.ReadUInt64();
|
||||
VersionMadeBy = reader.ReadUInt16();
|
||||
VersionNeededToExtract = reader.ReadUInt16();
|
||||
VolumeNumber = reader.ReadUInt32();
|
||||
FirstVolumeWithDirectory = reader.ReadUInt32();
|
||||
TotalNumberOfEntriesInDisk = (long)reader.ReadUInt64();
|
||||
TotalNumberOfEntries = (long)reader.ReadUInt64();
|
||||
DirectorySize = (long)reader.ReadUInt64();
|
||||
DirectoryStartOffsetRelativeToDisk = (long)reader.ReadUInt64();
|
||||
DataSector = reader.ReadBytes((int)(SizeOfDirectoryEndRecord - SizeOfFixedHeaderDataExceptSignatureAndSizeFields));
|
||||
}
|
||||
|
||||
const int SizeOfFixedHeaderDataExceptSignatureAndSizeFields = 44;
|
||||
|
||||
internal override void Write(BinaryWriter writer)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public long SizeOfDirectoryEndRecord { get; private set; }
|
||||
|
||||
public ushort VersionMadeBy { get; private set; }
|
||||
|
||||
public ushort VersionNeededToExtract { get; private set; }
|
||||
|
||||
public uint VolumeNumber { get; private set; }
|
||||
|
||||
public uint FirstVolumeWithDirectory { get; private set; }
|
||||
|
||||
public long TotalNumberOfEntriesInDisk { get; private set; }
|
||||
|
||||
public long TotalNumberOfEntries { get; private set; }
|
||||
|
||||
public long DirectorySize { get; private set; }
|
||||
|
||||
public long DirectoryStartOffsetRelativeToDisk { get; private set; }
|
||||
|
||||
public byte[] DataSector { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System.IO;
|
||||
|
||||
namespace SharpCompress.Common.Zip.Headers
|
||||
{
|
||||
internal class Zip64DirectoryEndLocatorHeader : ZipHeader
|
||||
{
|
||||
public Zip64DirectoryEndLocatorHeader()
|
||||
: base(ZipHeaderType.Zip64DirectoryEndLocator)
|
||||
{
|
||||
}
|
||||
|
||||
internal override void Read(BinaryReader reader)
|
||||
{
|
||||
FirstVolumeWithDirectory = reader.ReadUInt32();
|
||||
RelativeOffsetOfTheEndOfDirectoryRecord = (long)reader.ReadUInt64();
|
||||
TotalNumberOfVolumes = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
internal override void Write(BinaryWriter writer)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public uint FirstVolumeWithDirectory { get; private set; }
|
||||
|
||||
public long RelativeOffsetOfTheEndOfDirectoryRecord { get; private set; }
|
||||
|
||||
public uint TotalNumberOfVolumes { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -57,15 +57,31 @@ namespace SharpCompress.Common.Zip.Headers
|
||||
|
||||
internal ZipCompressionMethod CompressionMethod { get; set; }
|
||||
|
||||
internal uint CompressedSize { get; set; }
|
||||
internal long CompressedSize { get; set; }
|
||||
|
||||
internal long? DataStartPosition { get; set; }
|
||||
|
||||
internal uint UncompressedSize { get; set; }
|
||||
internal long UncompressedSize { get; set; }
|
||||
|
||||
internal List<ExtraData> Extra { get; set; }
|
||||
|
||||
public string Password { get; set; }
|
||||
|
||||
internal PkwareTraditionalEncryptionData ComposeEncryptionData(Stream archiveStream)
|
||||
{
|
||||
if (archiveStream == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(archiveStream));
|
||||
}
|
||||
|
||||
var buffer = new byte[12];
|
||||
archiveStream.Read(buffer, 0, 12);
|
||||
|
||||
PkwareTraditionalEncryptionData encryptionData = PkwareTraditionalEncryptionData.ForRead(Password, this, buffer);
|
||||
|
||||
return encryptionData;
|
||||
}
|
||||
|
||||
internal PkwareTraditionalEncryptionData PkwareTraditionalEncryptionData { get; set; }
|
||||
#if !NO_CRYPTO
|
||||
internal WinzipAesEncryptionData WinzipAesEncryptionData { get; set; }
|
||||
#endif
|
||||
@@ -96,5 +112,7 @@ namespace SharpCompress.Common.Zip.Headers
|
||||
}
|
||||
|
||||
internal ZipFilePart Part { get; set; }
|
||||
|
||||
internal bool IsZip64 { get { return CompressedSize == uint.MaxValue; } }
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@
|
||||
LocalEntry,
|
||||
DirectoryEntry,
|
||||
DirectoryEnd,
|
||||
Split
|
||||
Split,
|
||||
Zip64DirectoryEnd,
|
||||
Zip64DirectoryEndLocator
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ namespace SharpCompress.Common.Zip
|
||||
internal class SeekableZipHeaderFactory : ZipHeaderFactory
|
||||
{
|
||||
private const int MAX_ITERATIONS_FOR_DIRECTORY_HEADER = 4096;
|
||||
private bool zip64;
|
||||
|
||||
internal SeekableZipHeaderFactory(string password)
|
||||
: base(StreamingMode.Seekable, password)
|
||||
@@ -16,11 +17,56 @@ namespace SharpCompress.Common.Zip
|
||||
}
|
||||
|
||||
internal IEnumerable<DirectoryEntryHeader> ReadSeekableHeader(Stream stream)
|
||||
{
|
||||
var reader = new BinaryReader(stream);
|
||||
|
||||
SeekBackToHeader(stream, reader, DIRECTORY_END_HEADER_BYTES);
|
||||
var entry = new DirectoryEndHeader();
|
||||
entry.Read(reader);
|
||||
|
||||
if (entry.IsZip64)
|
||||
{
|
||||
zip64 = true;
|
||||
SeekBackToHeader(stream, reader, ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR);
|
||||
var zip64Locator = new Zip64DirectoryEndLocatorHeader();
|
||||
zip64Locator.Read(reader);
|
||||
|
||||
stream.Seek(zip64Locator.RelativeOffsetOfTheEndOfDirectoryRecord, SeekOrigin.Begin);
|
||||
uint zip64Signature = reader.ReadUInt32();
|
||||
if(zip64Signature != ZIP64_END_OF_CENTRAL_DIRECTORY)
|
||||
throw new ArchiveException("Failed to locate the Zip64 Header");
|
||||
|
||||
var zip64Entry = new Zip64DirectoryEndHeader();
|
||||
zip64Entry.Read(reader);
|
||||
stream.Seek(zip64Entry.DirectoryStartOffsetRelativeToDisk, SeekOrigin.Begin);
|
||||
}
|
||||
else
|
||||
{
|
||||
stream.Seek(entry.DirectoryStartOffsetRelativeToDisk, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
long position = stream.Position;
|
||||
while (true)
|
||||
{
|
||||
stream.Position = position;
|
||||
uint signature = reader.ReadUInt32();
|
||||
var directoryEntryHeader = ReadHeader(signature, reader, zip64) as DirectoryEntryHeader;
|
||||
position = stream.Position;
|
||||
if (directoryEntryHeader == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
//entry could be zero bytes so we need to know that.
|
||||
directoryEntryHeader.HasData = directoryEntryHeader.CompressedSize != 0;
|
||||
yield return directoryEntryHeader;
|
||||
}
|
||||
}
|
||||
|
||||
private static void SeekBackToHeader(Stream stream, BinaryReader reader, uint headerSignature)
|
||||
{
|
||||
long offset = 0;
|
||||
uint signature;
|
||||
BinaryReader reader = new BinaryReader(stream);
|
||||
|
||||
int iterationCount = 0;
|
||||
do
|
||||
{
|
||||
@@ -34,33 +80,10 @@ namespace SharpCompress.Common.Zip
|
||||
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.");
|
||||
throw new ArchiveException("Could not find Zip file Directory at the end of the file. File may be corrupted.");
|
||||
}
|
||||
}
|
||||
while (signature != DIRECTORY_END_HEADER_BYTES);
|
||||
|
||||
var entry = new DirectoryEndHeader();
|
||||
entry.Read(reader);
|
||||
stream.Seek(entry.DirectoryStartOffsetRelativeToDisk, SeekOrigin.Begin);
|
||||
|
||||
DirectoryEntryHeader directoryEntryHeader = null;
|
||||
long position = stream.Position;
|
||||
while (true)
|
||||
{
|
||||
stream.Position = position;
|
||||
signature = reader.ReadUInt32();
|
||||
directoryEntryHeader = ReadHeader(signature, reader) as DirectoryEntryHeader;
|
||||
position = stream.Position;
|
||||
if (directoryEntryHeader == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
//entry could be zero bytes so we need to know that.
|
||||
directoryEntryHeader.HasData = directoryEntryHeader.CompressedSize != 0;
|
||||
yield return directoryEntryHeader;
|
||||
}
|
||||
while (signature != headerSignature);
|
||||
}
|
||||
|
||||
internal LocalEntryHeader GetLocalHeader(Stream stream, DirectoryEntryHeader directoryEntryHeader)
|
||||
@@ -68,7 +91,7 @@ namespace SharpCompress.Common.Zip
|
||||
stream.Seek(directoryEntryHeader.RelativeOffsetOfEntryHeader, SeekOrigin.Begin);
|
||||
BinaryReader reader = new BinaryReader(stream);
|
||||
uint signature = reader.ReadUInt32();
|
||||
var localEntryHeader = ReadHeader(signature, reader) as LocalEntryHeader;
|
||||
var localEntryHeader = ReadHeader(signature, reader, zip64) as LocalEntryHeader;
|
||||
if (localEntryHeader == null)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace SharpCompress.Common.Zip
|
||||
ZipHeader header = null;
|
||||
BinaryReader reader = new BinaryReader(rewindableStream);
|
||||
if (lastEntryHeader != null &&
|
||||
FlagUtility.HasFlag(lastEntryHeader.Flags, HeaderFlags.UsePostDataDescriptor))
|
||||
(FlagUtility.HasFlag(lastEntryHeader.Flags, HeaderFlags.UsePostDataDescriptor) || lastEntryHeader.IsZip64))
|
||||
{
|
||||
reader = (lastEntryHeader.Part as StreamingZipFilePart).FixStreamedFileLocation(ref rewindableStream);
|
||||
long? pos = rewindableStream.CanSeek ? (long?)rewindableStream.Position : null;
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace SharpCompress.Common.Zip
|
||||
|
||||
protected abstract Stream CreateBaseStream();
|
||||
|
||||
protected bool LeaveStreamOpen { get { return FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor); } }
|
||||
protected bool LeaveStreamOpen { get { return FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor) || Header.IsZip64; } }
|
||||
|
||||
protected Stream CreateDecompressionStream(Stream stream)
|
||||
{
|
||||
@@ -126,18 +126,16 @@ namespace SharpCompress.Common.Zip
|
||||
|
||||
protected Stream GetCryptoStream(Stream plainStream)
|
||||
{
|
||||
if ((Header.CompressedSize == 0)
|
||||
#if !NO_CRYPTO
|
||||
&& ((Header.PkwareTraditionalEncryptionData != null)
|
||||
|| (Header.WinzipAesEncryptionData != null)))
|
||||
#else
|
||||
&& (Header.PkwareTraditionalEncryptionData != null))
|
||||
#endif
|
||||
bool isFileEncrypted = FlagUtility.HasFlag(Header.Flags, HeaderFlags.Encrypted);
|
||||
|
||||
if (Header.CompressedSize == 0 && isFileEncrypted)
|
||||
{
|
||||
throw new NotSupportedException("Cannot encrypt file with unknown size at start.");
|
||||
}
|
||||
if ((Header.CompressedSize == 0)
|
||||
|
||||
if ((Header.CompressedSize == 0
|
||||
&& FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor))
|
||||
|| Header.IsZip64)
|
||||
{
|
||||
plainStream = new NonDisposingStream(plainStream); //make sure AES doesn't close
|
||||
}
|
||||
@@ -145,18 +143,40 @@ namespace SharpCompress.Common.Zip
|
||||
{
|
||||
plainStream = new ReadOnlySubStream(plainStream, Header.CompressedSize); //make sure AES doesn't close
|
||||
}
|
||||
if (Header.PkwareTraditionalEncryptionData != null)
|
||||
|
||||
if (isFileEncrypted)
|
||||
{
|
||||
return new PkwareTraditionalCryptoStream(plainStream, Header.PkwareTraditionalEncryptionData,
|
||||
CryptoMode.Decrypt);
|
||||
}
|
||||
switch (Header.CompressionMethod)
|
||||
{
|
||||
case ZipCompressionMethod.None:
|
||||
case ZipCompressionMethod.Deflate:
|
||||
case ZipCompressionMethod.Deflate64:
|
||||
case ZipCompressionMethod.BZip2:
|
||||
case ZipCompressionMethod.LZMA:
|
||||
case ZipCompressionMethod.PPMd:
|
||||
{
|
||||
return new PkwareTraditionalCryptoStream(plainStream, Header.ComposeEncryptionData(plainStream), CryptoMode.Decrypt);
|
||||
}
|
||||
|
||||
case ZipCompressionMethod.WinzipAes:
|
||||
{
|
||||
#if !NO_FILE
|
||||
if (Header.WinzipAesEncryptionData != null)
|
||||
{
|
||||
//only read 10 less because the last ten are auth bytes
|
||||
return new WinzipAesCryptoStream(plainStream, Header.WinzipAesEncryptionData, Header.CompressedSize - 10);
|
||||
}
|
||||
if (Header.WinzipAesEncryptionData != null)
|
||||
{
|
||||
return new WinzipAesCryptoStream(plainStream, Header.WinzipAesEncryptionData, Header.CompressedSize - 10);
|
||||
}
|
||||
#endif
|
||||
return plainStream;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return plainStream;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,8 @@ namespace SharpCompress.Common.Zip
|
||||
internal const uint DIGITAL_SIGNATURE = 0x05054b50;
|
||||
internal const uint SPLIT_ARCHIVE_HEADER_BYTES = 0x30304b50;
|
||||
|
||||
private const uint ZIP64_END_OF_CENTRAL_DIRECTORY = 0x06064b50;
|
||||
private const uint ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR = 0x07064b50;
|
||||
internal const uint ZIP64_END_OF_CENTRAL_DIRECTORY = 0x06064b50;
|
||||
internal const uint ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR = 0x07064b50;
|
||||
|
||||
protected LocalEntryHeader lastEntryHeader;
|
||||
private readonly string password;
|
||||
@@ -30,7 +30,7 @@ namespace SharpCompress.Common.Zip
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
protected ZipHeader ReadHeader(uint headerBytes, BinaryReader reader)
|
||||
protected ZipHeader ReadHeader(uint headerBytes, BinaryReader reader, bool zip64 = false)
|
||||
{
|
||||
switch (headerBytes)
|
||||
{
|
||||
@@ -54,14 +54,12 @@ namespace SharpCompress.Common.Zip
|
||||
if (FlagUtility.HasFlag(lastEntryHeader.Flags, HeaderFlags.UsePostDataDescriptor))
|
||||
{
|
||||
lastEntryHeader.Crc = reader.ReadUInt32();
|
||||
lastEntryHeader.CompressedSize = reader.ReadUInt32();
|
||||
lastEntryHeader.UncompressedSize = reader.ReadUInt32();
|
||||
lastEntryHeader.CompressedSize = zip64 ? (long)reader.ReadUInt64() : reader.ReadUInt32();
|
||||
lastEntryHeader.UncompressedSize = zip64 ? (long)reader.ReadUInt64() : reader.ReadUInt32();
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.ReadUInt32();
|
||||
reader.ReadUInt32();
|
||||
reader.ReadUInt32();
|
||||
reader.ReadBytes(zip64 ? 20 : 12);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -78,9 +76,14 @@ namespace SharpCompress.Common.Zip
|
||||
return new SplitHeader();
|
||||
}
|
||||
case ZIP64_END_OF_CENTRAL_DIRECTORY:
|
||||
{
|
||||
var entry = new Zip64DirectoryEndHeader();
|
||||
entry.Read(reader);
|
||||
return entry;
|
||||
}
|
||||
case ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR:
|
||||
{
|
||||
var entry = new IgnoreHeader(ZipHeaderType.Ignore);
|
||||
var entry = new Zip64DirectoryEndLocatorHeader();
|
||||
entry.Read(reader);
|
||||
return entry;
|
||||
}
|
||||
@@ -111,46 +114,43 @@ namespace SharpCompress.Common.Zip
|
||||
{
|
||||
if (FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.Encrypted))
|
||||
{
|
||||
if (!entryHeader.IsDirectory &&
|
||||
entryHeader.CompressedSize == 0 &&
|
||||
if (!entryHeader.IsDirectory && entryHeader.CompressedSize == 0 &&
|
||||
FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.UsePostDataDescriptor))
|
||||
{
|
||||
throw new NotSupportedException(
|
||||
"SharpCompress cannot currently read non-seekable Zip Streams with encrypted data that has been written in a non-seekable manner.");
|
||||
throw new NotSupportedException("SharpCompress cannot currently read non-seekable Zip Streams with encrypted data that has been written in a non-seekable manner.");
|
||||
}
|
||||
|
||||
if (password == null)
|
||||
{
|
||||
throw new CryptographicException("No password supplied for encrypted zip.");
|
||||
}
|
||||
if (entryHeader.CompressionMethod != ZipCompressionMethod.WinzipAes)
|
||||
{
|
||||
byte[] buffer = new byte[12];
|
||||
stream.Read(buffer, 0, 12);
|
||||
entryHeader.PkwareTraditionalEncryptionData = PkwareTraditionalEncryptionData.ForRead(password,
|
||||
entryHeader,
|
||||
buffer);
|
||||
entryHeader.CompressedSize -= 12;
|
||||
}
|
||||
else
|
||||
|
||||
entryHeader.Password = password;
|
||||
|
||||
if (entryHeader.CompressionMethod == ZipCompressionMethod.WinzipAes)
|
||||
{
|
||||
#if NO_CRYPTO
|
||||
throw new NotSupportedException("Cannot decrypt Winzip AES with Silverlight or WP7.");
|
||||
#else
|
||||
|
||||
var data = entryHeader.Extra.SingleOrDefault(x => x.Type == ExtraDataType.WinZipAes);
|
||||
WinzipAesKeySize keySize = (WinzipAesKeySize) data.DataBytes[4];
|
||||
ExtraData data = entryHeader.Extra.SingleOrDefault(x => x.Type == ExtraDataType.WinZipAes);
|
||||
if (data != null)
|
||||
{
|
||||
var keySize = (WinzipAesKeySize)data.DataBytes[4];
|
||||
|
||||
byte[] salt = new byte[WinzipAesEncryptionData.KeyLengthInBytes(keySize)/2];
|
||||
byte[] passwordVerifyValue = new byte[2];
|
||||
stream.Read(salt, 0, salt.Length);
|
||||
stream.Read(passwordVerifyValue, 0, 2);
|
||||
entryHeader.WinzipAesEncryptionData = new WinzipAesEncryptionData(keySize, salt, passwordVerifyValue,
|
||||
password);
|
||||
entryHeader.CompressedSize -= (uint) (salt.Length + 2);
|
||||
var salt = new byte[WinzipAesEncryptionData.KeyLengthInBytes(keySize) / 2];
|
||||
var passwordVerifyValue = new byte[2];
|
||||
stream.Read(salt, 0, salt.Length);
|
||||
stream.Read(passwordVerifyValue, 0, 2);
|
||||
entryHeader.WinzipAesEncryptionData =
|
||||
new WinzipAesEncryptionData(keySize, salt, passwordVerifyValue, password);
|
||||
|
||||
entryHeader.CompressedSize -= (uint)(salt.Length + 2);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (entryHeader.IsDirectory)
|
||||
{
|
||||
return;
|
||||
@@ -168,13 +168,15 @@ namespace SharpCompress.Common.Zip
|
||||
{
|
||||
entryHeader.DataStartPosition = stream.Position;
|
||||
stream.Position += entryHeader.CompressedSize;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case StreamingMode.Streaming:
|
||||
{
|
||||
entryHeader.PackedStream = stream;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
throw new InvalidFormatException("Invalid StreamingMode");
|
||||
|
||||
153
src/SharpCompress/Compressors/LZMA/LZipStream.cs
Normal file
153
src/SharpCompress/Compressors/LZMA/LZipStream.cs
Normal file
@@ -0,0 +1,153 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace SharpCompress.Compressors.LZMA
|
||||
{
|
||||
// TODO:
|
||||
// - Write as well as read
|
||||
// - Multi-volume support
|
||||
// - Use of the data size / member size values at the end of the stream
|
||||
|
||||
/// <summary>
|
||||
/// Stream supporting the LZIP format, as documented at http://www.nongnu.org/lzip/manual/lzip_manual.html
|
||||
/// </summary>
|
||||
public class LZipStream : Stream
|
||||
{
|
||||
private readonly Stream stream;
|
||||
private bool disposed;
|
||||
private readonly bool leaveOpen;
|
||||
|
||||
public LZipStream(Stream stream, CompressionMode mode)
|
||||
: this(stream, mode, false)
|
||||
{
|
||||
}
|
||||
|
||||
public LZipStream(Stream stream, CompressionMode mode, bool leaveOpen)
|
||||
{
|
||||
if (mode != CompressionMode.Decompress)
|
||||
{
|
||||
throw new NotImplementedException("Only LZip decompression is currently supported");
|
||||
}
|
||||
Mode = mode;
|
||||
this.leaveOpen = leaveOpen;
|
||||
int dictionarySize = ValidateAndReadSize(stream);
|
||||
if (dictionarySize == 0)
|
||||
{
|
||||
throw new IOException("Not an LZip stream");
|
||||
}
|
||||
byte[] properties = GetProperties(dictionarySize);
|
||||
this.stream = new LzmaStream(properties, stream);
|
||||
}
|
||||
|
||||
#region Stream methods
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
disposed = true;
|
||||
if (disposing && !leaveOpen)
|
||||
{
|
||||
stream.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public CompressionMode Mode { get; }
|
||||
|
||||
public override bool CanRead => stream.CanRead;
|
||||
|
||||
public override bool CanSeek => false;
|
||||
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
stream.Flush();
|
||||
}
|
||||
|
||||
// TODO: Both Length and Position are sometimes feasible, but would require
|
||||
// reading the output length when we initialize.
|
||||
public override long Length { get { throw new NotImplementedException(); } }
|
||||
|
||||
public override long Position { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } }
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count) => stream.Read(buffer, offset, count);
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the given stream is positioned at the start of a v1 LZip
|
||||
/// file, as indicated by the ASCII characters "LZIP" and a version byte
|
||||
/// of 1, followed by at least one byte.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to read from. Must not be null.</param>
|
||||
/// <returns><c>true</c> if the given stream is an LZip file, <c>false</c> otherwise.</returns>
|
||||
public static bool IsLZipFile(Stream stream) => ValidateAndReadSize(stream) != 0;
|
||||
|
||||
/// <summary>
|
||||
/// Reads the 6-byte header of the stream, and returns 0 if either the header
|
||||
/// couldn't be read or it isn't a validate LZIP header, or the dictionary
|
||||
/// size if it *is* a valid LZIP file.
|
||||
/// </summary>
|
||||
private static int ValidateAndReadSize(Stream stream)
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(stream));
|
||||
}
|
||||
// Read the header
|
||||
byte[] header = new byte[6];
|
||||
int n = stream.Read(header, 0, header.Length);
|
||||
|
||||
// TODO: Handle reading only part of the header?
|
||||
|
||||
if (n != 6)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (header[0] != 'L' || header[1] != 'Z' || header[2] != 'I' || header[3] != 'P' || header[4] != 1 /* version 1 */)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int basePower = header[5] & 0x1F;
|
||||
int subtractionNumerator = (header[5] & 0xE0) >> 5;
|
||||
return (1 << basePower) - subtractionNumerator * (1 << (basePower - 4));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a byte array to communicate the parameters and dictionary size to LzmaStream.
|
||||
/// </summary>
|
||||
private static byte[] GetProperties(int dictionarySize) =>
|
||||
new byte[]
|
||||
{
|
||||
// Parameters as per http://www.nongnu.org/lzip/manual/lzip_manual.html#Stream-format
|
||||
// but encoded as a single byte in the format LzmaStream expects.
|
||||
// literal_context_bits = 3
|
||||
// literal_pos_state_bits = 0
|
||||
// pos_state_bits = 2
|
||||
93,
|
||||
// Dictionary size as 4-byte little-endian value
|
||||
(byte)(dictionarySize & 0xff),
|
||||
(byte)((dictionarySize >> 8) & 0xff),
|
||||
(byte)((dictionarySize >> 16) & 0xff),
|
||||
(byte)((dictionarySize >> 24) & 0xff)
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -3,13 +3,6 @@ using SharpCompress.Converters;
|
||||
|
||||
namespace SharpCompress.Compressors.PPMd
|
||||
{
|
||||
public enum PpmdVersion
|
||||
{
|
||||
H,
|
||||
H7z,
|
||||
I1
|
||||
}
|
||||
|
||||
public class PpmdProperties
|
||||
{
|
||||
public PpmdVersion Version = PpmdVersion.I1;
|
||||
|
||||
9
src/SharpCompress/Compressors/PPMd/PpmdVersion.cs
Normal file
9
src/SharpCompress/Compressors/PPMd/PpmdVersion.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace SharpCompress.Compressors.PPMd
|
||||
{
|
||||
public enum PpmdVersion
|
||||
{
|
||||
H,
|
||||
H7z,
|
||||
I1
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ namespace SharpCompress.Readers
|
||||
Options = options;
|
||||
}
|
||||
|
||||
internal ReaderOptions Options { get; private set; }
|
||||
internal ReaderOptions Options { get; }
|
||||
|
||||
public ArchiveType ArchiveType { get; }
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ using SharpCompress.Readers.GZip;
|
||||
using SharpCompress.Readers.Rar;
|
||||
using SharpCompress.Readers.Tar;
|
||||
using SharpCompress.Readers.Zip;
|
||||
using SharpCompress.Compressors.LZMA;
|
||||
|
||||
namespace SharpCompress.Readers
|
||||
{
|
||||
@@ -33,7 +34,7 @@ namespace SharpCompress.Readers
|
||||
};
|
||||
RewindableStream rewindableStream = new RewindableStream(stream);
|
||||
rewindableStream.StartRecording();
|
||||
if (ZipArchive.IsZipFile(rewindableStream, null))
|
||||
if (ZipArchive.IsZipFile(rewindableStream, options.Password))
|
||||
{
|
||||
rewindableStream.Rewind(true);
|
||||
return ZipReader.Open(rewindableStream, options);
|
||||
@@ -64,6 +65,18 @@ namespace SharpCompress.Readers
|
||||
}
|
||||
}
|
||||
|
||||
rewindableStream.Rewind(false);
|
||||
if (LZipStream.IsLZipFile(rewindableStream))
|
||||
{
|
||||
rewindableStream.Rewind(false);
|
||||
LZipStream testStream = new LZipStream(rewindableStream, CompressionMode.Decompress, true);
|
||||
if (TarArchive.IsTarFile(testStream))
|
||||
{
|
||||
rewindableStream.Rewind(true);
|
||||
return new TarReader(rewindableStream, options, CompressionType.LZip);
|
||||
}
|
||||
}
|
||||
|
||||
rewindableStream.Rewind(false);
|
||||
if (RarArchive.IsRarFile(rewindableStream, options))
|
||||
{
|
||||
|
||||
@@ -9,6 +9,7 @@ using SharpCompress.Compressors;
|
||||
using SharpCompress.Compressors.BZip2;
|
||||
using SharpCompress.Compressors.Deflate;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Compressors.LZMA;
|
||||
|
||||
namespace SharpCompress.Readers.Tar
|
||||
{
|
||||
@@ -38,6 +39,10 @@ namespace SharpCompress.Readers.Tar
|
||||
{
|
||||
return new GZipStream(stream, CompressionMode.Decompress);
|
||||
}
|
||||
case CompressionType.LZip:
|
||||
{
|
||||
return new LZipStream(stream, CompressionMode.Decompress);
|
||||
}
|
||||
case CompressionType.None:
|
||||
{
|
||||
return stream;
|
||||
@@ -87,6 +92,19 @@ namespace SharpCompress.Readers.Tar
|
||||
}
|
||||
throw new InvalidFormatException("Not a tar file.");
|
||||
}
|
||||
|
||||
rewindableStream.Rewind(false);
|
||||
if (LZipStream.IsLZipFile(rewindableStream))
|
||||
{
|
||||
rewindableStream.Rewind(false);
|
||||
LZipStream testStream = new LZipStream(rewindableStream, CompressionMode.Decompress, false);
|
||||
if (TarArchive.IsTarFile(testStream))
|
||||
{
|
||||
rewindableStream.Rewind(true);
|
||||
return new TarReader(rewindableStream, options, CompressionType.LZip);
|
||||
}
|
||||
throw new InvalidFormatException("Not a tar file.");
|
||||
}
|
||||
rewindableStream.Rewind(true);
|
||||
return new TarReader(rewindableStream, options, CompressionType.None);
|
||||
}
|
||||
|
||||
@@ -19,10 +19,10 @@ namespace SharpCompress.Writers.Zip
|
||||
{
|
||||
private readonly CompressionType compressionType;
|
||||
private readonly CompressionLevel compressionLevel;
|
||||
private readonly PpmdProperties ppmdProperties = new PpmdProperties(); // Caching properties to speed up PPMd
|
||||
private readonly List<ZipCentralDirectoryEntry> entries = new List<ZipCentralDirectoryEntry>();
|
||||
private readonly string zipComment;
|
||||
private long streamPosition;
|
||||
private PpmdProperties ppmdProps;
|
||||
|
||||
public ZipWriter(Stream destination, ZipWriterOptions zipWriterOptions)
|
||||
: base(ArchiveType.Zip)
|
||||
@@ -34,6 +34,18 @@ namespace SharpCompress.Writers.Zip
|
||||
InitalizeStream(destination, !zipWriterOptions.LeaveStreamOpen);
|
||||
}
|
||||
|
||||
private PpmdProperties PpmdProperties
|
||||
{
|
||||
get
|
||||
{
|
||||
if (ppmdProps == null)
|
||||
{
|
||||
ppmdProps = new PpmdProperties();
|
||||
}
|
||||
return ppmdProps;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
if (isDisposing)
|
||||
@@ -252,8 +264,8 @@ namespace SharpCompress.Writers.Zip
|
||||
}
|
||||
case ZipCompressionMethod.PPMd:
|
||||
{
|
||||
counting.Write(writer.ppmdProperties.Properties, 0, 2);
|
||||
return new PpmdStream(writer.ppmdProperties, counting, true);
|
||||
counting.Write(writer.PpmdProperties.Properties, 0, 2);
|
||||
return new PpmdStream(writer.PpmdProperties, counting, true);
|
||||
}
|
||||
default:
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "0.13.0",
|
||||
"version": "0.15.2",
|
||||
"title": "SharpCompress - Pure C# Decompression/Compression",
|
||||
"authors": [ "Adam Hathcock" ],
|
||||
"language": "en-US",
|
||||
@@ -13,7 +13,8 @@
|
||||
},
|
||||
"buildOptions": {
|
||||
"warningsAsErrors": true,
|
||||
"allowUnsafe": true
|
||||
"allowUnsafe": true,
|
||||
"keyFile": "../../SharpCompress.snk"
|
||||
},
|
||||
"frameworks": {
|
||||
"net35": {
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace SharpCompress.Test
|
||||
[Fact]
|
||||
public void GZip_Archive_NoAdd()
|
||||
{
|
||||
string jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg\\test.jpg");
|
||||
string jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg", "test.jpg");
|
||||
ResetScratch();
|
||||
using (Stream stream = File.Open(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"), FileMode.Open))
|
||||
using (var archive = GZipArchive.Open(stream))
|
||||
@@ -55,5 +55,47 @@ namespace SharpCompress.Test
|
||||
archive.SaveTo(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void GZip_Archive_Multiple_Reads()
|
||||
{
|
||||
ResetScratch();
|
||||
var inputStream = new MemoryStream();
|
||||
using (var fileStream = File.Open(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"), FileMode.Open))
|
||||
{
|
||||
fileStream.CopyTo(inputStream);
|
||||
inputStream.Position = 0;
|
||||
}
|
||||
using (var archive = GZipArchive.Open(inputStream))
|
||||
{
|
||||
var archiveEntry = archive.Entries.First();
|
||||
|
||||
MemoryStream tarStream;
|
||||
using (var entryStream = archiveEntry.OpenEntryStream())
|
||||
{
|
||||
tarStream = new MemoryStream();
|
||||
entryStream.CopyTo(tarStream);
|
||||
}
|
||||
var size = tarStream.Length;
|
||||
using (var entryStream = archiveEntry.OpenEntryStream())
|
||||
{
|
||||
tarStream = new MemoryStream();
|
||||
entryStream.CopyTo(tarStream);
|
||||
}
|
||||
Assert.Equal(size, tarStream.Length);
|
||||
using (var entryStream = archiveEntry.OpenEntryStream())
|
||||
{
|
||||
var result = SharpCompress.Archives.Tar.TarArchive.IsTarFile(entryStream);
|
||||
}
|
||||
Assert.Equal(size, tarStream.Length);
|
||||
using (var entryStream = archiveEntry.OpenEntryStream())
|
||||
{
|
||||
tarStream = new MemoryStream();
|
||||
entryStream.CopyTo(tarStream);
|
||||
}
|
||||
Assert.Equal(size, tarStream.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ namespace SharpCompress.Test
|
||||
[Fact]
|
||||
public void Tar_Random_Write_Add()
|
||||
{
|
||||
string jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg\\test.jpg");
|
||||
string jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg","test.jpg");
|
||||
string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Tar.mod.tar");
|
||||
string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.mod.tar");
|
||||
string modified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.noEmptyDirs.tar");
|
||||
|
||||
@@ -33,6 +33,12 @@ namespace SharpCompress.Test
|
||||
Read("Tar.tar.gz", CompressionType.GZip);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Tar_LZip_Reader()
|
||||
{
|
||||
Read("Tar.tar.lz", CompressionType.LZip);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Tar_BZip2_Entry_Stream()
|
||||
{
|
||||
|
||||
@@ -210,16 +210,26 @@ namespace SharpCompress.Test
|
||||
|
||||
protected void CompareArchivesByPath(string file1, string file2)
|
||||
{
|
||||
//don't compare the order. OS X reads files from the file system in a different order therefore makes the archive ordering different
|
||||
var archive1Entries = new List<string>();
|
||||
var archive2Entries = new List<string>();
|
||||
using (var archive1 = ReaderFactory.Open(File.OpenRead(file1)))
|
||||
using (var archive2 = ReaderFactory.Open(File.OpenRead(file2)))
|
||||
{
|
||||
while (archive1.MoveToNextEntry())
|
||||
{
|
||||
Assert.True(archive2.MoveToNextEntry());
|
||||
Assert.Equal(archive1.Entry.Key, archive2.Entry.Key);
|
||||
archive1Entries.Add(archive1.Entry.Key);
|
||||
archive2Entries.Add(archive2.Entry.Key);
|
||||
}
|
||||
Assert.False(archive2.MoveToNextEntry());
|
||||
}
|
||||
archive1Entries.Sort();
|
||||
archive2Entries.Sort();
|
||||
for (int i = 0; i < archive1Entries.Count; i++)
|
||||
{
|
||||
Assert.Equal(archive1Entries[i], archive2Entries[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private static object lockObject = new object();
|
||||
|
||||
@@ -25,7 +25,6 @@ namespace SharpCompress.Test
|
||||
ArchiveStreamRead("Zip.zipx");
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void Zip_BZip2_Streamed_ArchiveStreamRead()
|
||||
{
|
||||
@@ -130,6 +129,18 @@ namespace SharpCompress.Test
|
||||
ArchiveFileRead("Zip.none.zip");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Zip_Zip64_ArchiveStreamRead()
|
||||
{
|
||||
ArchiveStreamRead("Zip.zip64.zip");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Zip_Zip64_ArchiveFileRead()
|
||||
{
|
||||
ArchiveFileRead("Zip.zip64.zip");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Zip_Random_Write_Remove()
|
||||
{
|
||||
@@ -150,7 +161,7 @@ namespace SharpCompress.Test
|
||||
[Fact]
|
||||
public void Zip_Random_Write_Add()
|
||||
{
|
||||
string jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg\\test.jpg");
|
||||
string jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg","test.jpg");
|
||||
string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Zip.deflate.mod.zip");
|
||||
string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.mod.zip");
|
||||
string modified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.mod2.zip");
|
||||
@@ -374,6 +385,29 @@ namespace SharpCompress.Test
|
||||
Assert.Equal(count3, 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Zip_Deflate_PKWear_Multipy_Entry_Access()
|
||||
{
|
||||
string zipFile = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.pkware.zip");
|
||||
|
||||
using (FileStream fileStream = File.Open(zipFile, FileMode.Open))
|
||||
{
|
||||
using (IArchive archive = ArchiveFactory.Open(fileStream, new ReaderOptions { Password = "12345678" }))
|
||||
{
|
||||
var entries = archive.Entries.Where(entry => !entry.IsDirectory);
|
||||
foreach (IArchiveEntry entry in entries)
|
||||
{
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
using (var memoryStream = new MemoryStream())
|
||||
using (Stream entryStream = entry.OpenEntryStream())
|
||||
entryStream.CopyTo(memoryStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class NonSeekableMemoryStream : MemoryStream
|
||||
{
|
||||
|
||||
@@ -14,6 +14,13 @@ namespace SharpCompress.Test
|
||||
{
|
||||
UseExtensionInsteadOfNameToVerify = true;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Zip_Zip64_Streamed_Read()
|
||||
{
|
||||
Read("Zip.Zip64.zip", CompressionType.Deflate);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Zip_ZipX_Streamed_Read()
|
||||
{
|
||||
@@ -228,6 +235,8 @@ namespace SharpCompress.Test
|
||||
[Fact]
|
||||
public void TestSharpCompressWithEmptyStream()
|
||||
{
|
||||
ResetScratch();
|
||||
|
||||
MemoryStream stream = new NonSeekableMemoryStream();
|
||||
|
||||
using (IWriter zipWriter = WriterFactory.Open(stream, ArchiveType.Zip, CompressionType.Deflate))
|
||||
@@ -250,7 +259,9 @@ namespace SharpCompress.Test
|
||||
byte[] buf = new byte[bufSize];
|
||||
int bytesRead = 0;
|
||||
while ((bytesRead = entry.Read(buf, 0, bufSize)) > 0)
|
||||
{
|
||||
tempStream.Write(buf, 0, bytesRead);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
{
|
||||
"buildOptions": {
|
||||
"keyFile": "../../SharpCompress.snk"
|
||||
},
|
||||
|
||||
"testRunner": "xunit",
|
||||
|
||||
"frameworks": {
|
||||
|
||||
BIN
test/TestArchives/Archives/Tar.tar.lz
Normal file
BIN
test/TestArchives/Archives/Tar.tar.lz
Normal file
Binary file not shown.
BIN
test/TestArchives/Archives/Zip.deflate.pkware.zip
Normal file
BIN
test/TestArchives/Archives/Zip.deflate.pkware.zip
Normal file
Binary file not shown.
BIN
test/TestArchives/Archives/Zip.zip64.zip
Normal file
BIN
test/TestArchives/Archives/Zip.zip64.zip
Normal file
Binary file not shown.
Reference in New Issue
Block a user