Compare commits

...

42 Commits

Author SHA1 Message Date
Adam Hathcock
b3a4fed8be Mark for 0.15.2 2017-03-09 11:02:44 +00:00
Adam Hathcock
d0b4af6666 Merge pull request #210 from kenkendk/fix_invalid_headers
Fix invalid headers
2017-03-09 10:41:18 +00:00
Kenneth Skovhede
81ab5c189d Fixed writing correct headers in zip archives 2017-03-09 11:34:24 +01:00
Kenneth Skovhede
6ef3be4b5c Fixed writing correct headers in zip archives 2017-03-09 11:32:20 +01:00
Adam Hathcock
9f90a1d651 Mark for 0.15.1 2017-01-25 09:31:01 +00:00
Adam Hathcock
ce9a3fd1ef Add file ordering fix for OS X 2017-01-25 09:29:13 +00:00
Adam Hathcock
7c6f05058e Merge pull request #206 from markryd/zip64-extraction
Zip64 extending information and ZipReader
2017-01-25 09:03:43 +00:00
Mark Rydstrom
a8c3a7439e Add support for zip64 to ZipReader 2017-01-25 17:05:48 +10:00
Mark Rydstrom
839b3ab0cf Add support for zip64 extended information field 2017-01-25 16:51:15 +10:00
Adam Hathcock
44d54db80e Fix some path issues on OS X when running tests. 2017-01-24 17:36:51 +00:00
Adam Hathcock
a67d7bc429 Mark for 0.15 2017-01-24 17:25:19 +00:00
Adam Hathcock
079a818c6c Merge pull request #205 from markryd/zip64-extraction
Add zip64 support for ZipArchive extraction
2017-01-24 16:56:42 +00:00
Mark Rydstrom
6be6ef0b5c Add zip64 support for ZipArchive extraction 2017-01-24 13:04:03 +10:00
Adam Hathcock
8e51d9d646 0.14.1 2016-11-30 14:26:18 +00:00
Adam Hathcock
ea206f4f02 Merge pull request #199 from adamhathcock/Issue-198
Gzip entry can't be read multiple times
2016-11-25 09:33:56 +00:00
Adam Hathcock
f175a2a252 Merge branch 'master' into Issue-198 2016-11-25 09:21:44 +00:00
Adam Hathcock
3f7e559b86 Merge pull request #200 from ITnent/bug/Issue-197
Open branch, to fix multiple crashes on repeated zip archives reading…
2016-11-25 09:21:34 +00:00
Vladimir Demidov
2959b4d701 Modified check integrity condition for the encrypted file. 2016-11-24 20:41:08 +03:00
Vladimir Demidov
031286c5eb Fixed defects after review. 2016-11-24 18:01:49 +03:00
Vladimir Demidov
e181fa8c4a Restored original tabs. 2016-11-24 17:11:43 +03:00
Vladimir Demidov
7b035bec5d Fixed some issues after review. 2016-11-24 16:21:02 +03:00
Vladimir Demidov
f39d2bf53a Open branch, to fix multiple crashes on repeated zip archives reading. Added fix. 2016-11-24 15:14:29 +03:00
Adam Hathcock
7c8e407182 Merge branch 'master' into Issue-198 2016-11-21 12:21:29 +00:00
Adam Hathcock
a09136d46b Merge pull request #195 from jskeet/strong-naming
Strong-name both the main and test projects
2016-11-21 12:06:13 +00:00
Adam Hathcock
5fe1363ee1 Gzip entry can't be read multiple times https://github.com/adamhathcock/sharpcompress/issues/198 2016-11-21 12:04:35 +00:00
Jon Skeet
b41823fc10 Strong-name both the main and test projects
It's not clear whether SharpCompress.Test.Portable (as referenced
in AssemblyInfo.cs) still exists, but build.ps1 certainly works.
2016-11-15 18:42:56 +00:00
Adam Hathcock
0a64fe28b0 Oops, removed too much from project.json 2016-10-14 09:03:15 +01:00
Adam Hathcock
e320ccfa9a 0.14.0 2016-10-14 08:59:19 +01:00
Adam Hathcock
9628ff9456 Merge pull request #191 from jskeet/lzip
Initial read-only support for LZip
2016-10-14 08:50:32 +01:00
Jon Skeet
d540f78cfc Initial read-only support for LZip
LZip has no notion of flienames, so an LzipReader wouldn't make very much sense;
I've just implemented the stream, and hooked it into tar support.
2016-10-12 15:08:56 +01:00
Adam Hathcock
66420cd299 Merge pull request #189 from ziaa/master
Remove unbalanced parentheses in code samples
2016-10-08 18:25:30 +01:00
Seyed Zia Azimi
dd0594471f Remove unbalanced parentheses in samples 2016-10-07 19:33:41 +03:30
Adam Hathcock
844ba228ee Make 0.13.1 2016-10-03 13:44:19 +01:00
Adam Hathcock
7efc701b32 Merge pull request #188 from adamhathcock/fix_nulls
Fix null password on ReaderFactory.  Fix null options on SevenZipArchive
2016-10-03 13:41:55 +01:00
Adam Hathcock
d7e29f7c4d Fix occasionally failing test 2016-10-03 13:37:04 +01:00
Adam Hathcock
f26ba91386 Fix null password on ReaderFactory. Fix null options on SevenZipArchive 2016-10-03 13:32:53 +01:00
Adam Hathcock
c73ac2039c Merge pull request #185 from adamhathcock/ppmd_allocation_zipwriter
Make PpmdProperties lazy to avoid unnecessary allocations.
2016-10-03 13:04:14 +01:00
Adam Hathcock
671f9cd0cb Empty commit to kick build 2016-10-03 12:58:23 +01:00
Adam Hathcock
131b5b9714 Can't use Lazy on .NET 3.5 :( 2016-10-03 11:20:29 +01:00
Adam Hathcock
74af0889b9 Make PpmdProperties lazy to avoid unnecessary allocations. 2016-10-03 10:16:26 +01:00
Adam Hathcock
e5ee399045 Merge pull request #181 from claunia/patch-1
Update FORMATS.md
2016-09-30 07:08:52 +01:00
deeb7a0f64 Update FORMATS.md
Add ADC to formats list.
2016-09-29 22:53:51 +01:00
43 changed files with 808 additions and 173 deletions

1
.gitignore vendored
View File

@@ -13,3 +13,4 @@ project.lock.json
test/TestArchives/Scratch
.vs
tools
.vscode

View File

@@ -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 |

View File

@@ -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

View File

@@ -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

Binary file not shown.

View File

@@ -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);
}
```
```

View File

@@ -1,4 +1,4 @@
version: '0.13.{build}'
version: '0.15.{build}'
init:
- git config --global core.autocrlf true

View File

@@ -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();
}

View File

@@ -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

View 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";
}
}

View File

@@ -11,6 +11,7 @@
LZMA,
BCJ,
BCJ2,
LZip,
Unknown
}
}

View File

@@ -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; } }

View File

@@ -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); } }

View File

@@ -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;
}
}
}
}

View File

@@ -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; }

View File

@@ -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);

View File

@@ -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
{

View File

@@ -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; }
}
}

View File

@@ -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; }
}
}

View File

@@ -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; } }
}
}

View File

@@ -6,6 +6,8 @@
LocalEntry,
DirectoryEntry,
DirectoryEnd,
Split
Split,
Zip64DirectoryEnd,
Zip64DirectoryEndLocator
}
}

View File

@@ -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();

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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");

View 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)
};
}
}

View File

@@ -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;

View File

@@ -0,0 +1,9 @@
namespace SharpCompress.Compressors.PPMd
{
public enum PpmdVersion
{
H,
H7z,
I1
}
}

View File

@@ -29,7 +29,7 @@ namespace SharpCompress.Readers
Options = options;
}
internal ReaderOptions Options { get; private set; }
internal ReaderOptions Options { get; }
public ArchiveType ArchiveType { get; }

View File

@@ -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))
{

View File

@@ -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);
}

View File

@@ -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:
{

View File

@@ -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": {

View File

@@ -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);
}
}
}
}

View File

@@ -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");

View File

@@ -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()
{

View File

@@ -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();

View File

@@ -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
{

View File

@@ -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);
}
}
}
}

View File

@@ -1,4 +1,8 @@
{
"buildOptions": {
"keyFile": "../../SharpCompress.snk"
},
"testRunner": "xunit",
"frameworks": {

Binary file not shown.

Binary file not shown.

Binary file not shown.