mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-02-04 13:34:59 +00:00
Compare commits
180 Commits
portable_c
...
0.11.5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee5e3fbc1d | ||
|
|
d13b2ad073 | ||
|
|
e9a7efc371 | ||
|
|
9b8ddda191 | ||
|
|
1fc14e1075 | ||
|
|
b3a5204e74 | ||
|
|
0fab1ff976 | ||
|
|
a05b692fc3 | ||
|
|
ed7f140364 | ||
|
|
a4b594121e | ||
|
|
fe8da55c95 | ||
|
|
42c4eab4be | ||
|
|
2e8844c896 | ||
|
|
aed7ff003d | ||
|
|
681b28f654 | ||
|
|
0de64b1551 | ||
|
|
526df2404e | ||
|
|
f20274aac7 | ||
|
|
08b899fdac | ||
|
|
7b91b6e7c8 | ||
|
|
1661b7ec36 | ||
|
|
e5ab9dc883 | ||
|
|
25d22e33a7 | ||
|
|
8ceac9000c | ||
|
|
ecceec8e1a | ||
|
|
d5c88ebab3 | ||
|
|
0a2adbc205 | ||
|
|
3be7f9da37 | ||
|
|
3f2ca67416 | ||
|
|
21087323af | ||
|
|
05f92018c3 | ||
|
|
b8fc4a2415 | ||
|
|
a30872809d | ||
|
|
7abf2ed58b | ||
|
|
bec2662d23 | ||
|
|
dd35052de9 | ||
|
|
2a630e04b2 | ||
|
|
231b78e096 | ||
|
|
ce6e1d26f4 | ||
|
|
69a25cd142 | ||
|
|
cc2ad7d8d5 | ||
|
|
1aa0498e5d | ||
|
|
1ce5e15fd2 | ||
|
|
b40131736a | ||
|
|
c2b15b9c09 | ||
|
|
27a4f78712 | ||
|
|
2b5ee6e8cb | ||
|
|
cd8ea28576 | ||
|
|
b2b6934499 | ||
|
|
0f12a073af | ||
|
|
18bd810228 | ||
|
|
13bbb202c7 | ||
|
|
6e0f4ecbc9 | ||
|
|
9a638e7aa5 | ||
|
|
7a11dc4385 | ||
|
|
66816ce390 | ||
|
|
5d8bd7b69b | ||
|
|
0132c85ec7 | ||
|
|
9bf5df72a6 | ||
|
|
91fc241358 | ||
|
|
35a8b444b8 | ||
|
|
2e928e86fd | ||
|
|
6648f33c4e | ||
|
|
2a70ec8100 | ||
|
|
05e0d591a5 | ||
|
|
1d30a1b51d | ||
|
|
315c138c05 | ||
|
|
b0c514d87c | ||
|
|
8e5cb77af2 | ||
|
|
8faebc78d0 | ||
|
|
afff386622 | ||
|
|
9eb43156e8 | ||
|
|
5dd9994d34 | ||
|
|
f18771904e | ||
|
|
ff1cdbfff2 | ||
|
|
332d71d40d | ||
|
|
d9c31dace8 | ||
|
|
33c83e3893 | ||
|
|
c7fc5f8819 | ||
|
|
8df6243807 | ||
|
|
8bf5c99386 | ||
|
|
83eae05e0c | ||
|
|
7c70a7aafd | ||
|
|
dae13c782f | ||
|
|
ae1e37cde6 | ||
|
|
94f4d35663 | ||
|
|
5144104fef | ||
|
|
f87e6672f2 | ||
|
|
312b53398c | ||
|
|
26ddc09c6a | ||
|
|
3113500229 | ||
|
|
ef72829f1c | ||
|
|
088644240a | ||
|
|
065ed29600 | ||
|
|
ee8c1f7904 | ||
|
|
5d6a83578c | ||
|
|
37d8d34601 | ||
|
|
492f64053b | ||
|
|
988fe5eac0 | ||
|
|
c48a47c9b2 | ||
|
|
abed9eb2c9 | ||
|
|
391663ac67 | ||
|
|
a8c055b990 | ||
|
|
7ee885e7d5 | ||
|
|
ed05bd721f | ||
|
|
e52c183f1a | ||
|
|
ed6ad6ac6d | ||
|
|
62f198b532 | ||
|
|
9770cfec9b | ||
|
|
e05f30308c | ||
|
|
6958347849 | ||
|
|
8e6ced6138 | ||
|
|
0c36ff6082 | ||
|
|
f78e839365 | ||
|
|
7e3f04e669 | ||
|
|
2d237bfbca | ||
|
|
e6e88dbde0 | ||
|
|
e558a78354 | ||
|
|
c2df06a746 | ||
|
|
41da844250 | ||
|
|
8fcb0cb7a2 | ||
|
|
2e533f9fb5 | ||
|
|
ca2778b658 | ||
|
|
3147ee0f14 | ||
|
|
f72558de9e | ||
|
|
6d69791db1 | ||
|
|
6e05a20136 | ||
|
|
d36ae445e2 | ||
|
|
022f7ed26b | ||
|
|
d1a64021e1 | ||
|
|
9225531f1e | ||
|
|
650dc6f8bb | ||
|
|
49d6f1f633 | ||
|
|
505f435f5d | ||
|
|
d9d63fba96 | ||
|
|
8c3d260d7c | ||
|
|
0fd00efada | ||
|
|
71e86cd7e4 | ||
|
|
c64a96398d | ||
|
|
efa9805fe4 | ||
|
|
2100d49cef | ||
|
|
66ffc82d41 | ||
|
|
e58ec599f0 | ||
|
|
4eda2043df | ||
|
|
afd65a7505 | ||
|
|
25148a9bf8 | ||
|
|
97bc1865dc | ||
|
|
865afbfbf0 | ||
|
|
c59e6a8c99 | ||
|
|
be9111630e | ||
|
|
d46de85ca2 | ||
|
|
c1562c5829 | ||
|
|
f862cc6947 | ||
|
|
cc3848aea5 | ||
|
|
46fc663e90 | ||
|
|
84ed6bc7f0 | ||
|
|
fe5895d373 | ||
|
|
770e2d6e75 | ||
|
|
84704e5ce2 | ||
|
|
059fe1f545 | ||
|
|
fe8c6aec5f | ||
|
|
3ab38fbfc2 | ||
|
|
b4bfde77d2 | ||
|
|
c4b005b3d4 | ||
|
|
c9d1f7b528 | ||
|
|
21aa57945d | ||
|
|
1d0c7b6445 | ||
|
|
f33d8f9a5e | ||
|
|
ee2d6216b7 | ||
|
|
a42414bdaa | ||
|
|
3e201053c6 | ||
|
|
46c03ce027 | ||
|
|
718dac1a31 | ||
|
|
137f2655a5 | ||
|
|
8109ae003d | ||
|
|
8325b919ce | ||
|
|
61c97faf6c | ||
|
|
2dc297394f | ||
|
|
7aa5d310f2 | ||
|
|
e3fb32aa3c |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -8,3 +8,4 @@ TestArchives/Scratch/
|
||||
TestArchives/Scratch2/
|
||||
TestResults/
|
||||
*.nupkg
|
||||
packages/*/
|
||||
|
||||
21
LICENSE.txt
Normal file
21
LICENSE.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Adam Hathcock
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -2,21 +2,23 @@
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>sharpcompress</id>
|
||||
<version>0.9</version>
|
||||
<version>0.11.5</version>
|
||||
<title>SharpCompress - Pure C# Decompression/Compression</title>
|
||||
<authors>Adam Hathcock</authors>
|
||||
<owners>Adam Hathcock</owners>
|
||||
<licenseUrl>http://sharpcompress.codeplex.com/license</licenseUrl>
|
||||
<licenseUrl>https://github.com/adamhathcock/sharpcompress/blob/master/LICENSE.txt</licenseUrl>
|
||||
<projectUrl>https://github.com/adamhathcock/sharpcompress</projectUrl>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<description>SharpCompress is a compression library for .NET/Mono/Silverlight/WP7/WindowsStore that can unrar, decompress 7zip, zip/unzip, tar/untar bzip2/unbzip2 and gzip/ungzip with forward-only reading and file random access APIs. Write support for zip/tar/bzip2/gzip is implemented.</description>
|
||||
<releaseNotes />
|
||||
<language>en-US</language>
|
||||
<tags>rar unrar zip unzip bzip2 gzip tar 7zip .net40 .net35 sl4</tags>
|
||||
<tags>rar unrar zip unzip bzip2 gzip tar 7zip</tags>
|
||||
<dependencies>
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="..\bin\SharpCompress.dll" target="lib\net40\SharpCompress.dll" />
|
||||
<file src="..\bin\SharpCompress.WindowsStore.dll" target="lib\netcore45\SharpCompress.WindowsStore.dll" />
|
||||
<file src="..\bin\SharpCompress.Portable.dll" target="lib\portable-net4+sl4+wp7+win8\SharpCompress.Portable.dll" />
|
||||
<file src="..\bin\Full\SharpCompress.dll" target="lib\net40\SharpCompress.dll" />
|
||||
<file src="..\bin\WindowsStore\SharpCompress.dll" target="lib\netcore45\SharpCompress.dll" />
|
||||
<file src="..\bin\Portable\SharpCompress.dll" target="lib\portable-net4+sl5+wp8+win8\SharpCompress.dll" />
|
||||
</files>
|
||||
</package>
|
||||
60
README.md
60
README.md
@@ -1,9 +1,7 @@
|
||||
SharpCompress
|
||||
=============
|
||||
|
||||
Github mirror of http://sharpcompress.codeplex.com
|
||||
|
||||
SharpCompress is a compression library for .NET/Mono/Silverlight/WP7 that can unrar, un7zip, unzip, untar unbzip2 and ungzip with forward-only reading and file random access APIs. Write support for zip/tar/bzip2/gzip is implemented.
|
||||
SharpCompress is a compression library for .NET/Mono/Silverlight/WP7 that can unrar, un7zip, unzip, untar unbzip2 and ungzip with forward-only reading and file random access APIs. Write support for zip/tar/bzip2/gzip are implemented.
|
||||
|
||||
The major feature is support for non-seekable streams so large files can be processed on the fly (i.e. download stream).
|
||||
|
||||
@@ -11,16 +9,68 @@ A Simple Request
|
||||
|
||||
Hi everyone. I hope you're using SharpCompress and finding it useful. Please give me feedback on what you'd like to see changed especially as far as usability goes. New feature suggestions are always welcome as well. I would also like to know what projects SharpCompress is being used in. I like seeing how it is used to give me ideas for future versions. Thanks!
|
||||
|
||||
Please do not email me directly to ask for help. If you think there is a real issue, please report it here.
|
||||
|
||||
Want to contribute?
|
||||
|
||||
I'm always looking for help or ideas. Please submit code or email with ideas. Unfortunately, just letting me know you'd like to help is not enough because I really have no overall plan of what needs to be done. I'll definitely accept code submissions and add you as a member of the project!
|
||||
|
||||
TODOs (always lots):
|
||||
* RAR 5 support
|
||||
* 7Zip writing
|
||||
* RAR Decryption
|
||||
* Zip64
|
||||
* Multi-volume Zip support.
|
||||
|
||||
In-Progress:
|
||||
==============
|
||||
- RAR5 support
|
||||
- DNX/NET Core support
|
||||
- xproj targeting
|
||||
|
||||
Version 0.11.5:
|
||||
==============
|
||||
- Bug fix in Skip method
|
||||
|
||||
Version 0.11.4:
|
||||
==============
|
||||
- SharpCompress is now endian neutral (matters for Mono platforms)
|
||||
- Fix for Inflate (need to change implementation)
|
||||
- Fixes for RAR detection
|
||||
|
||||
Version 0.11.1:
|
||||
==============
|
||||
- Added Cancel on IReader
|
||||
- Removed .NET 2.0 support and LinqBridge dependency
|
||||
|
||||
Version 0.11:
|
||||
==============
|
||||
- Been over a year, contains mainly fixes from contributors!
|
||||
- Possible breaking change: ArchiveEncoding is UTF8 by default now.
|
||||
- TAR supports writing long names using longlink
|
||||
- RAR Protect Header added
|
||||
|
||||
Version 0.10.3:
|
||||
==============
|
||||
- Finally fixed Disposal issue when creating a new archive with the Archive API
|
||||
|
||||
Version 0.10.2:
|
||||
==============
|
||||
- Fixed Rar Header reading for invalid extended time headers.
|
||||
- Windows Store assembly is now strong named
|
||||
- Known issues with Long Tar names being worked on
|
||||
- Updated to VS2013
|
||||
- Portable targets SL5 and Windows Phone 8 (up from SL4 and WP7)
|
||||
|
||||
Version 0.10.1:
|
||||
==============
|
||||
- Fixed 7Zip extraction performance problem
|
||||
|
||||
Version 0.10:
|
||||
==============
|
||||
- Added support for RAR Decryption (thanks to https://github.com/hrasyid)
|
||||
- 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
|
||||
|
||||
@@ -33,4 +83,4 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
@@ -120,11 +120,60 @@ namespace SharpCompress.Test
|
||||
void archive_EntryExtractionBegin(object sender, ArchiveExtractionEventArgs<IArchiveEntry> e)
|
||||
{
|
||||
this.entryTotal = e.Item.Size;
|
||||
Console.WriteLine("Initializing File Entry Extraction: " + e.Item.FilePath);
|
||||
Console.WriteLine("Initializing File Entry Extraction: " + e.Item.Key);
|
||||
}
|
||||
|
||||
private long? entryTotal;
|
||||
private long partTotal;
|
||||
private long totalSize;
|
||||
|
||||
protected void ArchiveFileReadEx(string testArchive)
|
||||
{
|
||||
testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive);
|
||||
ArchiveFileReadEx(testArchive.AsEnumerable());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrate the TotalUncompressSize property, and the ExtractOptions.PreserveFileTime and ExtractOptions.PreserveAttributes extract options
|
||||
/// </summary>
|
||||
protected void ArchiveFileReadEx(IEnumerable<string> testArchives)
|
||||
{
|
||||
foreach (var path in testArchives)
|
||||
{
|
||||
ResetScratch();
|
||||
using (var archive = ArchiveFactory.Open(path))
|
||||
{
|
||||
this.totalSize = archive.TotalUncompressSize;
|
||||
archive.EntryExtractionBegin += Archive_EntryExtractionBeginEx;
|
||||
archive.EntryExtractionEnd += Archive_EntryExtractionEndEx;
|
||||
archive.CompressedBytesRead += Archive_CompressedBytesReadEx;
|
||||
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
entry.WriteToDirectory(SCRATCH_FILES_PATH,
|
||||
ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite | ExtractOptions.PreserveFileTime | ExtractOptions.PreserveAttributes);
|
||||
}
|
||||
}
|
||||
VerifyFilesEx();
|
||||
}
|
||||
}
|
||||
|
||||
private void Archive_EntryExtractionEndEx(object sender, ArchiveExtractionEventArgs<IArchiveEntry> e)
|
||||
{
|
||||
this.partTotal += e.Item.Size;
|
||||
}
|
||||
|
||||
private void Archive_CompressedBytesReadEx(object sender, CompressedBytesReadEventArgs e)
|
||||
{
|
||||
string percentage = this.entryTotal.HasValue ? this.CreatePercentage(e.CompressedBytesRead, this.entryTotal.Value).ToString() : "-";
|
||||
string tortalPercentage = this.CreatePercentage(this.partTotal + e.CompressedBytesRead, this.totalSize).ToString();
|
||||
Console.WriteLine(@"Read Compressed File Progress: {0}% Total Progress {1}%", percentage, tortalPercentage);
|
||||
}
|
||||
|
||||
private void Archive_EntryExtractionBeginEx(object sender, ArchiveExtractionEventArgs<IArchiveEntry> e)
|
||||
{
|
||||
this.entryTotal = e.Item.Size;
|
||||
}
|
||||
|
||||
private int CreatePercentage(long n, long d)
|
||||
{
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace SharpCompress.Test
|
||||
using (var archive = ArchiveFactory.Open(stream))
|
||||
{
|
||||
var entry = archive.Entries.First();
|
||||
entry.WriteToFile(Path.Combine(SCRATCH_FILES_PATH, entry.FilePath));
|
||||
entry.WriteToFile(Path.Combine(SCRATCH_FILES_PATH, entry.Key));
|
||||
}
|
||||
CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar"),
|
||||
Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"));
|
||||
@@ -37,7 +37,7 @@ namespace SharpCompress.Test
|
||||
using (var archive = GZipArchive.Open(stream))
|
||||
{
|
||||
var entry = archive.Entries.First();
|
||||
entry.WriteToFile(Path.Combine(SCRATCH_FILES_PATH, entry.FilePath));
|
||||
entry.WriteToFile(Path.Combine(SCRATCH_FILES_PATH, entry.Key));
|
||||
}
|
||||
CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar"),
|
||||
Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"));
|
||||
|
||||
@@ -10,17 +10,93 @@ namespace SharpCompress.Test
|
||||
[TestClass]
|
||||
public class RarArchiveTests : ArchiveTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void Rar_EncryptedFileAndHeader_Archive()
|
||||
{
|
||||
ReadRarPassword("Rar.encrypted_filesAndHeader.rar", "test");
|
||||
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Rar_EncryptedFileOnly_Archive()
|
||||
{
|
||||
ReadRarPassword("Rar.encrypted_filesOnly.rar", "test");
|
||||
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Rar_Encrypted_Archive()
|
||||
{
|
||||
ReadRarPassword("Encrypted.rar", "test");
|
||||
}
|
||||
|
||||
private void ReadRarPassword(string testArchive, string password)
|
||||
{
|
||||
ResetScratch();
|
||||
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, testArchive)))
|
||||
using (var archive = RarArchive.Open(stream, Options.KeepStreamsOpen, password))
|
||||
{
|
||||
foreach (var entry in archive.Entries)
|
||||
{
|
||||
if (!entry.IsDirectory)
|
||||
{
|
||||
Assert.AreEqual(entry.CompressionType, CompressionType.Rar);
|
||||
entry.WriteToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
|
||||
}
|
||||
}
|
||||
}
|
||||
VerifyFiles();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(InvalidFormatException))]
|
||||
public void Rar_Multi_Archive_Encrypted()
|
||||
{
|
||||
ArchiveFileReadPassword("EncryptedParts.part01.rar", "test");
|
||||
}
|
||||
|
||||
protected void ArchiveFileReadPassword(string archiveName, string password)
|
||||
{
|
||||
ResetScratch();
|
||||
using (var archive = RarArchive.Open(Path.Combine(TEST_ARCHIVES_PATH, archiveName), Options.None, password))
|
||||
{
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
entry.WriteToDirectory(SCRATCH_FILES_PATH,
|
||||
ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
|
||||
}
|
||||
}
|
||||
VerifyFiles();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Rar_None_ArchiveStreamRead()
|
||||
{
|
||||
ArchiveStreamRead("Rar.none.rar");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Rar_ArchiveStreamRead()
|
||||
{
|
||||
ArchiveStreamRead("Rar.rar");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Rar_test_invalid_exttime_ArchiveStreamRead()
|
||||
{
|
||||
ResetScratch();
|
||||
using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "test_invalid_exttime.rar")))
|
||||
{
|
||||
using (var archive = ArchiveFactory.Open(stream))
|
||||
{
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
entry.WriteToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Rar_Jpg_ArchiveStreamRead()
|
||||
{
|
||||
@@ -47,7 +123,7 @@ namespace SharpCompress.Test
|
||||
{
|
||||
using (var archive = RarArchive.Open(stream))
|
||||
{
|
||||
Assert.IsFalse(archive.IsSolidArchive());
|
||||
Assert.IsFalse(archive.IsSolid);
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
entry.WriteToDirectory(SCRATCH_FILES_PATH,
|
||||
@@ -114,7 +190,7 @@ namespace SharpCompress.Test
|
||||
{
|
||||
using (var archive = RarArchive.Open(stream))
|
||||
{
|
||||
Assert.IsFalse(archive.IsSolidArchive());
|
||||
Assert.IsFalse(archive.IsSolid);
|
||||
Assert.IsTrue(archive.Entries.Any(entry => entry.IsDirectory));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,29 @@ namespace SharpCompress.Test
|
||||
VerifyFiles();
|
||||
}
|
||||
|
||||
//[TestMethod]
|
||||
public void Rar_Multi_Reader_Encrypted()
|
||||
{
|
||||
var testArchives = new string[] { "EncryptedParts.part01.rar",
|
||||
"EncryptedParts.part02.rar",
|
||||
"EncryptedParts.part03.rar",
|
||||
"EncryptedParts.part04.rar",
|
||||
"EncryptedParts.part05.rar",
|
||||
"EncryptedParts.part06.rar"};
|
||||
|
||||
|
||||
ResetScratch();
|
||||
using (var reader = RarReader.Open(testArchives.Select(s => Path.Combine(TEST_ARCHIVES_PATH, s))
|
||||
.Select(p => File.OpenRead(p))))
|
||||
{
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
|
||||
}
|
||||
}
|
||||
VerifyFiles();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Rar_Multi_Reader_Delete_Files()
|
||||
{
|
||||
@@ -50,15 +73,18 @@ namespace SharpCompress.Test
|
||||
{
|
||||
File.Copy(Path.Combine(TEST_ARCHIVES_PATH, file), Path.Combine(SCRATCH2_FILES_PATH, file));
|
||||
}
|
||||
|
||||
using (var reader = RarReader.Open(testArchives.Select(s => Path.Combine(SCRATCH2_FILES_PATH, s))
|
||||
.Select(p => File.OpenRead(p)), Options.None))
|
||||
var streams = testArchives.Select(s => Path.Combine(SCRATCH2_FILES_PATH, s)).Select(File.OpenRead).ToList();
|
||||
using (var reader = RarReader.Open(streams))
|
||||
{
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
|
||||
}
|
||||
}
|
||||
foreach (var stream in streams)
|
||||
{
|
||||
stream.Dispose();
|
||||
}
|
||||
VerifyFiles();
|
||||
|
||||
foreach (var file in testArchives.Select(s => Path.Combine(SCRATCH2_FILES_PATH, s)))
|
||||
@@ -97,7 +123,6 @@ namespace SharpCompress.Test
|
||||
public void Rar_Encrypted_Reader()
|
||||
{
|
||||
ReadRar("Encrypted.rar", "test");
|
||||
|
||||
}
|
||||
|
||||
private void ReadRar(string testArchive, string password)
|
||||
@@ -132,8 +157,8 @@ namespace SharpCompress.Test
|
||||
Assert.AreEqual(reader.Entry.CompressionType, CompressionType.Rar);
|
||||
using (var entryStream = reader.OpenEntryStream())
|
||||
{
|
||||
string file = Path.GetFileName(reader.Entry.FilePath);
|
||||
string folder = Path.GetDirectoryName(reader.Entry.FilePath);
|
||||
string file = Path.GetFileName(reader.Entry.Key);
|
||||
string folder = Path.GetDirectoryName(reader.Entry.Key);
|
||||
string destdir = Path.Combine(SCRATCH_FILES_PATH, folder);
|
||||
if (!Directory.Exists(destdir))
|
||||
{
|
||||
@@ -200,7 +225,7 @@ namespace SharpCompress.Test
|
||||
{
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
if (reader.Entry.FilePath.Contains("jpg"))
|
||||
if (reader.Entry.Key.Contains("jpg"))
|
||||
{
|
||||
Assert.AreEqual(reader.Entry.CompressionType, CompressionType.Rar);
|
||||
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
|
||||
@@ -218,7 +243,7 @@ namespace SharpCompress.Test
|
||||
{
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
if (reader.Entry.FilePath.Contains("jpg"))
|
||||
if (reader.Entry.Key.Contains("jpg"))
|
||||
{
|
||||
Assert.AreEqual(reader.Entry.CompressionType, CompressionType.Rar);
|
||||
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
|
||||
|
||||
@@ -61,6 +61,11 @@ namespace SharpCompress.Test
|
||||
ArchiveFileRead("7Zip.BZip2.7z");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SevenZipArchive_LZMA_Time_Attributes_PathRead()
|
||||
{
|
||||
ArchiveFileReadEx("7Zip.LZMA.7z");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(IndexOutOfRangeException))]
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
</StartupObject>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<SignAssembly>false</SignAssembly>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<AssemblyOriginatorKeyFile>..\SharpCompress\SharpCompress.pfx</AssemblyOriginatorKeyFile>
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
</StartupObject>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<SignAssembly>false</SignAssembly>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<AssemblyOriginatorKeyFile>..\SharpCompress\SharpCompress.pfx</AssemblyOriginatorKeyFile>
|
||||
@@ -97,9 +97,9 @@
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SharpCompress\SharpCompress.csproj">
|
||||
<Project>{10A689CF-76A2-4A4F-96E4-553C33398438}</Project>
|
||||
<Name>SharpCompress</Name>
|
||||
<ProjectReference Include="..\SharpCompress\SharpCompress.Unsigned.csproj">
|
||||
<Project>{27d535cb-2fd3-4621-8c9a-46161fc77a5d}</Project>
|
||||
<Name>SharpCompress.Unsigned</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
|
||||
@@ -30,13 +30,71 @@ namespace SharpCompress.Test
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public void TarArchivePathReadLongName()
|
||||
public void Tar_NonUstarArchiveWithLongNameDoesNotSkipEntriesAfterTheLongOne()
|
||||
{
|
||||
string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "very long filename.tar");
|
||||
using (var archive = TarArchive.Open(unmodified))
|
||||
{
|
||||
Assert.AreEqual(2, archive.Entries.Count);
|
||||
Assert.AreEqual(archive.Entries.Last().FilePath, @"very long filename/very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename.jpg");
|
||||
Assert.AreEqual(5, archive.Entries.Count);
|
||||
Assert.IsTrue(archive.Entries.Any(entry => entry.Key == "very long filename/"));
|
||||
Assert.IsTrue(archive.Entries.Any(entry => entry.Key == "very long filename/very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename.jpg"));
|
||||
Assert.IsTrue(archive.Entries.Any(entry => entry.Key == "z_file 1.txt"));
|
||||
Assert.IsTrue(archive.Entries.Any(entry => entry.Key == "z_file 2.txt"));
|
||||
Assert.IsTrue(archive.Entries.Any(entry => entry.Key == "z_file 3.txt"));
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Tar_VeryLongFilepathReadback()
|
||||
{
|
||||
string archive = "Tar_VeryLongFilepathReadback.tar";
|
||||
|
||||
ResetScratch();
|
||||
|
||||
// create a very long filename
|
||||
string longFilename = "";
|
||||
for (int i = 0; i < 600; i = longFilename.Length)
|
||||
longFilename += i.ToString("D10") + "-";
|
||||
longFilename += ".txt";
|
||||
|
||||
// Step 1: create a tar file containing a file with a long name
|
||||
using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive)))
|
||||
using (var writer = SharpCompress.Writer.WriterFactory.Open(stream, ArchiveType.Tar, CompressionType.None))
|
||||
using (Stream inputStream = new MemoryStream())
|
||||
{
|
||||
StreamWriter sw = new StreamWriter(inputStream);
|
||||
sw.Write("dummy filecontent");
|
||||
sw.Flush();
|
||||
|
||||
inputStream.Position = 0;
|
||||
writer.Write(longFilename, inputStream, null);
|
||||
}
|
||||
|
||||
// Step 2: check if the written tar file can be read correctly
|
||||
string unmodified = Path.Combine(SCRATCH2_FILES_PATH, archive);
|
||||
using (var archive2 = TarArchive.Open(unmodified))
|
||||
{
|
||||
Assert.AreEqual(1, archive2.Entries.Count);
|
||||
Assert.IsTrue(archive2.Entries.Any(entry => entry.Key == longFilename));
|
||||
|
||||
foreach (var entry in archive2.Entries)
|
||||
Assert.AreEqual("dummy filecontent", new StreamReader(entry.OpenEntryStream()).ReadLine());
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Tar_UstarArchivePathReadLongName()
|
||||
{
|
||||
string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "ustar with long names.tar");
|
||||
using(var archive = TarArchive.Open(unmodified))
|
||||
{
|
||||
Assert.AreEqual(6, archive.Entries.Count);
|
||||
Assert.IsTrue(archive.Entries.Any(entry => entry.Key == "Directory/"));
|
||||
Assert.IsTrue(archive.Entries.Any(entry => entry.Key == "Directory/Some file with veeeeeeeeeery loooooooooong name"));
|
||||
Assert.IsTrue(archive.Entries.Any(entry => entry.Key == "Directory/Directory with veeeeeeeeeery loooooooooong name/"));
|
||||
Assert.IsTrue(archive.Entries.Any(entry => entry.Key == "Directory/Directory with veeeeeeeeeery loooooooooong name/Some file with veeeeeeeeeery loooooooooong name"));
|
||||
Assert.IsTrue(archive.Entries.Any(entry => entry.Key == "Directory/Directory with veeeeeeeeeery loooooooooong name/Directory with veeeeeeeeeery loooooooooong name/"));
|
||||
Assert.IsTrue(archive.Entries.Any(entry => entry.Key == "Directory/Directory with veeeeeeeeeery loooooooooong name/Directory with veeeeeeeeeery loooooooooong name/Some file with veeeeeeeeeery loooooooooong name"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,11 +139,22 @@ namespace SharpCompress.Test
|
||||
base.ResetScratch();
|
||||
using (var archive = TarArchive.Open(unmodified))
|
||||
{
|
||||
var entry = archive.Entries.Where(x => x.FilePath.EndsWith("jpg")).Single();
|
||||
var entry = archive.Entries.Where(x => x.Key.EndsWith("jpg")).Single();
|
||||
archive.RemoveEntry(entry);
|
||||
archive.SaveTo(scratchPath, CompressionType.None);
|
||||
}
|
||||
CompareArchivesByPath(modified, scratchPath);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Tar_Containing_Rar_Archive()
|
||||
{
|
||||
string archiveFullPath = Path.Combine(TEST_ARCHIVES_PATH, "Tar.ContainsRar.tar");
|
||||
using (Stream stream = File.OpenRead(archiveFullPath))
|
||||
using (IArchive archive = ArchiveFactory.Open(stream))
|
||||
{
|
||||
Assert.IsTrue(archive.Type == ArchiveType.Tar);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.IO;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Reader;
|
||||
using SharpCompress.Reader.Tar;
|
||||
|
||||
namespace SharpCompress.Test
|
||||
@@ -46,8 +47,8 @@ namespace SharpCompress.Test
|
||||
Assert.AreEqual(reader.Entry.CompressionType, CompressionType.BZip2);
|
||||
using (var entryStream = reader.OpenEntryStream())
|
||||
{
|
||||
string file = Path.GetFileName(reader.Entry.FilePath);
|
||||
string folder = Path.GetDirectoryName(reader.Entry.FilePath);
|
||||
string file = Path.GetFileName(reader.Entry.Key);
|
||||
string folder = Path.GetDirectoryName(reader.Entry.Key);
|
||||
string destdir = Path.Combine(SCRATCH_FILES_PATH, folder);
|
||||
if (!Directory.Exists(destdir))
|
||||
{
|
||||
@@ -81,12 +82,23 @@ namespace SharpCompress.Test
|
||||
using (var entryStream = reader.OpenEntryStream())
|
||||
{
|
||||
entryStream.SkipEntry();
|
||||
names.Add(reader.Entry.FilePath);
|
||||
names.Add(reader.Entry.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
Assert.AreEqual(names.Count, 3);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Tar_Containing_Rar_Reader()
|
||||
{
|
||||
string archiveFullPath = Path.Combine(TEST_ARCHIVES_PATH, "Tar.ContainsRar.tar");
|
||||
using (Stream stream = File.OpenRead(archiveFullPath))
|
||||
using (IReader reader = ReaderFactory.Open(stream))
|
||||
{
|
||||
Assert.IsTrue(reader.ArchiveType == ArchiveType.Tar);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
@@ -8,15 +9,15 @@ using SharpCompress.Reader;
|
||||
|
||||
namespace SharpCompress.Test
|
||||
{
|
||||
[TestClass]
|
||||
public class TestBase
|
||||
{
|
||||
protected const string TEST_BASE_PATH = @"C:\Git\sharpcompress";
|
||||
protected static readonly string TEST_ARCHIVES_PATH = Path.Combine(TEST_BASE_PATH, "TestArchives", "Archives");
|
||||
protected static readonly string ORIGINAL_FILES_PATH = Path.Combine(TEST_BASE_PATH, "TestArchives", "Original");
|
||||
protected static readonly string MISC_TEST_FILES_PATH = Path.Combine(TEST_BASE_PATH, "TestArchives", "MiscTest");
|
||||
protected static readonly string SCRATCH_FILES_PATH = Path.Combine(TEST_BASE_PATH, "TestArchives", "Scratch");
|
||||
protected static readonly string SCRATCH2_FILES_PATH = Path.Combine(TEST_BASE_PATH, "TestArchives", "Scratch2");
|
||||
|
||||
protected static string SOLUTION_BASE_PATH=null;
|
||||
protected static string TEST_ARCHIVES_PATH;
|
||||
protected static string ORIGINAL_FILES_PATH;
|
||||
protected static string MISC_TEST_FILES_PATH;
|
||||
protected static string SCRATCH_FILES_PATH;
|
||||
protected static string SCRATCH2_FILES_PATH;
|
||||
protected static IEnumerable<string> GetRarArchives()
|
||||
{
|
||||
yield return Path.Combine(TEST_ARCHIVES_PATH, "Rar.none.rar");
|
||||
@@ -77,6 +78,21 @@ namespace SharpCompress.Test
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the files also check modified time and attributes.
|
||||
/// </summary>
|
||||
public void VerifyFilesEx()
|
||||
{
|
||||
if (UseExtensionInsteadOfNameToVerify)
|
||||
{
|
||||
VerifyFilesByExtensionEx();
|
||||
}
|
||||
else
|
||||
{
|
||||
VerifyFilesByNameEx();
|
||||
}
|
||||
}
|
||||
|
||||
protected void VerifyFilesByName()
|
||||
{
|
||||
var extracted =
|
||||
@@ -96,6 +112,52 @@ namespace SharpCompress.Test
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the files by name also check modified time and attributes.
|
||||
/// </summary>
|
||||
protected void VerifyFilesByNameEx()
|
||||
{
|
||||
var extracted =
|
||||
Directory.EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories)
|
||||
.ToLookup(path => path.Substring(SCRATCH_FILES_PATH.Length));
|
||||
var original =
|
||||
Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories)
|
||||
.ToLookup(path => path.Substring(ORIGINAL_FILES_PATH.Length));
|
||||
|
||||
Assert.AreEqual(extracted.Count, original.Count);
|
||||
|
||||
foreach (var orig in original)
|
||||
{
|
||||
Assert.IsTrue(extracted.Contains(orig.Key));
|
||||
|
||||
CompareFilesByPath(orig.Single(), extracted[orig.Key].Single());
|
||||
CompareFilesByTimeAndAttribut(orig.Single(), extracted[orig.Key].Single());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the files by extension also check modified time and attributes.
|
||||
/// </summary>
|
||||
protected void VerifyFilesByExtensionEx()
|
||||
{
|
||||
var extracted =
|
||||
Directory.EnumerateFiles(SCRATCH_FILES_PATH, "*.*", SearchOption.AllDirectories)
|
||||
.ToLookup(path => Path.GetExtension(path));
|
||||
var original =
|
||||
Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories)
|
||||
.ToLookup(path => Path.GetExtension(path));
|
||||
|
||||
Assert.AreEqual(extracted.Count, original.Count);
|
||||
|
||||
foreach (var orig in original)
|
||||
{
|
||||
Assert.IsTrue(extracted.Contains(orig.Key));
|
||||
|
||||
CompareFilesByPath(orig.Single(), extracted[orig.Key].Single());
|
||||
CompareFilesByTimeAndAttribut(orig.Single(), extracted[orig.Key].Single());
|
||||
}
|
||||
}
|
||||
|
||||
protected bool UseExtensionInsteadOfNameToVerify { get; set; }
|
||||
|
||||
protected void VerifyFilesByExtension()
|
||||
@@ -136,6 +198,14 @@ namespace SharpCompress.Test
|
||||
}
|
||||
}
|
||||
|
||||
protected void CompareFilesByTimeAndAttribut(string file1, string file2)
|
||||
{
|
||||
FileInfo fi1 = new FileInfo(file1);
|
||||
FileInfo fi2 = new FileInfo(file2);
|
||||
Assert.AreNotEqual(fi1.LastWriteTime, fi2.LastWriteTime);
|
||||
Assert.AreEqual(fi1.Attributes, fi2.Attributes);
|
||||
}
|
||||
|
||||
protected void CompareArchivesByPath(string file1, string file2)
|
||||
{
|
||||
using (var archive1 = ReaderFactory.Open(File.OpenRead(file1), Options.None))
|
||||
@@ -144,7 +214,7 @@ namespace SharpCompress.Test
|
||||
while (archive1.MoveToNextEntry())
|
||||
{
|
||||
Assert.IsTrue(archive2.MoveToNextEntry());
|
||||
Assert.AreEqual(archive1.Entry.FilePath, archive2.Entry.FilePath);
|
||||
Assert.AreEqual(archive1.Entry.Key, archive2.Entry.Key);
|
||||
}
|
||||
Assert.IsFalse(archive2.MoveToNextEntry());
|
||||
}
|
||||
@@ -152,16 +222,15 @@ namespace SharpCompress.Test
|
||||
|
||||
private static readonly object testLock = new object();
|
||||
|
||||
[TestInitialize]
|
||||
public void TestSetup()
|
||||
[AssemblyInitialize]
|
||||
public static void InitializePaths(TestContext ctx)
|
||||
{
|
||||
Monitor.Enter(testLock);
|
||||
}
|
||||
|
||||
[TestCleanup]
|
||||
public void TestCleanup()
|
||||
{
|
||||
Monitor.Exit(testLock);
|
||||
SOLUTION_BASE_PATH = Path.GetDirectoryName(Path.GetDirectoryName(ctx.TestDir));
|
||||
TEST_ARCHIVES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "Archives");
|
||||
ORIGINAL_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "Original");
|
||||
MISC_TEST_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "MiscTest");
|
||||
SCRATCH_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "Scratch");
|
||||
SCRATCH2_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "Scratch2");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using SharpCompress.Archive;
|
||||
using SharpCompress.Archive.Zip;
|
||||
@@ -138,26 +140,7 @@ namespace SharpCompress.Test
|
||||
base.ResetScratch();
|
||||
using (var archive = ZipArchive.Open(unmodified))
|
||||
{
|
||||
var entry = archive.Entries.Where(x => x.FilePath.EndsWith("jpg")).Single();
|
||||
archive.RemoveEntry(entry);
|
||||
archive.SaveTo(scratchPath, CompressionType.Deflate);
|
||||
}
|
||||
CompareArchivesByPath(modified, scratchPath);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(ArchiveException))]
|
||||
public void Zip_Random_Write_Remove_Fail()
|
||||
{
|
||||
string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Zip.deflate.mod.zip");
|
||||
string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip");
|
||||
string modified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.mod.zip");
|
||||
|
||||
base.ResetScratch();
|
||||
using (var stream = File.OpenRead(unmodified))
|
||||
using (var archive = ZipArchive.Open(stream))
|
||||
{
|
||||
var entry = archive.Entries.Where(x => x.FilePath.EndsWith("jpg")).Single();
|
||||
var entry = archive.Entries.Single(x => x.Key.EndsWith("jpg"));
|
||||
archive.RemoveEntry(entry);
|
||||
archive.SaveTo(scratchPath, CompressionType.Deflate);
|
||||
}
|
||||
@@ -181,19 +164,133 @@ namespace SharpCompress.Test
|
||||
CompareArchivesByPath(modified, scratchPath);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Zip_Save_Twice()
|
||||
{
|
||||
string scratchPath1 = Path.Combine(SCRATCH_FILES_PATH, "a.zip");
|
||||
string scratchPath2 = Path.Combine(SCRATCH_FILES_PATH, "b.zip");
|
||||
|
||||
ResetScratch();
|
||||
using (var arc = ZipArchive.Create())
|
||||
{
|
||||
string str = "test.txt";
|
||||
var source = new MemoryStream(Encoding.UTF8.GetBytes(str));
|
||||
arc.AddEntry("test.txt", source, true, source.Length);
|
||||
arc.SaveTo(scratchPath1, CompressionType.Deflate);
|
||||
arc.SaveTo(scratchPath2, CompressionType.Deflate);
|
||||
}
|
||||
|
||||
Assert.AreEqual(new FileInfo(scratchPath1).Length, new FileInfo(scratchPath2).Length);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Zip_Removal_Poly()
|
||||
{
|
||||
ResetScratch();
|
||||
|
||||
string scratchPath = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip");
|
||||
|
||||
|
||||
|
||||
using (ZipArchive vfs = (ZipArchive)ArchiveFactory.Open(scratchPath))
|
||||
{
|
||||
var e = vfs.Entries.First(v => v.Key.EndsWith("jpg"));
|
||||
vfs.RemoveEntry(e);
|
||||
Assert.IsNull(vfs.Entries.FirstOrDefault(v => v.Key.EndsWith("jpg")));
|
||||
Assert.IsNull(((IArchive)vfs).Entries.FirstOrDefault(v => v.Key.EndsWith("jpg")));
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(ArchiveException))]
|
||||
public void Zip_Create_NoDups()
|
||||
{
|
||||
using (var arc = ZipArchive.Create())
|
||||
{
|
||||
arc.AddEntry("1.txt", new MemoryStream());
|
||||
arc.AddEntry("\\1.txt", new MemoryStream());
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Zip_Create_Same_Stream()
|
||||
{
|
||||
string scratchPath1 = Path.Combine(SCRATCH_FILES_PATH, "a.zip");
|
||||
string scratchPath2 = Path.Combine(SCRATCH_FILES_PATH, "b.zip");
|
||||
|
||||
using (var arc = ZipArchive.Create())
|
||||
{
|
||||
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes("qwert")))
|
||||
{
|
||||
arc.AddEntry("1.txt", stream, false, stream.Length);
|
||||
arc.AddEntry("2.txt", stream, false, stream.Length);
|
||||
arc.SaveTo(scratchPath1, CompressionType.Deflate);
|
||||
arc.SaveTo(scratchPath2, CompressionType.Deflate);
|
||||
}
|
||||
}
|
||||
|
||||
Assert.AreEqual(new FileInfo(scratchPath1).Length, new FileInfo(scratchPath2).Length);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Zip_Create_New()
|
||||
{
|
||||
string scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Zip.deflate.noEmptyDirs.zip");
|
||||
base.ResetScratch();
|
||||
foreach (var file in Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories))
|
||||
{
|
||||
var newFileName = file.Substring(ORIGINAL_FILES_PATH.Length);
|
||||
if (newFileName.StartsWith(Path.DirectorySeparatorChar.ToString()))
|
||||
{
|
||||
newFileName = newFileName.Substring(1);
|
||||
}
|
||||
newFileName = Path.Combine(SCRATCH_FILES_PATH, newFileName);
|
||||
var newDir = Path.GetDirectoryName(newFileName);
|
||||
if (!Directory.Exists(newDir))
|
||||
{
|
||||
Directory.CreateDirectory(newDir);
|
||||
}
|
||||
File.Copy(file, newFileName);
|
||||
}
|
||||
string scratchPath = Path.Combine(SCRATCH2_FILES_PATH, "Zip.deflate.noEmptyDirs.zip");
|
||||
string unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Zip.deflate.noEmptyDirs.zip");
|
||||
|
||||
base.ResetScratch();
|
||||
using (var archive = ZipArchive.Create())
|
||||
{
|
||||
archive.AddAllFromDirectory(ORIGINAL_FILES_PATH);
|
||||
archive.AddAllFromDirectory(SCRATCH_FILES_PATH);
|
||||
archive.SaveTo(scratchPath, CompressionType.Deflate);
|
||||
}
|
||||
CompareArchivesByPath(unmodified, scratchPath);
|
||||
Directory.Delete(SCRATCH_FILES_PATH, true);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Zip_Create_New_Add_Remove()
|
||||
{
|
||||
base.ResetScratch();
|
||||
foreach (var file in Directory.EnumerateFiles(ORIGINAL_FILES_PATH, "*.*", SearchOption.AllDirectories))
|
||||
{
|
||||
var newFileName = file.Substring(ORIGINAL_FILES_PATH.Length);
|
||||
if (newFileName.StartsWith(Path.DirectorySeparatorChar.ToString()))
|
||||
{
|
||||
newFileName = newFileName.Substring(1);
|
||||
}
|
||||
newFileName = Path.Combine(SCRATCH_FILES_PATH, newFileName);
|
||||
var newDir = Path.GetDirectoryName(newFileName);
|
||||
if (!Directory.Exists(newDir))
|
||||
{
|
||||
Directory.CreateDirectory(newDir);
|
||||
}
|
||||
File.Copy(file, newFileName);
|
||||
}
|
||||
string scratchPath = Path.Combine(SCRATCH2_FILES_PATH, "Zip.deflate.noEmptyDirs.zip");
|
||||
|
||||
using (var archive = ZipArchive.Create())
|
||||
{
|
||||
archive.AddAllFromDirectory(SCRATCH_FILES_PATH);
|
||||
archive.RemoveEntry(archive.Entries.Single(x => x.Key.EndsWith("jpg", StringComparison.OrdinalIgnoreCase)));
|
||||
Assert.IsFalse(archive.Entries.Any(x => x.Key.EndsWith("jpg")));
|
||||
}
|
||||
Directory.Delete(SCRATCH_FILES_PATH, true);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
@@ -292,7 +389,7 @@ namespace SharpCompress.Test
|
||||
|
||||
using (var zipArchive = ZipArchive.Open(stream))
|
||||
{
|
||||
foreach(var entry in zipArchive.Entries)
|
||||
foreach (var entry in zipArchive.Entries)
|
||||
{
|
||||
using (var entryStream = entry.OpenEntryStream())
|
||||
{
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2012
|
||||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.31101.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Testing", "Testing", "{932BBFCC-76E3-45FF-90CA-6BE4FBF4A097}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F18F1765-4A02-42FD-9BEF-F0E2FCBD9D17}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
NuGet\sharpcompress.nuspec = NuGet\sharpcompress.nuspec
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpCompress", "SharpCompress\SharpCompress.csproj", "{10A689CF-76A2-4A4F-96E4-553C33398438}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpCompress.Test", "SharpCompress.Test\SharpCompress.Test.csproj", "{15679D7A-F22C-4943-87FF-BF5C76C4A6FD}"
|
||||
@@ -13,93 +22,50 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpCompress.PortableTest"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpCompress.Test.Portable", "SharpCompress.Test\SharpCompress.Test.Portable.csproj", "{E9C3C94B-FB27-4B4F-B225-57513C254D37}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Testing", "Testing", "{932BBFCC-76E3-45FF-90CA-6BE4FBF4A097}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpCompress.Unsigned", "SharpCompress\SharpCompress.Unsigned.csproj", "{27D535CB-2FD3-4621-8C9A-46161FC77A5D}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|ARM = Debug|ARM
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|ARM = Release|ARM
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{10A689CF-76A2-4A4F-96E4-553C33398438}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{10A689CF-76A2-4A4F-96E4-553C33398438}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{10A689CF-76A2-4A4F-96E4-553C33398438}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{10A689CF-76A2-4A4F-96E4-553C33398438}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{10A689CF-76A2-4A4F-96E4-553C33398438}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{10A689CF-76A2-4A4F-96E4-553C33398438}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{10A689CF-76A2-4A4F-96E4-553C33398438}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{10A689CF-76A2-4A4F-96E4-553C33398438}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{10A689CF-76A2-4A4F-96E4-553C33398438}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{10A689CF-76A2-4A4F-96E4-553C33398438}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{15679D7A-F22C-4943-87FF-BF5C76C4A6FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{15679D7A-F22C-4943-87FF-BF5C76C4A6FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{15679D7A-F22C-4943-87FF-BF5C76C4A6FD}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{15679D7A-F22C-4943-87FF-BF5C76C4A6FD}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{15679D7A-F22C-4943-87FF-BF5C76C4A6FD}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{15679D7A-F22C-4943-87FF-BF5C76C4A6FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{15679D7A-F22C-4943-87FF-BF5C76C4A6FD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{15679D7A-F22C-4943-87FF-BF5C76C4A6FD}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{15679D7A-F22C-4943-87FF-BF5C76C4A6FD}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{15679D7A-F22C-4943-87FF-BF5C76C4A6FD}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{7FA7D133-1417-4F85-9998-4C618AC8FEDA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7FA7D133-1417-4F85-9998-4C618AC8FEDA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7FA7D133-1417-4F85-9998-4C618AC8FEDA}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{7FA7D133-1417-4F85-9998-4C618AC8FEDA}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{7FA7D133-1417-4F85-9998-4C618AC8FEDA}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{7FA7D133-1417-4F85-9998-4C618AC8FEDA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7FA7D133-1417-4F85-9998-4C618AC8FEDA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7FA7D133-1417-4F85-9998-4C618AC8FEDA}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{7FA7D133-1417-4F85-9998-4C618AC8FEDA}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{7FA7D133-1417-4F85-9998-4C618AC8FEDA}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Debug|ARM.ActiveCfg = Debug|ARM
|
||||
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Debug|ARM.Build.0 = Debug|ARM
|
||||
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Debug|x64.Build.0 = Debug|x64
|
||||
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Debug|x86.Build.0 = Debug|x86
|
||||
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Release|ARM.ActiveCfg = Release|ARM
|
||||
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Release|ARM.Build.0 = Release|ARM
|
||||
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Release|x64.ActiveCfg = Release|x64
|
||||
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Release|x64.Build.0 = Release|x64
|
||||
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Release|x86.ActiveCfg = Release|x86
|
||||
{1DF6D83C-31FF-47B6-82FE-C4603BE916B5}.Release|x86.Build.0 = Release|x86
|
||||
{EFDCAF57-FD4D-4E5D-A3D5-F26B875817ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EFDCAF57-FD4D-4E5D-A3D5-F26B875817ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EFDCAF57-FD4D-4E5D-A3D5-F26B875817ED}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{EFDCAF57-FD4D-4E5D-A3D5-F26B875817ED}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{EFDCAF57-FD4D-4E5D-A3D5-F26B875817ED}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{EFDCAF57-FD4D-4E5D-A3D5-F26B875817ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EFDCAF57-FD4D-4E5D-A3D5-F26B875817ED}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{EFDCAF57-FD4D-4E5D-A3D5-F26B875817ED}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{EFDCAF57-FD4D-4E5D-A3D5-F26B875817ED}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{EFDCAF57-FD4D-4E5D-A3D5-F26B875817ED}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{E9C3C94B-FB27-4B4F-B225-57513C254D37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E9C3C94B-FB27-4B4F-B225-57513C254D37}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E9C3C94B-FB27-4B4F-B225-57513C254D37}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{E9C3C94B-FB27-4B4F-B225-57513C254D37}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{E9C3C94B-FB27-4B4F-B225-57513C254D37}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{E9C3C94B-FB27-4B4F-B225-57513C254D37}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E9C3C94B-FB27-4B4F-B225-57513C254D37}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E9C3C94B-FB27-4B4F-B225-57513C254D37}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{E9C3C94B-FB27-4B4F-B225-57513C254D37}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{E9C3C94B-FB27-4B4F-B225-57513C254D37}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{27D535CB-2FD3-4621-8C9A-46161FC77A5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{27D535CB-2FD3-4621-8C9A-46161FC77A5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{27D535CB-2FD3-4621-8C9A-46161FC77A5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{27D535CB-2FD3-4621-8C9A-46161FC77A5D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{EFDCAF57-FD4D-4E5D-A3D5-F26B875817ED} = {932BBFCC-76E3-45FF-90CA-6BE4FBF4A097}
|
||||
{15679D7A-F22C-4943-87FF-BF5C76C4A6FD} = {932BBFCC-76E3-45FF-90CA-6BE4FBF4A097}
|
||||
{EFDCAF57-FD4D-4E5D-A3D5-F26B875817ED} = {932BBFCC-76E3-45FF-90CA-6BE4FBF4A097}
|
||||
{E9C3C94B-FB27-4B4F-B225-57513C254D37} = {932BBFCC-76E3-45FF-90CA-6BE4FBF4A097}
|
||||
{27D535CB-2FD3-4621-8C9A-46161FC77A5D} = {932BBFCC-76E3-45FF-90CA-6BE4FBF4A097}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@@ -7,7 +7,7 @@ using SharpCompress.Reader;
|
||||
|
||||
namespace SharpCompress.Archive
|
||||
{
|
||||
public abstract class AbstractArchive<TEntry, TVolume> : IArchive, IStreamListener
|
||||
public abstract class AbstractArchive<TEntry, TVolume> : IArchive, IArchiveExtractionListener
|
||||
where TEntry : IArchiveEntry
|
||||
where TVolume : IVolume
|
||||
{
|
||||
@@ -20,10 +20,13 @@ namespace SharpCompress.Archive
|
||||
public event EventHandler<CompressedBytesReadEventArgs> CompressedBytesRead;
|
||||
public event EventHandler<FilePartExtractionBeginEventArgs> FilePartExtractionBegin;
|
||||
|
||||
protected string Password { get; private set; }
|
||||
|
||||
#if !PORTABLE && !NETFX_CORE
|
||||
internal AbstractArchive(ArchiveType type, FileInfo fileInfo, Options options)
|
||||
internal AbstractArchive(ArchiveType type, FileInfo fileInfo, Options options, string password)
|
||||
{
|
||||
this.Type = type;
|
||||
Type = type;
|
||||
Password = password;
|
||||
if (!fileInfo.Exists)
|
||||
{
|
||||
throw new ArgumentException("File does not exist: " + fileInfo.FullName);
|
||||
@@ -37,22 +40,23 @@ namespace SharpCompress.Archive
|
||||
protected abstract IEnumerable<TVolume> LoadVolumes(FileInfo file, Options options);
|
||||
#endif
|
||||
|
||||
internal AbstractArchive(ArchiveType type, IEnumerable<Stream> streams, Options options)
|
||||
internal AbstractArchive(ArchiveType type, IEnumerable<Stream> streams, Options options, string password)
|
||||
{
|
||||
this.Type = type;
|
||||
lazyVolumes =
|
||||
new LazyReadOnlyCollection<TVolume>(LoadVolumes(streams.Select<Stream, Stream>(CheckStreams), options));
|
||||
Type = type;
|
||||
Password = password;
|
||||
lazyVolumes = new LazyReadOnlyCollection<TVolume>(LoadVolumes(streams.Select(CheckStreams), options));
|
||||
lazyEntries = new LazyReadOnlyCollection<TEntry>(LoadEntries(Volumes));
|
||||
}
|
||||
|
||||
internal AbstractArchive(ArchiveType type)
|
||||
{
|
||||
this.Type = type;
|
||||
Type = type;
|
||||
lazyVolumes = new LazyReadOnlyCollection<TVolume>(Enumerable.Empty<TVolume>());
|
||||
lazyEntries = new LazyReadOnlyCollection<TEntry>(Enumerable.Empty<TEntry>());
|
||||
}
|
||||
public ArchiveType Type { get; private set; }
|
||||
|
||||
internal void FireEntryExtractionBegin(IArchiveEntry entry)
|
||||
void IArchiveExtractionListener.FireEntryExtractionBegin(IArchiveEntry entry)
|
||||
{
|
||||
if (EntryExtractionBegin != null)
|
||||
{
|
||||
@@ -60,7 +64,7 @@ namespace SharpCompress.Archive
|
||||
}
|
||||
}
|
||||
|
||||
internal void FireEntryExtractionEnd(IArchiveEntry entry)
|
||||
void IArchiveExtractionListener.FireEntryExtractionEnd(IArchiveEntry entry)
|
||||
{
|
||||
if (EntryExtractionEnd != null)
|
||||
{
|
||||
@@ -80,7 +84,6 @@ namespace SharpCompress.Archive
|
||||
/// <summary>
|
||||
/// Returns an ReadOnlyCollection of all the RarArchiveEntries across the one or many parts of the RarArchive.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual ICollection<TEntry> Entries
|
||||
{
|
||||
get { return lazyEntries; }
|
||||
@@ -89,7 +92,6 @@ namespace SharpCompress.Archive
|
||||
/// <summary>
|
||||
/// Returns an ReadOnlyCollection of all the RarArchiveVolumes across the one or many parts of the RarArchive.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public ICollection<TVolume> Volumes
|
||||
{
|
||||
get { return lazyVolumes; }
|
||||
@@ -98,17 +100,25 @@ namespace SharpCompress.Archive
|
||||
/// <summary>
|
||||
/// The total size of the files compressed in the archive.
|
||||
/// </summary>
|
||||
public long TotalSize
|
||||
public virtual long TotalSize
|
||||
{
|
||||
get { return Entries.Aggregate(0L, (total, cf) => total + cf.CompressedSize); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The total size of the files as uncompressed in the archive.
|
||||
/// </summary>
|
||||
public virtual long TotalUncompressSize
|
||||
{
|
||||
get { return Entries.Aggregate(0L, (total, cf) => total + cf.Size); }
|
||||
}
|
||||
|
||||
protected abstract IEnumerable<TVolume> LoadVolumes(IEnumerable<Stream> streams, Options options);
|
||||
protected abstract IEnumerable<TEntry> LoadEntries(IEnumerable<TVolume> volumes);
|
||||
|
||||
IEnumerable<IArchiveEntry> IArchive.Entries
|
||||
{
|
||||
get { return lazyEntries.Cast<IArchiveEntry>(); }
|
||||
get { return Entries.Cast<IArchiveEntry>(); }
|
||||
}
|
||||
|
||||
IEnumerable<IVolume> IArchive.Volumes
|
||||
@@ -118,7 +128,7 @@ namespace SharpCompress.Archive
|
||||
|
||||
private bool disposed;
|
||||
|
||||
public void Dispose()
|
||||
public virtual void Dispose()
|
||||
{
|
||||
if (!disposed)
|
||||
{
|
||||
@@ -128,16 +138,13 @@ namespace SharpCompress.Archive
|
||||
}
|
||||
}
|
||||
|
||||
internal void EnsureEntriesLoaded()
|
||||
void IArchiveExtractionListener.EnsureEntriesLoaded()
|
||||
{
|
||||
lazyEntries.EnsureFullyLoaded();
|
||||
lazyVolumes.EnsureFullyLoaded();
|
||||
}
|
||||
|
||||
|
||||
public ArchiveType Type { get; private set; }
|
||||
|
||||
void IStreamListener.FireCompressedBytesRead(long currentPartCompressedBytes, long compressedReadBytes)
|
||||
void IExtractionListener.FireCompressedBytesRead(long currentPartCompressedBytes, long compressedReadBytes)
|
||||
{
|
||||
if (CompressedBytesRead != null)
|
||||
{
|
||||
@@ -149,7 +156,7 @@ namespace SharpCompress.Archive
|
||||
}
|
||||
}
|
||||
|
||||
void IStreamListener.FireFilePartExtractionBegin(string name, long size, long compressedSize)
|
||||
void IExtractionListener.FireFilePartExtractionBegin(string name, long size, long compressedSize)
|
||||
{
|
||||
if (FilePartExtractionBegin != null)
|
||||
{
|
||||
@@ -175,7 +182,7 @@ namespace SharpCompress.Archive
|
||||
/// <returns></returns>
|
||||
public IReader ExtractAllEntries()
|
||||
{
|
||||
EnsureEntriesLoaded();
|
||||
((IArchiveExtractionListener)this).EnsureEntriesLoaded();
|
||||
return CreateReaderForSolidExtraction();
|
||||
}
|
||||
|
||||
@@ -197,7 +204,7 @@ namespace SharpCompress.Archive
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureEntriesLoaded();
|
||||
((IArchiveExtractionListener)this).EnsureEntriesLoaded();
|
||||
return Entries.All(x => x.IsComplete);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress.Archive
|
||||
{
|
||||
public abstract class AbstractWritableArchive<TEntry, TVolume> : AbstractArchive<TEntry, TVolume>
|
||||
public abstract class AbstractWritableArchive<TEntry, TVolume> : AbstractArchive<TEntry, TVolume>, IWritableArchive
|
||||
where TEntry : IArchiveEntry
|
||||
where TVolume : IVolume
|
||||
{
|
||||
@@ -15,37 +15,24 @@ namespace SharpCompress.Archive
|
||||
|
||||
private readonly List<TEntry> modifiedEntries = new List<TEntry>();
|
||||
private bool hasModifications;
|
||||
private readonly bool anyNotWritable;
|
||||
|
||||
internal AbstractWritableArchive(ArchiveType type)
|
||||
: base(type)
|
||||
{
|
||||
}
|
||||
|
||||
internal AbstractWritableArchive(ArchiveType type, IEnumerable<Stream> streams, Options options)
|
||||
: base(type, streams, options)
|
||||
internal AbstractWritableArchive(ArchiveType type, Stream stream, Options options)
|
||||
: base(type, stream.AsEnumerable(), options, null)
|
||||
{
|
||||
if (streams.Any(x => !x.CanWrite))
|
||||
{
|
||||
anyNotWritable = true;
|
||||
}
|
||||
}
|
||||
|
||||
#if !PORTABLE && !NETFX_CORE
|
||||
internal AbstractWritableArchive(ArchiveType type, FileInfo fileInfo, Options options)
|
||||
: base(type, fileInfo, options)
|
||||
: base(type, fileInfo, options, null)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
private void CheckWritable()
|
||||
{
|
||||
if (anyNotWritable)
|
||||
{
|
||||
throw new ArchiveException("All Archive streams must be Writable to use Archive writing functionality.");
|
||||
}
|
||||
}
|
||||
|
||||
public override ICollection<TEntry> Entries
|
||||
{
|
||||
get
|
||||
@@ -61,6 +48,7 @@ namespace SharpCompress.Archive
|
||||
private void RebuildModifiedCollection()
|
||||
{
|
||||
hasModifications = true;
|
||||
newEntries.RemoveAll(v => removedEntries.Contains(v));
|
||||
modifiedEntries.Clear();
|
||||
modifiedEntries.AddRange(OldEntries.Concat(newEntries));
|
||||
}
|
||||
@@ -72,50 +60,90 @@ namespace SharpCompress.Archive
|
||||
|
||||
public void RemoveEntry(TEntry entry)
|
||||
{
|
||||
CheckWritable();
|
||||
if (!removedEntries.Contains(entry))
|
||||
{
|
||||
removedEntries.Add(entry);
|
||||
RebuildModifiedCollection();
|
||||
}
|
||||
}
|
||||
|
||||
public void AddEntry(string filePath, Stream source,
|
||||
long size = 0, DateTime? modified = null)
|
||||
void IWritableArchive.RemoveEntry(IArchiveEntry entry)
|
||||
{
|
||||
CheckWritable();
|
||||
newEntries.Add(CreateEntry(filePath, source, size, modified, false));
|
||||
RebuildModifiedCollection();
|
||||
RemoveEntry((TEntry)entry);
|
||||
}
|
||||
|
||||
public void AddEntry(string filePath, Stream source, bool closeStream,
|
||||
public TEntry AddEntry(string key, Stream source,
|
||||
long size = 0, DateTime? modified = null)
|
||||
{
|
||||
CheckWritable();
|
||||
newEntries.Add(CreateEntry(filePath, source, size, modified, closeStream));
|
||||
RebuildModifiedCollection();
|
||||
return AddEntry(key, source, false, size, modified);
|
||||
}
|
||||
|
||||
#if !PORTABLE && !NETFX_CORE
|
||||
public void AddEntry(string filePath, FileInfo fileInfo)
|
||||
|
||||
IArchiveEntry IWritableArchive.AddEntry(string key, Stream source, bool closeStream, long size, DateTime? modified)
|
||||
{
|
||||
if (!fileInfo.Exists)
|
||||
return AddEntry(key, source, closeStream, size, modified);
|
||||
}
|
||||
|
||||
public TEntry AddEntry(string key, Stream source, bool closeStream,
|
||||
long size = 0, DateTime? modified = null)
|
||||
{
|
||||
if (key.StartsWith("/")
|
||||
|| key.StartsWith("\\"))
|
||||
{
|
||||
throw new ArgumentException("FileInfo does not exist.");
|
||||
key = key.Substring(1);
|
||||
}
|
||||
AddEntry(filePath, fileInfo.OpenRead(), true, fileInfo.Length, fileInfo.LastWriteTime);
|
||||
if (DoesKeyMatchExisting(key))
|
||||
{
|
||||
throw new ArchiveException("Cannot add entry with duplicate key: " + key);
|
||||
}
|
||||
var entry = CreateEntry(key, source, size, modified, closeStream);
|
||||
newEntries.Add(entry);
|
||||
RebuildModifiedCollection();
|
||||
return entry;
|
||||
}
|
||||
|
||||
private bool DoesKeyMatchExisting(string key)
|
||||
{
|
||||
foreach (var path in Entries.Select(x => x.Key))
|
||||
{
|
||||
var p = path.Replace('/','\\');
|
||||
if (p.StartsWith("\\"))
|
||||
{
|
||||
p = p.Substring(1);
|
||||
}
|
||||
return string.Equals(p, key, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
public void SaveTo(Stream stream, CompressionInfo compressionType)
|
||||
{
|
||||
//reset streams of new entries
|
||||
newEntries.Cast<IWritableArchiveEntry>().ForEach(x => x.Stream.Seek(0, SeekOrigin.Begin));
|
||||
SaveTo(stream, compressionType, OldEntries, newEntries);
|
||||
}
|
||||
|
||||
protected abstract TEntry CreateEntry(string filePath, Stream source, long size, DateTime? modified,
|
||||
protected TEntry CreateEntry(string key, Stream source, long size, DateTime? modified,
|
||||
bool closeStream)
|
||||
{
|
||||
if (!source.CanRead || !source.CanSeek)
|
||||
{
|
||||
throw new ArgumentException("Streams must be readable and seekable to use the Writing Archive API");
|
||||
}
|
||||
return CreateEntryInternal(key, source, size, modified, closeStream);
|
||||
}
|
||||
|
||||
protected abstract TEntry CreateEntryInternal(string key, Stream source, long size, DateTime? modified,
|
||||
bool closeStream);
|
||||
|
||||
protected abstract void SaveTo(Stream stream, CompressionInfo compressionType,
|
||||
IEnumerable<TEntry> oldEntries, IEnumerable<TEntry> newEntries);
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
newEntries.Cast<Entry>().ForEach(x => x.Close());
|
||||
removedEntries.Cast<Entry>().ForEach(x => x.Close());
|
||||
modifiedEntries.Cast<Entry>().ForEach(x => x.Close());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,18 +31,6 @@ namespace SharpCompress.Archive
|
||||
return ZipArchive.Open(stream, options, null);
|
||||
}
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if (RarArchive.IsRarFile(stream, Options.LookForHeader | Options.KeepStreamsOpen))
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
return RarArchive.Open(stream, options);
|
||||
}
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if (TarArchive.IsTarFile(stream))
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
return TarArchive.Open(stream, options);
|
||||
}
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if (SevenZipArchive.IsSevenZipFile(stream))
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
@@ -54,10 +42,22 @@ namespace SharpCompress.Archive
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
return GZipArchive.Open(stream, options);
|
||||
}
|
||||
throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip");
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if (RarArchive.IsRarFile(stream, options))
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
return RarArchive.Open(stream, options);
|
||||
}
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if (TarArchive.IsTarFile(stream))
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
return TarArchive.Open(stream, options);
|
||||
}
|
||||
throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip");
|
||||
}
|
||||
|
||||
public static IArchive Create(ArchiveType type)
|
||||
public static IWritableArchive Create(ArchiveType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
@@ -69,6 +69,10 @@ namespace SharpCompress.Archive
|
||||
{
|
||||
return TarArchive.Create();
|
||||
}
|
||||
case ArchiveType.GZip:
|
||||
{
|
||||
return GZipArchive.Create();
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new NotSupportedException("Cannot create Archives of type: " + type);
|
||||
@@ -122,18 +126,6 @@ namespace SharpCompress.Archive
|
||||
return ZipArchive.Open(fileInfo, options, null);
|
||||
}
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if (RarArchive.IsRarFile(stream, Options.LookForHeader | Options.KeepStreamsOpen))
|
||||
{
|
||||
stream.Dispose();
|
||||
return RarArchive.Open(fileInfo, options);
|
||||
}
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if (TarArchive.IsTarFile(stream))
|
||||
{
|
||||
stream.Dispose();
|
||||
return TarArchive.Open(fileInfo, options);
|
||||
}
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if (SevenZipArchive.IsSevenZipFile(stream))
|
||||
{
|
||||
stream.Dispose();
|
||||
@@ -145,7 +137,19 @@ namespace SharpCompress.Archive
|
||||
stream.Dispose();
|
||||
return GZipArchive.Open(fileInfo, options);
|
||||
}
|
||||
throw new InvalidOperationException("Cannot determine compressed stream type.");
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if (RarArchive.IsRarFile(stream, options))
|
||||
{
|
||||
stream.Dispose();
|
||||
return RarArchive.Open(fileInfo, options);
|
||||
}
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if (TarArchive.IsTarFile(stream))
|
||||
{
|
||||
stream.Dispose();
|
||||
return TarArchive.Open(fileInfo, options);
|
||||
}
|
||||
throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -75,6 +75,11 @@ namespace SharpCompress.Archive.GZip
|
||||
return new GZipArchive(stream, options);
|
||||
}
|
||||
|
||||
public static GZipArchive Create()
|
||||
{
|
||||
return new GZipArchive();
|
||||
}
|
||||
|
||||
#if !PORTABLE && !NETFX_CORE
|
||||
/// <summary>
|
||||
/// Constructor with a FileInfo object to an existing file.
|
||||
@@ -147,7 +152,7 @@ namespace SharpCompress.Archive.GZip
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="options"></param>
|
||||
internal GZipArchive(Stream stream, Options options)
|
||||
: base(ArchiveType.GZip, stream.AsEnumerable(), options)
|
||||
: base(ArchiveType.GZip, stream, options)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -158,10 +163,10 @@ namespace SharpCompress.Archive.GZip
|
||||
|
||||
public void SaveTo(Stream stream)
|
||||
{
|
||||
this.SaveTo(stream, CompressionType.GZip);
|
||||
SaveTo(stream, CompressionType.GZip);
|
||||
}
|
||||
|
||||
protected override GZipArchiveEntry CreateEntry(string filePath, Stream source, long size, DateTime? modified,
|
||||
protected override GZipArchiveEntry CreateEntryInternal(string filePath, Stream source, long size, DateTime? modified,
|
||||
bool closeStream)
|
||||
{
|
||||
if (Entries.Any())
|
||||
@@ -186,7 +191,7 @@ namespace SharpCompress.Archive.GZip
|
||||
{
|
||||
using (var entryStream = entry.OpenEntryStream())
|
||||
{
|
||||
writer.Write(entry.FilePath, entryStream, entry.LastModifiedTime);
|
||||
writer.Write(entry.Key, entryStream, entry.LastModifiedTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.GZip;
|
||||
|
||||
namespace SharpCompress.Archive.GZip
|
||||
{
|
||||
public class GZipArchiveEntry : GZipEntry, IArchiveEntry
|
||||
{
|
||||
private GZipArchive archive;
|
||||
|
||||
internal GZipArchiveEntry(GZipArchive archive, GZipFilePart part)
|
||||
: base(part)
|
||||
{
|
||||
this.archive = archive;
|
||||
Archive = archive;
|
||||
}
|
||||
|
||||
public virtual Stream OpenEntryStream()
|
||||
@@ -21,15 +19,7 @@ namespace SharpCompress.Archive.GZip
|
||||
}
|
||||
|
||||
#region IArchiveEntry Members
|
||||
|
||||
public void WriteTo(Stream streamToWriteTo)
|
||||
{
|
||||
if (IsEncrypted)
|
||||
{
|
||||
throw new PasswordProtectedException("Entry is password protected and cannot be extracted.");
|
||||
}
|
||||
this.Extract(archive, streamToWriteTo);
|
||||
}
|
||||
public IArchive Archive { get; private set; }
|
||||
|
||||
public bool IsComplete
|
||||
{
|
||||
|
||||
@@ -6,30 +6,31 @@ using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress.Archive.GZip
|
||||
{
|
||||
internal class GZipWritableArchiveEntry : GZipArchiveEntry
|
||||
internal class GZipWritableArchiveEntry : GZipArchiveEntry, IWritableArchiveEntry
|
||||
{
|
||||
private string path;
|
||||
private long size;
|
||||
private DateTime? lastModified;
|
||||
private bool closeStream;
|
||||
private readonly string path;
|
||||
private readonly long size;
|
||||
private readonly DateTime? lastModified;
|
||||
private readonly bool closeStream;
|
||||
private readonly Stream stream;
|
||||
|
||||
internal GZipWritableArchiveEntry(GZipArchive archive, Stream stream,
|
||||
string path, long size, DateTime? lastModified, bool closeStream)
|
||||
: base(archive, null)
|
||||
{
|
||||
this.Stream = stream;
|
||||
this.stream = stream;
|
||||
this.path = path;
|
||||
this.size = size;
|
||||
this.lastModified = lastModified;
|
||||
this.closeStream = closeStream;
|
||||
}
|
||||
|
||||
public override uint Crc
|
||||
public override long Crc
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public override string FilePath
|
||||
public override string Key
|
||||
{
|
||||
get { return path; }
|
||||
}
|
||||
@@ -84,18 +85,26 @@ namespace SharpCompress.Archive.GZip
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
internal Stream Stream { get; private set; }
|
||||
Stream IWritableArchiveEntry.Stream
|
||||
{
|
||||
get
|
||||
{
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
|
||||
public override Stream OpenEntryStream()
|
||||
{
|
||||
return new NonDisposingStream(Stream);
|
||||
//ensure new stream is at the start, this could be reset
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
return new NonDisposingStream(stream);
|
||||
}
|
||||
|
||||
internal override void Close()
|
||||
{
|
||||
if (closeStream)
|
||||
{
|
||||
Stream.Dispose();
|
||||
stream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ namespace SharpCompress.Archive
|
||||
event EventHandler<FilePartExtractionBeginEventArgs> FilePartExtractionBegin;
|
||||
|
||||
IEnumerable<IArchiveEntry> Entries { get; }
|
||||
long TotalSize { get; }
|
||||
IEnumerable<IVolume> Volumes { get; }
|
||||
|
||||
ArchiveType Type { get; }
|
||||
@@ -24,7 +23,6 @@ namespace SharpCompress.Archive
|
||||
/// This is primarily for SOLID Rar Archives or 7Zip Archives as they need to be
|
||||
/// extracted sequentially for the best performance.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IReader ExtractAllEntries();
|
||||
|
||||
/// <summary>
|
||||
@@ -37,5 +35,15 @@ namespace SharpCompress.Archive
|
||||
/// This checks to see if all the known entries have IsComplete = true
|
||||
/// </summary>
|
||||
bool IsComplete { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The total size of the files compressed in the archive.
|
||||
/// </summary>
|
||||
long TotalSize { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The total size of the files as uncompressed in the archive.
|
||||
/// </summary>
|
||||
long TotalUncompressSize { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,40 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress.Archive
|
||||
{
|
||||
public static class IArchiveEntryExtensions
|
||||
{
|
||||
public static void WriteTo(this IArchiveEntry archiveEntry, Stream streamToWriteTo)
|
||||
{
|
||||
if (archiveEntry.Archive.Type == ArchiveType.Rar && archiveEntry.Archive.IsSolid)
|
||||
{
|
||||
throw new InvalidFormatException("Cannot use Archive random access on SOLID Rar files.");
|
||||
}
|
||||
|
||||
if (archiveEntry.IsDirectory)
|
||||
{
|
||||
throw new ExtractionException("Entry is a file directory and cannot be extracted.");
|
||||
}
|
||||
|
||||
var streamListener = archiveEntry.Archive as IArchiveExtractionListener;
|
||||
streamListener.EnsureEntriesLoaded();
|
||||
streamListener.FireEntryExtractionBegin(archiveEntry);
|
||||
streamListener.FireFilePartExtractionBegin(archiveEntry.Key, archiveEntry.Size, archiveEntry.CompressedSize);
|
||||
var entryStream = archiveEntry.OpenEntryStream();
|
||||
if (entryStream == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
using (entryStream)
|
||||
using (Stream s = new ListeningStream(streamListener, entryStream))
|
||||
{
|
||||
s.TransferTo(streamToWriteTo);
|
||||
}
|
||||
streamListener.FireEntryExtractionEnd(archiveEntry);
|
||||
}
|
||||
|
||||
#if !PORTABLE && !NETFX_CORE
|
||||
/// <summary>
|
||||
/// Extract to specific directory, retaining filename
|
||||
@@ -12,13 +42,13 @@ namespace SharpCompress.Archive
|
||||
public static void WriteToDirectory(this IArchiveEntry entry, string destinationDirectory,
|
||||
ExtractOptions options = ExtractOptions.Overwrite)
|
||||
{
|
||||
string destinationFileName = string.Empty;
|
||||
string file = Path.GetFileName(entry.FilePath);
|
||||
string destinationFileName;
|
||||
string file = Path.GetFileName(entry.Key);
|
||||
|
||||
|
||||
if (options.HasFlag(ExtractOptions.ExtractFullPath))
|
||||
{
|
||||
string folder = Path.GetDirectoryName(entry.FilePath);
|
||||
string folder = Path.GetDirectoryName(entry.Key);
|
||||
string destdir = Path.Combine(destinationDirectory, folder);
|
||||
if (!Directory.Exists(destdir))
|
||||
{
|
||||
@@ -30,7 +60,10 @@ namespace SharpCompress.Archive
|
||||
{
|
||||
destinationFileName = Path.Combine(destinationDirectory, file);
|
||||
}
|
||||
entry.WriteToFile(destinationFileName, options);
|
||||
if (!entry.IsDirectory)
|
||||
{
|
||||
entry.WriteToFile(destinationFileName, options);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -39,10 +72,6 @@ namespace SharpCompress.Archive
|
||||
public static void WriteToFile(this IArchiveEntry entry, string destinationFileName,
|
||||
ExtractOptions options = ExtractOptions.Overwrite)
|
||||
{
|
||||
if (entry.IsDirectory)
|
||||
{
|
||||
return;
|
||||
}
|
||||
FileMode fm = FileMode.Create;
|
||||
|
||||
if (!options.HasFlag(ExtractOptions.Overwrite))
|
||||
@@ -50,11 +79,11 @@ namespace SharpCompress.Archive
|
||||
fm = FileMode.CreateNew;
|
||||
}
|
||||
using (FileStream fs = File.Open(destinationFileName, fm))
|
||||
// using (Stream entryStream = entry.OpenEntryStream())
|
||||
{
|
||||
//entryStream.TransferTo(fs);
|
||||
entry.WriteTo(fs);
|
||||
}
|
||||
|
||||
entry.PreserveExtractionOptions(destinationFileName, options);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -11,11 +11,14 @@ namespace SharpCompress.Archive
|
||||
/// </summary>
|
||||
Stream OpenEntryStream();
|
||||
|
||||
void WriteTo(Stream stream);
|
||||
|
||||
/// <summary>
|
||||
/// The archive can find all the parts of the archive needed to extract this entry.
|
||||
/// </summary>
|
||||
bool IsComplete { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The archive instance this entry belongs to
|
||||
/// </summary>
|
||||
IArchive Archive { get; }
|
||||
}
|
||||
}
|
||||
11
SharpCompress/Archive/IArchiveExtractionListener.cs
Normal file
11
SharpCompress/Archive/IArchiveExtractionListener.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress.Archive
|
||||
{
|
||||
internal interface IArchiveExtractionListener : IExtractionListener
|
||||
{
|
||||
void EnsureEntriesLoaded();
|
||||
void FireEntryExtractionBegin(IArchiveEntry entry);
|
||||
void FireEntryExtractionEnd(IArchiveEntry entry);
|
||||
}
|
||||
}
|
||||
@@ -1,85 +1,84 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress.Archive
|
||||
{
|
||||
public static class AbstractWritableArchiveExtensions
|
||||
{
|
||||
public static void SaveTo<TEntry, TVolume>(this AbstractWritableArchive<TEntry, TVolume> writableArchive,
|
||||
Stream stream, CompressionType compressionType)
|
||||
where TEntry : IArchiveEntry
|
||||
where TVolume : IVolume
|
||||
{
|
||||
writableArchive.SaveTo(stream, new CompressionInfo {Type = compressionType});
|
||||
}
|
||||
|
||||
#if !PORTABLE && !NETFX_CORE
|
||||
|
||||
public static void AddEntry<TEntry, TVolume>(this AbstractWritableArchive<TEntry, TVolume> writableArchive,
|
||||
string entryPath, string filePath)
|
||||
where TEntry : IArchiveEntry
|
||||
where TVolume : IVolume
|
||||
{
|
||||
var fileInfo = new FileInfo(filePath);
|
||||
if (!fileInfo.Exists)
|
||||
{
|
||||
throw new FileNotFoundException("Could not AddEntry: " + filePath);
|
||||
}
|
||||
writableArchive.AddEntry(entryPath, new FileInfo(filePath).OpenRead(), true, fileInfo.Length,
|
||||
fileInfo.LastWriteTime);
|
||||
}
|
||||
|
||||
public static void SaveTo<TEntry, TVolume>(this AbstractWritableArchive<TEntry, TVolume> writableArchive,
|
||||
string filePath, CompressionType compressionType)
|
||||
where TEntry : IArchiveEntry
|
||||
where TVolume : IVolume
|
||||
{
|
||||
writableArchive.SaveTo(new FileInfo(filePath), new CompressionInfo {Type = compressionType});
|
||||
}
|
||||
|
||||
public static void SaveTo<TEntry, TVolume>(this AbstractWritableArchive<TEntry, TVolume> writableArchive,
|
||||
FileInfo fileInfo, CompressionType compressionType)
|
||||
where TEntry : IArchiveEntry
|
||||
where TVolume : IVolume
|
||||
{
|
||||
using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
writableArchive.SaveTo(stream, new CompressionInfo {Type = compressionType});
|
||||
}
|
||||
}
|
||||
|
||||
public static void SaveTo<TEntry, TVolume>(this AbstractWritableArchive<TEntry, TVolume> writableArchive,
|
||||
string filePath, CompressionInfo compressionInfo)
|
||||
where TEntry : IArchiveEntry
|
||||
where TVolume : IVolume
|
||||
{
|
||||
writableArchive.SaveTo(new FileInfo(filePath), compressionInfo);
|
||||
}
|
||||
|
||||
public static void SaveTo<TEntry, TVolume>(this AbstractWritableArchive<TEntry, TVolume> writableArchive,
|
||||
FileInfo fileInfo, CompressionInfo compressionInfo)
|
||||
where TEntry : IArchiveEntry
|
||||
where TVolume : IVolume
|
||||
{
|
||||
using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
writableArchive.SaveTo(stream, compressionInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddAllFromDirectory<TEntry, TVolume>(
|
||||
this AbstractWritableArchive<TEntry, TVolume> writableArchive,
|
||||
string filePath, string searchPattern = "*.*", SearchOption searchOption = SearchOption.AllDirectories)
|
||||
where TEntry : IArchiveEntry
|
||||
where TVolume : IVolume
|
||||
{
|
||||
foreach (var path in Directory.EnumerateFiles(filePath, searchPattern, searchOption))
|
||||
{
|
||||
var fileInfo = new FileInfo(path);
|
||||
writableArchive.AddEntry(path.Substring(filePath.Length), fileInfo.OpenRead(), true, fileInfo.Length,
|
||||
fileInfo.LastWriteTime);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
using System;
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress.Archive
|
||||
{
|
||||
public static class IWritableArchiveExtensions
|
||||
{
|
||||
public static void SaveTo(this IWritableArchive writableArchive,
|
||||
Stream stream, CompressionType compressionType)
|
||||
{
|
||||
writableArchive.SaveTo(stream, new CompressionInfo {Type = compressionType});
|
||||
}
|
||||
|
||||
#if !PORTABLE && !NETFX_CORE
|
||||
|
||||
public static void AddEntry(this IWritableArchive writableArchive,
|
||||
string entryPath, string filePath)
|
||||
{
|
||||
var fileInfo = new FileInfo(filePath);
|
||||
if (!fileInfo.Exists)
|
||||
{
|
||||
throw new FileNotFoundException("Could not AddEntry: " + filePath);
|
||||
}
|
||||
writableArchive.AddEntry(entryPath, new FileInfo(filePath).OpenRead(), true, fileInfo.Length,
|
||||
fileInfo.LastWriteTime);
|
||||
}
|
||||
|
||||
public static void SaveTo(this IWritableArchive writableArchive,
|
||||
string filePath, CompressionType compressionType)
|
||||
{
|
||||
writableArchive.SaveTo(new FileInfo(filePath), new CompressionInfo {Type = compressionType});
|
||||
}
|
||||
|
||||
public static void SaveTo(this IWritableArchive writableArchive,
|
||||
FileInfo fileInfo, CompressionType compressionType)
|
||||
{
|
||||
using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
writableArchive.SaveTo(stream, new CompressionInfo {Type = compressionType});
|
||||
}
|
||||
}
|
||||
|
||||
public static void SaveTo(this IWritableArchive writableArchive,
|
||||
string filePath, CompressionInfo compressionInfo)
|
||||
{
|
||||
writableArchive.SaveTo(new FileInfo(filePath), compressionInfo);
|
||||
}
|
||||
|
||||
public static void SaveTo(this IWritableArchive writableArchive,
|
||||
FileInfo fileInfo, CompressionInfo compressionInfo)
|
||||
{
|
||||
using (var stream = fileInfo.Open(FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
writableArchive.SaveTo(stream, compressionInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddAllFromDirectory(
|
||||
this IWritableArchive writableArchive,
|
||||
string filePath, string searchPattern = "*.*", SearchOption searchOption = SearchOption.AllDirectories)
|
||||
{
|
||||
#if NET35
|
||||
foreach (var path in Directory.GetFiles(filePath, searchPattern, searchOption))
|
||||
#else
|
||||
foreach (var path in Directory.EnumerateFiles(filePath, searchPattern, searchOption))
|
||||
#endif
|
||||
{
|
||||
var fileInfo = new FileInfo(path);
|
||||
writableArchive.AddEntry(path.Substring(filePath.Length), fileInfo.OpenRead(), true, fileInfo.Length,
|
||||
fileInfo.LastWriteTime);
|
||||
}
|
||||
}
|
||||
public static IArchiveEntry AddEntry(this IWritableArchive writableArchive, string key, FileInfo fileInfo)
|
||||
{
|
||||
if (!fileInfo.Exists)
|
||||
{
|
||||
throw new ArgumentException("FileInfo does not exist.");
|
||||
}
|
||||
return writableArchive.AddEntry(key, fileInfo.OpenRead(), true, fileInfo.Length, fileInfo.LastWriteTime);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
15
SharpCompress/Archive/IWritableArchive.cs
Normal file
15
SharpCompress/Archive/IWritableArchive.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
|
||||
namespace SharpCompress.Archive
|
||||
{
|
||||
public interface IWritableArchive : IArchive
|
||||
{
|
||||
void RemoveEntry(IArchiveEntry entry);
|
||||
|
||||
IArchiveEntry AddEntry(string key, Stream source, bool closeStream, long size = 0, DateTime? modified = null);
|
||||
|
||||
void SaveTo(Stream stream, CompressionInfo compressionType);
|
||||
}
|
||||
}
|
||||
9
SharpCompress/Archive/IWritableArchiveEntry.cs
Normal file
9
SharpCompress/Archive/IWritableArchiveEntry.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System.IO;
|
||||
|
||||
namespace SharpCompress.Archive
|
||||
{
|
||||
internal interface IWritableArchiveEntry
|
||||
{
|
||||
Stream Stream { get; }
|
||||
}
|
||||
}
|
||||
@@ -12,8 +12,8 @@ namespace SharpCompress.Archive.Rar
|
||||
/// </summary>
|
||||
internal class FileInfoRarArchiveVolume : RarVolume
|
||||
{
|
||||
internal FileInfoRarArchiveVolume(FileInfo fileInfo, Options options)
|
||||
: base(StreamingMode.Seekable, fileInfo.OpenRead(), FixOptions(options))
|
||||
internal FileInfoRarArchiveVolume(FileInfo fileInfo, string password, Options options)
|
||||
: base(StreamingMode.Seekable, fileInfo.OpenRead(), password, FixOptions(options))
|
||||
{
|
||||
FileInfo = fileInfo;
|
||||
FileParts = base.GetVolumeFileParts().ToReadOnly();
|
||||
@@ -42,10 +42,5 @@ namespace SharpCompress.Archive.Rar
|
||||
{
|
||||
return FileParts;
|
||||
}
|
||||
|
||||
public override FileInfo VolumeFile
|
||||
{
|
||||
get { return FileInfo; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,26 +4,16 @@ using SharpCompress.Common.Rar.Headers;
|
||||
|
||||
namespace SharpCompress.Archive.Rar
|
||||
{
|
||||
internal class FileInfoRarFilePart : RarFilePart
|
||||
internal class FileInfoRarFilePart : SeekableFilePart
|
||||
{
|
||||
private FileInfoRarArchiveVolume volume;
|
||||
|
||||
internal FileInfoRarFilePart(FileInfoRarArchiveVolume volume, MarkHeader mh, FileHeader fh, FileInfo fi)
|
||||
: base(mh, fh)
|
||||
: base(mh, fh, volume.Stream, volume.Password)
|
||||
{
|
||||
this.volume = volume;
|
||||
FileInfo = fi;
|
||||
}
|
||||
|
||||
internal FileInfo FileInfo { get; private set; }
|
||||
|
||||
internal override Stream GetCompressedStream()
|
||||
{
|
||||
var stream = volume.Stream;
|
||||
stream.Position = FileHeader.DataStartPosition;
|
||||
return stream;
|
||||
}
|
||||
|
||||
internal override string FilePartName
|
||||
{
|
||||
get
|
||||
|
||||
@@ -19,13 +19,5 @@ namespace SharpCompress.Archive.Rar
|
||||
{
|
||||
return archive.Volumes.First().IsMultiVolume;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RarArchive is SOLID (this means the Archive saved bytes by reusing information which helps for archives containing many small files).
|
||||
/// </summary>
|
||||
public static bool IsSolidArchive(this RarArchive archive)
|
||||
{
|
||||
return archive.IsSolid;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,14 +27,15 @@ namespace SharpCompress.Archive.Rar
|
||||
/// </summary>
|
||||
/// <param name="fileInfo"></param>
|
||||
/// <param name="options"></param>
|
||||
internal RarArchive(FileInfo fileInfo, Options options)
|
||||
: base(ArchiveType.Rar, fileInfo, options)
|
||||
/// <param name="password"></param>
|
||||
internal RarArchive(FileInfo fileInfo, Options options, string password)
|
||||
: base(ArchiveType.Rar, fileInfo, options, password)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IEnumerable<RarVolume> LoadVolumes(FileInfo file, Options options)
|
||||
{
|
||||
return RarArchiveVolumeFactory.GetParts(file, options);
|
||||
return RarArchiveVolumeFactory.GetParts(file, Password, options);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -43,8 +44,9 @@ namespace SharpCompress.Archive.Rar
|
||||
/// </summary>
|
||||
/// <param name="streams"></param>
|
||||
/// <param name="options"></param>
|
||||
internal RarArchive(IEnumerable<Stream> streams, Options options)
|
||||
: base(ArchiveType.Rar, streams, options)
|
||||
/// <param name="password"></param>
|
||||
internal RarArchive(IEnumerable<Stream> streams, Options options, string password)
|
||||
: base(ArchiveType.Rar, streams, options, password)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -55,14 +57,14 @@ namespace SharpCompress.Archive.Rar
|
||||
|
||||
protected override IEnumerable<RarVolume> LoadVolumes(IEnumerable<Stream> streams, Options options)
|
||||
{
|
||||
return RarArchiveVolumeFactory.GetParts(streams, options);
|
||||
return RarArchiveVolumeFactory.GetParts(streams, Password, options);
|
||||
}
|
||||
|
||||
protected override IReader CreateReaderForSolidExtraction()
|
||||
{
|
||||
var stream = Volumes.First().Stream;
|
||||
stream.Position = 0;
|
||||
return RarReader.Open(stream);
|
||||
return RarReader.Open(stream, Password);
|
||||
}
|
||||
|
||||
public override bool IsSolid
|
||||
@@ -73,33 +75,16 @@ namespace SharpCompress.Archive.Rar
|
||||
#region Creation
|
||||
|
||||
#if !PORTABLE && !NETFX_CORE
|
||||
/// <summary>
|
||||
/// Constructor expects a filepath to an existing file.
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
public static RarArchive Open(string filePath)
|
||||
{
|
||||
return Open(filePath, Options.None);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor with a FileInfo object to an existing file.
|
||||
/// </summary>
|
||||
/// <param name="fileInfo"></param>
|
||||
public static RarArchive Open(FileInfo fileInfo)
|
||||
{
|
||||
return Open(fileInfo, Options.None);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor expects a filepath to an existing file.
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <param name="options"></param>
|
||||
public static RarArchive Open(string filePath, Options options)
|
||||
/// <param name="password"></param>
|
||||
public static RarArchive Open(string filePath, Options options = Options.None, string password = null)
|
||||
{
|
||||
filePath.CheckNotNullOrEmpty("filePath");
|
||||
return Open(new FileInfo(filePath), options);
|
||||
return Open(new FileInfo(filePath), options, password);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -107,42 +92,23 @@ namespace SharpCompress.Archive.Rar
|
||||
/// </summary>
|
||||
/// <param name="fileInfo"></param>
|
||||
/// <param name="options"></param>
|
||||
public static RarArchive Open(FileInfo fileInfo, Options options)
|
||||
/// <param name="password"></param>
|
||||
public static RarArchive Open(FileInfo fileInfo, Options options = Options.None, string password = null)
|
||||
{
|
||||
fileInfo.CheckNotNull("fileInfo");
|
||||
return new RarArchive(fileInfo, options);
|
||||
return new RarArchive(fileInfo, options, password);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Takes a seekable Stream as a source
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
public static RarArchive Open(Stream stream)
|
||||
{
|
||||
stream.CheckNotNull("stream");
|
||||
return Open(stream.AsEnumerable());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Takes a seekable Stream as a source
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="options"></param>
|
||||
public static RarArchive Open(Stream stream, Options options)
|
||||
/// <param name="password"></param>
|
||||
public static RarArchive Open(Stream stream, Options options = Options.KeepStreamsOpen, string password = null)
|
||||
{
|
||||
stream.CheckNotNull("stream");
|
||||
return Open(stream.AsEnumerable(), options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Takes multiple seekable Streams for a multi-part archive
|
||||
/// </summary>
|
||||
/// <param name="streams"></param>
|
||||
public static RarArchive Open(IEnumerable<Stream> streams)
|
||||
{
|
||||
streams.CheckNotNull("streams");
|
||||
return new RarArchive(streams, Options.KeepStreamsOpen);
|
||||
return Open(stream.AsEnumerable(), options, password);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -150,10 +116,11 @@ namespace SharpCompress.Archive.Rar
|
||||
/// </summary>
|
||||
/// <param name="streams"></param>
|
||||
/// <param name="options"></param>
|
||||
public static RarArchive Open(IEnumerable<Stream> streams, Options options)
|
||||
/// <param name="password"></param>
|
||||
public static RarArchive Open(IEnumerable<Stream> streams, Options options = Options.KeepStreamsOpen, string password = null)
|
||||
{
|
||||
streams.CheckNotNull("streams");
|
||||
return new RarArchive(streams, options);
|
||||
return new RarArchive(streams, options, password);
|
||||
}
|
||||
|
||||
#if !PORTABLE && !NETFX_CORE
|
||||
@@ -185,12 +152,8 @@ namespace SharpCompress.Archive.Rar
|
||||
try
|
||||
{
|
||||
var headerFactory = new RarHeaderFactory(StreamingMode.Seekable, options);
|
||||
RarHeader header = headerFactory.ReadHeaders(stream).FirstOrDefault();
|
||||
if (header == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return Enum.IsDefined(typeof (HeaderType), header.HeaderType);
|
||||
var markHeader = headerFactory.ReadHeaders(stream).FirstOrDefault() as MarkHeader;
|
||||
return markHeader != null && markHeader.IsValid();
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -11,11 +12,12 @@ namespace SharpCompress.Archive.Rar
|
||||
public class RarArchiveEntry : RarEntry, IArchiveEntry
|
||||
{
|
||||
private readonly ICollection<RarFilePart> parts;
|
||||
private readonly RarArchive archive;
|
||||
|
||||
internal RarArchiveEntry(RarArchive archive, IEnumerable<RarFilePart> parts)
|
||||
{
|
||||
this.parts = parts.ToList();
|
||||
Archive = archive;
|
||||
this.archive = archive;
|
||||
}
|
||||
|
||||
public override CompressionType CompressionType
|
||||
@@ -23,7 +25,13 @@ namespace SharpCompress.Archive.Rar
|
||||
get { return CompressionType.Rar; }
|
||||
}
|
||||
|
||||
private RarArchive Archive { get; set; }
|
||||
public IArchive Archive
|
||||
{
|
||||
get
|
||||
{
|
||||
return archive;
|
||||
}
|
||||
}
|
||||
|
||||
internal override IEnumerable<FilePart> Parts
|
||||
{
|
||||
@@ -35,14 +43,13 @@ namespace SharpCompress.Archive.Rar
|
||||
get { return parts.First().FileHeader; }
|
||||
}
|
||||
|
||||
public override uint Crc
|
||||
public override long Crc
|
||||
{
|
||||
get
|
||||
{
|
||||
CheckIncomplete();
|
||||
return parts.Select(fp => fp.FileHeader)
|
||||
.Where(fh => !fh.FileFlags.HasFlag(FileFlags.SPLIT_AFTER))
|
||||
.Single().FileCRC;
|
||||
.Single(fh => !fh.FileFlags.HasFlag(FileFlags.SPLIT_AFTER)).FileCRC;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,22 +74,11 @@ namespace SharpCompress.Archive.Rar
|
||||
|
||||
public Stream OpenEntryStream()
|
||||
{
|
||||
return new RarStream(Archive.Unpack, FileHeader,
|
||||
new MultiVolumeReadOnlyStream(Parts.Cast<RarFilePart>(), Archive));
|
||||
}
|
||||
|
||||
public void WriteTo(Stream streamToWriteTo)
|
||||
{
|
||||
CheckIncomplete();
|
||||
if (Archive.IsSolidArchive())
|
||||
if (archive.IsSolid)
|
||||
{
|
||||
throw new InvalidFormatException("Cannot use Archive random access on SOLID Rar files.");
|
||||
throw new InvalidOperationException("Use ExtractAllEntries to extract SOLID archives.");
|
||||
}
|
||||
if (IsEncrypted)
|
||||
{
|
||||
throw new PasswordProtectedException("Entry is password protected and cannot be extracted.");
|
||||
}
|
||||
this.Extract(Archive, streamToWriteTo);
|
||||
return new RarStream(archive.Unpack, FileHeader, new MultiVolumeReadOnlyStream(Parts.Cast<RarFilePart>(), archive));
|
||||
}
|
||||
|
||||
public bool IsComplete
|
||||
@@ -97,9 +93,5 @@ namespace SharpCompress.Archive.Rar
|
||||
throw new IncompleteArchiveException("ArchiveEntry is incomplete and cannot perform this operation.");
|
||||
}
|
||||
}
|
||||
|
||||
internal override void Close()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ namespace SharpCompress.Archive.Rar
|
||||
{
|
||||
internal static class RarArchiveVolumeFactory
|
||||
{
|
||||
internal static IEnumerable<RarVolume> GetParts(IEnumerable<Stream> streams, Options options)
|
||||
internal static IEnumerable<RarVolume> GetParts(IEnumerable<Stream> streams, string password, Options options)
|
||||
{
|
||||
foreach (Stream s in streams)
|
||||
{
|
||||
@@ -21,15 +21,15 @@ namespace SharpCompress.Archive.Rar
|
||||
{
|
||||
throw new ArgumentException("Stream is not readable and seekable");
|
||||
}
|
||||
StreamRarArchiveVolume part = new StreamRarArchiveVolume(s, options);
|
||||
StreamRarArchiveVolume part = new StreamRarArchiveVolume(s, password, options);
|
||||
yield return part;
|
||||
}
|
||||
}
|
||||
|
||||
#if !PORTABLE && !NETFX_CORE
|
||||
internal static IEnumerable<RarVolume> GetParts(FileInfo fileInfo, Options options)
|
||||
internal static IEnumerable<RarVolume> GetParts(FileInfo fileInfo, string password, Options options)
|
||||
{
|
||||
FileInfoRarArchiveVolume part = new FileInfoRarArchiveVolume(fileInfo, options);
|
||||
FileInfoRarArchiveVolume part = new FileInfoRarArchiveVolume(fileInfo, password, options);
|
||||
yield return part;
|
||||
|
||||
if (!part.ArchiveHeader.ArchiveHeaderFlags.HasFlag(ArchiveFlags.VOLUME))
|
||||
@@ -41,7 +41,7 @@ namespace SharpCompress.Archive.Rar
|
||||
//we use fileinfo because rar is dumb and looks at file names rather than archive info for another volume
|
||||
while (fileInfo != null && fileInfo.Exists)
|
||||
{
|
||||
part = new FileInfoRarArchiveVolume(fileInfo, options);
|
||||
part = new FileInfoRarArchiveVolume(fileInfo, password, options);
|
||||
|
||||
fileInfo = GetNextFileInfo(ah, part.FileParts.FirstOrDefault() as FileInfoRarFilePart);
|
||||
yield return part;
|
||||
|
||||
39
SharpCompress/Archive/Rar/SeekableFilePart.cs
Normal file
39
SharpCompress/Archive/Rar/SeekableFilePart.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using SharpCompress.Common.Rar;
|
||||
using SharpCompress.Common.Rar.Headers;
|
||||
|
||||
namespace SharpCompress.Archive.Rar
|
||||
{
|
||||
internal class SeekableFilePart : RarFilePart
|
||||
{
|
||||
private readonly Stream stream;
|
||||
private readonly string password;
|
||||
|
||||
internal SeekableFilePart(MarkHeader mh, FileHeader fh, Stream stream, string password)
|
||||
: base(mh, fh)
|
||||
{
|
||||
this.stream = stream;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
internal override Stream GetCompressedStream()
|
||||
{
|
||||
stream.Position = FileHeader.DataStartPosition;
|
||||
if (FileHeader.Salt != null)
|
||||
{
|
||||
#if PORTABLE
|
||||
throw new NotSupportedException("Encrypted Rar files aren't supported in portable distro.");
|
||||
#else
|
||||
return new RarCryptoWrapper(stream, password, FileHeader.Salt);
|
||||
#endif
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
internal override string FilePartName
|
||||
{
|
||||
get { return "Unknown Stream - File Entry: " + FileHeader.FileName; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Common.Rar;
|
||||
using SharpCompress.Common.Rar.Headers;
|
||||
|
||||
namespace SharpCompress.Archive.Rar
|
||||
{
|
||||
internal class SeekableStreamFilePart : RarFilePart
|
||||
{
|
||||
internal SeekableStreamFilePart(MarkHeader mh, FileHeader fh, Stream stream)
|
||||
: base(mh, fh)
|
||||
{
|
||||
Stream = stream;
|
||||
}
|
||||
|
||||
internal Stream Stream { get; private set; }
|
||||
|
||||
internal override Stream GetCompressedStream()
|
||||
{
|
||||
Stream.Position = FileHeader.DataStartPosition;
|
||||
return Stream;
|
||||
}
|
||||
|
||||
internal override string FilePartName
|
||||
{
|
||||
get { return "Unknown Stream - File Entry: " + base.FileHeader.FileName; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,18 +9,11 @@ namespace SharpCompress.Archive.Rar
|
||||
{
|
||||
internal class StreamRarArchiveVolume : RarVolume
|
||||
{
|
||||
internal StreamRarArchiveVolume(Stream stream, Options options)
|
||||
: base(StreamingMode.Seekable, stream, options)
|
||||
internal StreamRarArchiveVolume(Stream stream, string password, Options options)
|
||||
: base(StreamingMode.Seekable, stream, password, options)
|
||||
{
|
||||
}
|
||||
|
||||
#if !PORTABLE && !NETFX_CORE
|
||||
public override FileInfo VolumeFile
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
#endif
|
||||
|
||||
internal override IEnumerable<RarFilePart> ReadFileParts()
|
||||
{
|
||||
return GetVolumeFileParts();
|
||||
@@ -28,7 +21,7 @@ namespace SharpCompress.Archive.Rar
|
||||
|
||||
internal override RarFilePart CreateFilePart(FileHeader fileHeader, MarkHeader markHeader)
|
||||
{
|
||||
return new SeekableStreamFilePart(markHeader, fileHeader, Stream);
|
||||
return new SeekableFilePart(markHeader, fileHeader, Stream, Password);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,13 +77,17 @@ namespace SharpCompress.Archive.SevenZip
|
||||
|
||||
#if !PORTABLE && !NETFX_CORE
|
||||
internal SevenZipArchive(FileInfo fileInfo, Options options)
|
||||
: base(ArchiveType.SevenZip, fileInfo, options)
|
||||
: base(ArchiveType.SevenZip, fileInfo, options, null)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IEnumerable<SevenZipVolume> LoadVolumes(FileInfo file, Options options)
|
||||
{
|
||||
return new SevenZipVolume(file, options).AsEnumerable();
|
||||
if (FlagUtility.HasFlag(options, Options.KeepStreamsOpen))
|
||||
{
|
||||
options = (Options)FlagUtility.SetFlag(options, Options.KeepStreamsOpen, false);
|
||||
}
|
||||
return new SevenZipVolume(file.OpenRead(), options).AsEnumerable();
|
||||
}
|
||||
|
||||
public static bool IsSevenZipFile(string filePath)
|
||||
@@ -105,7 +109,7 @@ namespace SharpCompress.Archive.SevenZip
|
||||
#endif
|
||||
|
||||
internal SevenZipArchive(Stream stream, Options options)
|
||||
: base(ArchiveType.SevenZip, stream.AsEnumerable(), options)
|
||||
: base(ArchiveType.SevenZip, stream.AsEnumerable(), options, null)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -184,6 +188,15 @@ namespace SharpCompress.Archive.SevenZip
|
||||
get { return Entries.Where(x => !x.IsDirectory).GroupBy(x => x.FilePart.Folder).Count() > 1; }
|
||||
}
|
||||
|
||||
public override long TotalSize
|
||||
{
|
||||
get
|
||||
{
|
||||
int i = Entries.Count;
|
||||
return database.PackSizes.Aggregate(0L, (total, packSize) => total + packSize);
|
||||
}
|
||||
}
|
||||
|
||||
private class SevenZipReader : AbstractReader<SevenZipEntry, SevenZipVolume>
|
||||
{
|
||||
private readonly SevenZipArchive archive;
|
||||
@@ -232,7 +245,7 @@ namespace SharpCompress.Archive.SevenZip
|
||||
|
||||
protected override EntryStream GetEntryStream()
|
||||
{
|
||||
return new EntryStream(new ReadOnlySubStream(currentStream, currentItem.Size));
|
||||
return CreateEntryStream(new ReadOnlySubStream(currentStream, currentItem.Size));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +1,22 @@
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using System;
|
||||
using System.IO;
|
||||
using SharpCompress.Common.SevenZip;
|
||||
|
||||
namespace SharpCompress.Archive.SevenZip
|
||||
{
|
||||
public class SevenZipArchiveEntry : SevenZipEntry, IArchiveEntry
|
||||
{
|
||||
private SevenZipArchive archive;
|
||||
|
||||
internal SevenZipArchiveEntry(SevenZipArchive archive, SevenZipFilePart part)
|
||||
: base(part)
|
||||
{
|
||||
this.archive = archive;
|
||||
Archive = archive;
|
||||
}
|
||||
|
||||
public Stream OpenEntryStream()
|
||||
{
|
||||
return FilePart.GetCompressedStream();
|
||||
}
|
||||
|
||||
public void WriteTo(Stream stream)
|
||||
{
|
||||
if (IsEncrypted)
|
||||
{
|
||||
throw new PasswordProtectedException("Entry is password protected and cannot be extracted.");
|
||||
}
|
||||
this.Extract(archive, stream);
|
||||
}
|
||||
public IArchive Archive { get; private set; }
|
||||
|
||||
public bool IsComplete
|
||||
{
|
||||
|
||||
@@ -123,7 +123,11 @@ namespace SharpCompress.Archive.Tar
|
||||
|
||||
protected override IEnumerable<TarVolume> LoadVolumes(FileInfo file, Options options)
|
||||
{
|
||||
return new TarVolume(file, options).AsEnumerable();
|
||||
if (FlagUtility.HasFlag(options, Options.KeepStreamsOpen))
|
||||
{
|
||||
options = (Options)FlagUtility.SetFlag(options, Options.KeepStreamsOpen, false);
|
||||
}
|
||||
return new TarVolume(file.OpenRead(), options).AsEnumerable();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -133,7 +137,7 @@ namespace SharpCompress.Archive.Tar
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="options"></param>
|
||||
internal TarArchive(Stream stream, Options options)
|
||||
: base(ArchiveType.Tar, stream.AsEnumerable(), options)
|
||||
: base(ArchiveType.Tar, stream, options)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -165,11 +169,21 @@ namespace SharpCompress.Archive.Tar
|
||||
{
|
||||
var entry = new TarArchiveEntry(this, new TarFilePart(previousHeader, stream),
|
||||
CompressionType.None);
|
||||
var memoryStream = new MemoryStream();
|
||||
entry.WriteTo(memoryStream);
|
||||
memoryStream.Position = 0;
|
||||
var bytes = memoryStream.ToArray();
|
||||
header.Name = ArchiveEncoding.Default.GetString(bytes, 0, bytes.Length).TrimNulls();
|
||||
|
||||
var oldStreamPos = stream.Position;
|
||||
|
||||
using(var entryStream = entry.OpenEntryStream())
|
||||
using(var memoryStream = new MemoryStream())
|
||||
{
|
||||
entryStream.TransferTo(memoryStream);
|
||||
memoryStream.Position = 0;
|
||||
var bytes = memoryStream.ToArray();
|
||||
|
||||
header.Name = ArchiveEncoding.Default.GetString(bytes, 0, bytes.Length).TrimNulls();
|
||||
}
|
||||
|
||||
stream.Position = oldStreamPos;
|
||||
|
||||
previousHeader = null;
|
||||
}
|
||||
yield return new TarArchiveEntry(this, new TarFilePart(header, stream), CompressionType.None);
|
||||
@@ -183,7 +197,7 @@ namespace SharpCompress.Archive.Tar
|
||||
return new TarArchive();
|
||||
}
|
||||
|
||||
protected override TarArchiveEntry CreateEntry(string filePath, Stream source,
|
||||
protected override TarArchiveEntry CreateEntryInternal(string filePath, Stream source,
|
||||
long size, DateTime? modified, bool closeStream)
|
||||
{
|
||||
return new TarWritableArchiveEntry(this, source, CompressionType.Unknown, filePath, size, modified,
|
||||
@@ -201,7 +215,7 @@ namespace SharpCompress.Archive.Tar
|
||||
{
|
||||
using (var entryStream = entry.OpenEntryStream())
|
||||
{
|
||||
writer.Write(entry.FilePath, entryStream, entry.LastModifiedTime, entry.Size);
|
||||
writer.Write(entry.Key, entryStream, entry.LastModifiedTime, entry.Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,12 +7,10 @@ namespace SharpCompress.Archive.Tar
|
||||
{
|
||||
public class TarArchiveEntry : TarEntry, IArchiveEntry
|
||||
{
|
||||
private TarArchive archive;
|
||||
|
||||
internal TarArchiveEntry(TarArchive archive, TarFilePart part, CompressionType compressionType)
|
||||
: base(part, compressionType)
|
||||
{
|
||||
this.archive = archive;
|
||||
Archive = archive;
|
||||
}
|
||||
|
||||
public virtual Stream OpenEntryStream()
|
||||
@@ -21,15 +19,7 @@ namespace SharpCompress.Archive.Tar
|
||||
}
|
||||
|
||||
#region IArchiveEntry Members
|
||||
|
||||
public void WriteTo(Stream streamToWriteTo)
|
||||
{
|
||||
if (IsEncrypted)
|
||||
{
|
||||
throw new PasswordProtectedException("Entry is password protected and cannot be extracted.");
|
||||
}
|
||||
this.Extract(archive, streamToWriteTo);
|
||||
}
|
||||
public IArchive Archive { get; private set; }
|
||||
|
||||
public bool IsComplete
|
||||
{
|
||||
|
||||
@@ -6,30 +6,31 @@ using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress.Archive.Tar
|
||||
{
|
||||
internal class TarWritableArchiveEntry : TarArchiveEntry
|
||||
internal class TarWritableArchiveEntry : TarArchiveEntry, IWritableArchiveEntry
|
||||
{
|
||||
private string path;
|
||||
private long size;
|
||||
private DateTime? lastModified;
|
||||
private bool closeStream;
|
||||
private readonly string path;
|
||||
private readonly long size;
|
||||
private readonly DateTime? lastModified;
|
||||
private readonly bool closeStream;
|
||||
private readonly Stream stream;
|
||||
|
||||
internal TarWritableArchiveEntry(TarArchive archive, Stream stream, CompressionType compressionType,
|
||||
string path, long size, DateTime? lastModified, bool closeStream)
|
||||
: base(archive, null, compressionType)
|
||||
{
|
||||
this.Stream = stream;
|
||||
this.stream = stream;
|
||||
this.path = path;
|
||||
this.size = size;
|
||||
this.lastModified = lastModified;
|
||||
this.closeStream = closeStream;
|
||||
}
|
||||
|
||||
public override uint Crc
|
||||
public override long Crc
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public override string FilePath
|
||||
public override string Key
|
||||
{
|
||||
get { return path; }
|
||||
}
|
||||
@@ -83,19 +84,26 @@ namespace SharpCompress.Archive.Tar
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
internal Stream Stream { get; private set; }
|
||||
Stream IWritableArchiveEntry.Stream
|
||||
{
|
||||
get
|
||||
{
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
|
||||
public override Stream OpenEntryStream()
|
||||
{
|
||||
return new NonDisposingStream(Stream);
|
||||
//ensure new stream is at the start, this could be reset
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
return new NonDisposingStream(stream);
|
||||
}
|
||||
|
||||
internal override void Close()
|
||||
{
|
||||
if (closeStream)
|
||||
{
|
||||
Stream.Dispose();
|
||||
stream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace SharpCompress.Archive.Zip
|
||||
{
|
||||
public class ZipArchive : AbstractWritableArchive<ZipArchiveEntry, ZipVolume>
|
||||
{
|
||||
private SeekableZipHeaderFactory headerFactory;
|
||||
private readonly SeekableZipHeaderFactory headerFactory;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the compression level applied to files added to the archive,
|
||||
@@ -148,7 +148,11 @@ namespace SharpCompress.Archive.Zip
|
||||
|
||||
protected override IEnumerable<ZipVolume> LoadVolumes(FileInfo file, Options options)
|
||||
{
|
||||
return new ZipVolume(file, options).AsEnumerable();
|
||||
if (FlagUtility.HasFlag(options, Options.KeepStreamsOpen))
|
||||
{
|
||||
options = (Options)FlagUtility.SetFlag(options, Options.KeepStreamsOpen, false);
|
||||
}
|
||||
return new ZipVolume(file.OpenRead(), options).AsEnumerable();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -164,7 +168,7 @@ namespace SharpCompress.Archive.Zip
|
||||
/// <param name="options"></param>
|
||||
/// <param name="password"></param>
|
||||
internal ZipArchive(Stream stream, Options options, string password = null)
|
||||
: base(ArchiveType.Zip, stream.AsEnumerable(), options)
|
||||
: base(ArchiveType.Zip, stream, options)
|
||||
{
|
||||
headerFactory = new SeekableZipHeaderFactory(password);
|
||||
}
|
||||
@@ -177,7 +181,7 @@ namespace SharpCompress.Archive.Zip
|
||||
protected override IEnumerable<ZipArchiveEntry> LoadEntries(IEnumerable<ZipVolume> volumes)
|
||||
{
|
||||
var volume = volumes.Single();
|
||||
Stream stream = volumes.Single().Stream;
|
||||
Stream stream = volume.Stream;
|
||||
foreach (ZipHeader h in headerFactory.ReadSeekableHeader(stream))
|
||||
{
|
||||
if (h != null)
|
||||
@@ -214,13 +218,13 @@ namespace SharpCompress.Archive.Zip
|
||||
{
|
||||
using (var entryStream = entry.OpenEntryStream())
|
||||
{
|
||||
writer.Write(entry.FilePath, entryStream, entry.LastModifiedTime, string.Empty);
|
||||
writer.Write(entry.Key, entryStream, entry.LastModifiedTime, string.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override ZipArchiveEntry CreateEntry(string filePath, Stream source, long size, DateTime? modified,
|
||||
protected override ZipArchiveEntry CreateEntryInternal(string filePath, Stream source, long size, DateTime? modified,
|
||||
bool closeStream)
|
||||
{
|
||||
return new ZipWritableArchiveEntry(this, source, filePath, size, modified, closeStream);
|
||||
|
||||
@@ -6,12 +6,10 @@ namespace SharpCompress.Archive.Zip
|
||||
{
|
||||
public class ZipArchiveEntry : ZipEntry, IArchiveEntry
|
||||
{
|
||||
private ZipArchive archive;
|
||||
|
||||
internal ZipArchiveEntry(ZipArchive archive, SeekableZipFilePart part)
|
||||
: base(part)
|
||||
{
|
||||
this.archive = archive;
|
||||
Archive = archive;
|
||||
}
|
||||
|
||||
public virtual Stream OpenEntryStream()
|
||||
@@ -21,10 +19,7 @@ namespace SharpCompress.Archive.Zip
|
||||
|
||||
#region IArchiveEntry Members
|
||||
|
||||
public void WriteTo(Stream streamToWriteTo)
|
||||
{
|
||||
this.Extract(archive, streamToWriteTo);
|
||||
}
|
||||
public IArchive Archive { get; private set; }
|
||||
|
||||
public bool IsComplete
|
||||
{
|
||||
|
||||
@@ -6,30 +6,32 @@ using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress.Archive.Zip
|
||||
{
|
||||
internal class ZipWritableArchiveEntry : ZipArchiveEntry
|
||||
internal class ZipWritableArchiveEntry : ZipArchiveEntry, IWritableArchiveEntry
|
||||
{
|
||||
private string path;
|
||||
private long size;
|
||||
private DateTime? lastModified;
|
||||
private bool closeStream;
|
||||
private readonly string path;
|
||||
private readonly long size;
|
||||
private readonly DateTime? lastModified;
|
||||
private readonly bool closeStream;
|
||||
private readonly Stream stream;
|
||||
private bool isDisposed;
|
||||
|
||||
internal ZipWritableArchiveEntry(ZipArchive archive, Stream stream, string path, long size,
|
||||
DateTime? lastModified, bool closeStream)
|
||||
: base(archive, null)
|
||||
{
|
||||
this.Stream = stream;
|
||||
this.stream = stream;
|
||||
this.path = path;
|
||||
this.size = size;
|
||||
this.lastModified = lastModified;
|
||||
this.closeStream = closeStream;
|
||||
}
|
||||
|
||||
public override uint Crc
|
||||
public override long Crc
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public override string FilePath
|
||||
public override string Key
|
||||
{
|
||||
get { return path; }
|
||||
}
|
||||
@@ -84,18 +86,27 @@ namespace SharpCompress.Archive.Zip
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
internal Stream Stream { get; private set; }
|
||||
Stream IWritableArchiveEntry.Stream
|
||||
{
|
||||
get
|
||||
{
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
|
||||
public override Stream OpenEntryStream()
|
||||
{
|
||||
return new NonDisposingStream(Stream);
|
||||
//ensure new stream is at the start, this could be reset
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
return new NonDisposingStream(stream);
|
||||
}
|
||||
|
||||
internal override void Close()
|
||||
{
|
||||
if (closeStream)
|
||||
if (closeStream && !isDisposed)
|
||||
{
|
||||
Stream.Dispose();
|
||||
stream.Dispose();
|
||||
isDisposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System.Reflection;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
|
||||
#if PORTABLE
|
||||
[assembly: AssemblyTitle("SharpCompress.Portable")]
|
||||
[assembly: AssemblyProduct("SharpCompress.Portable")]
|
||||
@@ -8,12 +10,11 @@ using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: AssemblyTitle("SharpCompress")]
|
||||
[assembly: AssemblyProduct("SharpCompress")]
|
||||
[assembly:
|
||||
InternalsVisibleTo(
|
||||
"SharpCompress.Test, PublicKey=002400000480000094000000060200000024000052534131000400000100010005d6ae1b0f6875393da83c920a5b9408f5191aaf4e8b3c2c476ad2a11f5041ecae84ce9298bc4c203637e2fd3a80ad5378a9fa8da1363e98cea45c73969198a4b64510927c910001491cebbadf597b22448ad103b0a4007e339faf8fe8665dcdb70d65b27ac05b1977c0655fad06b372b820ecbdccf10a0f214fee0986dfeded"
|
||||
)]
|
||||
[assembly:
|
||||
InternalsVisibleTo(
|
||||
"SharpCompress.Test.Portable, PublicKey=002400000480000094000000060200000024000052534131000400000100010005d6ae1b0f6875393da83c920a5b9408f5191aaf4e8b3c2c476ad2a11f5041ecae84ce9298bc4c203637e2fd3a80ad5378a9fa8da1363e98cea45c73969198a4b64510927c910001491cebbadf597b22448ad103b0a4007e339faf8fe8665dcdb70d65b27ac05b1977c0655fad06b372b820ecbdccf10a0f214fee0986dfeded"
|
||||
)]
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if UNSIGNED
|
||||
[assembly: InternalsVisibleTo("SharpCompress.Test")]
|
||||
[assembly: InternalsVisibleTo("SharpCompress.Test.Portable")]
|
||||
#endif
|
||||
|
||||
[assembly: CLSCompliant(true)]
|
||||
|
||||
@@ -1,29 +1,23 @@
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpCompress.Common
|
||||
{
|
||||
public class ArchiveEncoding
|
||||
public static class ArchiveEncoding
|
||||
{
|
||||
/// <summary>
|
||||
/// Default encoding to use when archive format doesn't specify one.
|
||||
/// </summary>
|
||||
public static Encoding Default;
|
||||
public static Encoding Default { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Encoding used by encryption schemes which don't comply with RFC 2898.
|
||||
/// </summary>
|
||||
public static Encoding Password;
|
||||
public static Encoding Password { get; set; }
|
||||
|
||||
static ArchiveEncoding()
|
||||
{
|
||||
#if PORTABLE || NETFX_CORE
|
||||
Default = Encoding.UTF8;
|
||||
Password = Encoding.UTF8;
|
||||
#else
|
||||
Default = Encoding.GetEncoding(CultureInfo.CurrentCulture.TextInfo.OEMCodePage);
|
||||
Password = Encoding.Default;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,19 +3,17 @@ using System.Collections.Generic;
|
||||
|
||||
namespace SharpCompress.Common
|
||||
{
|
||||
public abstract class Entry : SharpCompress.Common.IEntry
|
||||
public abstract class Entry : IEntry
|
||||
{
|
||||
internal bool IsSolid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The File's 32 bit CRC Hash
|
||||
/// </summary>
|
||||
public abstract uint Crc { get; }
|
||||
public abstract long Crc { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The path of the file internal to the Rar Archive.
|
||||
/// The string key of the file internal to the Archive.
|
||||
/// </summary>
|
||||
public abstract string FilePath { get; }
|
||||
public abstract string Key { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The compressed file size
|
||||
@@ -48,7 +46,7 @@ namespace SharpCompress.Common
|
||||
public abstract DateTime? LastAccessedTime { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The entry time whend archived, if recorded
|
||||
/// The entry time when archived, if recorded
|
||||
/// </summary>
|
||||
public abstract DateTime? ArchivedTime { get; }
|
||||
|
||||
@@ -62,10 +60,26 @@ namespace SharpCompress.Common
|
||||
/// </summary>
|
||||
public abstract bool IsDirectory { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Entry is split among multiple volumes
|
||||
/// </summary>
|
||||
public abstract bool IsSplit { get; }
|
||||
|
||||
internal abstract IEnumerable<FilePart> Parts { get; }
|
||||
internal bool IsSolid { get; set; }
|
||||
|
||||
internal virtual void Close()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Entry file attribute.
|
||||
/// </summary>
|
||||
public virtual int? Attrib
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
internal abstract void Close();
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,19 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using SharpCompress.Reader;
|
||||
|
||||
namespace SharpCompress.Common
|
||||
{
|
||||
public class EntryStream : Stream
|
||||
{
|
||||
public IReader Reader { get; private set; }
|
||||
private Stream stream;
|
||||
private bool completed;
|
||||
private bool isDisposed;
|
||||
|
||||
internal EntryStream(Stream stream)
|
||||
internal EntryStream(IReader reader, Stream stream)
|
||||
{
|
||||
this.Reader = reader;
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
@@ -28,10 +31,9 @@ namespace SharpCompress.Common
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (!completed)
|
||||
if (!(completed || Reader.Cancelled))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"EntryStream has not been fully consumed. Read the entire stream or use SkipEntry.");
|
||||
SkipEntry();
|
||||
}
|
||||
if (isDisposed)
|
||||
{
|
||||
@@ -59,18 +61,18 @@ namespace SharpCompress.Common
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get { throw new System.NotImplementedException(); }
|
||||
get { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get { throw new System.NotImplementedException(); }
|
||||
set { throw new System.NotImplementedException(); }
|
||||
get { throw new NotSupportedException(); }
|
||||
set { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
@@ -85,17 +87,17 @@ namespace SharpCompress.Common
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,16 +5,26 @@ namespace SharpCompress.Common
|
||||
[Flags]
|
||||
public enum ExtractOptions
|
||||
{
|
||||
None,
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// overwrite target if it exists
|
||||
/// </summary>
|
||||
Overwrite,
|
||||
Overwrite = 1 << 0,
|
||||
|
||||
/// <summary>
|
||||
/// extract with internal directory structure
|
||||
/// </summary>
|
||||
ExtractFullPath,
|
||||
ExtractFullPath = 1 << 1,
|
||||
|
||||
/// <summary>
|
||||
/// preserve file time
|
||||
/// </summary>
|
||||
PreserveFileTime = 1 << 2,
|
||||
|
||||
/// <summary>
|
||||
/// preserve windows file attributes
|
||||
/// </summary>
|
||||
PreserveAttributes = 1 << 3,
|
||||
}
|
||||
}
|
||||
@@ -18,12 +18,12 @@ namespace SharpCompress.Common.GZip
|
||||
get { return CompressionType.GZip; }
|
||||
}
|
||||
|
||||
public override uint Crc
|
||||
public override long Crc
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public override string FilePath
|
||||
public override string Key
|
||||
{
|
||||
get { return filePart.FilePartName; }
|
||||
}
|
||||
@@ -82,9 +82,5 @@ namespace SharpCompress.Common.GZip
|
||||
{
|
||||
yield return new GZipEntry(new GZipFilePart(stream));
|
||||
}
|
||||
|
||||
internal override void Close()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using System.IO;
|
||||
using SharpCompress.Common.Tar.Headers;
|
||||
using SharpCompress.Compressor;
|
||||
using SharpCompress.Compressor.Deflate;
|
||||
using SharpCompress.Converter;
|
||||
|
||||
namespace SharpCompress.Common.GZip
|
||||
{
|
||||
@@ -50,7 +51,7 @@ namespace SharpCompress.Common.GZip
|
||||
if (header[0] != 0x1F || header[1] != 0x8B || header[2] != 8)
|
||||
throw new ZlibException("Bad GZIP header.");
|
||||
|
||||
Int32 timet = BitConverter.ToInt32(header, 4);
|
||||
Int32 timet = DataConverter.LittleEndian.GetInt32(header, 4);
|
||||
DateModified = TarHeader.Epoch.AddSeconds(timet);
|
||||
if ((header[3] & 0x04) == 0x04)
|
||||
{
|
||||
|
||||
@@ -4,10 +4,6 @@ namespace SharpCompress.Common.GZip
|
||||
{
|
||||
public class GZipVolume : Volume
|
||||
{
|
||||
#if !PORTABLE && !NETFX_CORE
|
||||
private readonly FileInfo fileInfo;
|
||||
#endif
|
||||
|
||||
public GZipVolume(Stream stream, Options options)
|
||||
: base(stream, options)
|
||||
{
|
||||
@@ -17,17 +13,6 @@ namespace SharpCompress.Common.GZip
|
||||
public GZipVolume(FileInfo fileInfo, Options options)
|
||||
: base(fileInfo.OpenRead(), options)
|
||||
{
|
||||
this.fileInfo = fileInfo;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !PORTABLE && !NETFX_CORE
|
||||
/// <summary>
|
||||
/// File that backs this volume, if it not stream based
|
||||
/// </summary>
|
||||
public override FileInfo VolumeFile
|
||||
{
|
||||
get { return fileInfo; }
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
using System.IO;
|
||||
|
||||
namespace SharpCompress.Common
|
||||
{
|
||||
public class GenericVolume : Volume
|
||||
{
|
||||
#if !PORTABLE && !NETFX_CORE
|
||||
private FileInfo fileInfo;
|
||||
#endif
|
||||
|
||||
public GenericVolume(Stream stream, Options options)
|
||||
: base(stream, options)
|
||||
{
|
||||
}
|
||||
|
||||
#if !PORTABLE && !NETFX_CORE
|
||||
public GenericVolume(FileInfo fileInfo, Options options)
|
||||
: base(fileInfo.OpenRead(), options)
|
||||
{
|
||||
this.fileInfo = fileInfo;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !PORTABLE && !NETFX_CORE
|
||||
/// <summary>
|
||||
/// File that backs this volume, if it not stream based
|
||||
/// </summary>
|
||||
public override FileInfo VolumeFile
|
||||
{
|
||||
get { return fileInfo; }
|
||||
}
|
||||
#endif
|
||||
|
||||
public override bool IsFirstVolume
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public override bool IsMultiVolume
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
}
|
||||
}
|
||||
48
SharpCompress/Common/IEntry.Extensions.cs
Normal file
48
SharpCompress/Common/IEntry.Extensions.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace SharpCompress.Common
|
||||
{
|
||||
internal static class IEntryExtensions
|
||||
{
|
||||
internal static void PreserveExtractionOptions(this IEntry entry, string destinationFileName,
|
||||
ExtractOptions options)
|
||||
{
|
||||
if (options.HasFlag(ExtractOptions.PreserveFileTime) || options.HasFlag(ExtractOptions.PreserveAttributes))
|
||||
{
|
||||
FileInfo nf = new FileInfo(destinationFileName);
|
||||
if (!nf.Exists)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// update file time to original packed time
|
||||
if (options.HasFlag(ExtractOptions.PreserveFileTime))
|
||||
{
|
||||
if (entry.CreatedTime.HasValue)
|
||||
{
|
||||
nf.CreationTime = entry.CreatedTime.Value;
|
||||
}
|
||||
|
||||
if (entry.LastModifiedTime.HasValue)
|
||||
{
|
||||
nf.LastWriteTime = entry.LastModifiedTime.Value;
|
||||
}
|
||||
|
||||
if (entry.LastAccessedTime.HasValue)
|
||||
{
|
||||
nf.LastAccessTime = entry.LastAccessedTime.Value;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.HasFlag(ExtractOptions.PreserveAttributes))
|
||||
{
|
||||
if (entry.Attrib.HasValue)
|
||||
{
|
||||
nf.Attributes = (FileAttributes)System.Enum.ToObject(typeof(FileAttributes), entry.Attrib.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,14 +7,15 @@ namespace SharpCompress.Common
|
||||
CompressionType CompressionType { get; }
|
||||
DateTime? ArchivedTime { get; }
|
||||
long CompressedSize { get; }
|
||||
uint Crc { get; }
|
||||
long Crc { get; }
|
||||
DateTime? CreatedTime { get; }
|
||||
string FilePath { get; }
|
||||
string Key { get; }
|
||||
bool IsDirectory { get; }
|
||||
bool IsEncrypted { get; }
|
||||
bool IsSplit { get; }
|
||||
DateTime? LastAccessedTime { get; }
|
||||
DateTime? LastModifiedTime { get; }
|
||||
long Size { get; }
|
||||
int? Attrib { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace SharpCompress.Common
|
||||
{
|
||||
internal interface IStreamListener
|
||||
internal interface IExtractionListener
|
||||
{
|
||||
void FireFilePartExtractionBegin(string name, long size, long compressedSize);
|
||||
void FireCompressedBytesRead(long currentPartCompressedBytes, long compressedReadBytes);
|
||||
@@ -7,11 +7,5 @@ namespace SharpCompress.Common
|
||||
{
|
||||
public interface IVolume : IDisposable
|
||||
{
|
||||
#if !PORTABLE && !NETFX_CORE
|
||||
/// <summary>
|
||||
/// File that backs this volume, if it not stream based
|
||||
/// </summary>
|
||||
FileInfo VolumeFile { get; }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress.Common.Rar.Headers
|
||||
@@ -15,7 +14,7 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
{
|
||||
uint lowUncompressedSize = reader.ReadUInt32();
|
||||
|
||||
HostOS = (HostOS) (int) reader.ReadByte();
|
||||
HostOS = (HostOS)reader.ReadByte();
|
||||
|
||||
FileCRC = reader.ReadUInt32();
|
||||
|
||||
@@ -46,7 +45,7 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
CompressedSize = UInt32To64(highCompressedSize, AdditionalSize);
|
||||
UncompressedSize = UInt32To64(highUncompressedkSize, lowUncompressedSize);
|
||||
|
||||
nameSize = nameSize > 4*1024 ? (short) (4*1024) : nameSize;
|
||||
nameSize = nameSize > 4 * 1024 ? (short)(4 * 1024) : nameSize;
|
||||
|
||||
byte[] fileNameBytes = reader.ReadBytes(nameSize);
|
||||
|
||||
@@ -106,11 +105,16 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
}
|
||||
if (FileFlags.HasFlag(FileFlags.EXTTIME))
|
||||
{
|
||||
ushort extendedFlags = reader.ReadUInt16();
|
||||
FileLastModifiedTime = ProcessExtendedTime(extendedFlags, FileLastModifiedTime, reader, 0);
|
||||
FileCreatedTime = ProcessExtendedTime(extendedFlags, null, reader, 1);
|
||||
FileLastAccessedTime = ProcessExtendedTime(extendedFlags, null, reader, 2);
|
||||
FileArchivedTime = ProcessExtendedTime(extendedFlags, null, reader, 3);
|
||||
// verify that the end of the header hasn't been reached before reading the Extended Time.
|
||||
// some tools incorrectly omit Extended Time despite specifying FileFlags.EXTTIME, which most parsers tolerate.
|
||||
if (ReadBytes + reader.CurrentReadByteCount <= HeaderSize - 2)
|
||||
{
|
||||
ushort extendedFlags = reader.ReadUInt16();
|
||||
FileLastModifiedTime = ProcessExtendedTime(extendedFlags, FileLastModifiedTime, reader, 0);
|
||||
FileCreatedTime = ProcessExtendedTime(extendedFlags, null, reader, 1);
|
||||
FileLastAccessedTime = ProcessExtendedTime(extendedFlags, null, reader, 2);
|
||||
FileArchivedTime = ProcessExtendedTime(extendedFlags, null, reader, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +134,7 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
private static DateTime? ProcessExtendedTime(ushort extendedFlags, DateTime? time, MarkingBinaryReader reader,
|
||||
int i)
|
||||
{
|
||||
uint rmode = (uint) extendedFlags >> (3 - i)*4;
|
||||
uint rmode = (uint)extendedFlags >> (3 - i) * 4;
|
||||
if ((rmode & 8) == 0)
|
||||
{
|
||||
return null;
|
||||
@@ -145,14 +149,14 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
time = time.Value.AddSeconds(1);
|
||||
}
|
||||
uint nanosecondHundreds = 0;
|
||||
int count = (int) rmode & 3;
|
||||
int count = (int)rmode & 3;
|
||||
for (int j = 0; j < count; j++)
|
||||
{
|
||||
byte b = reader.ReadByte();
|
||||
nanosecondHundreds |= (((uint) b) << ((j + 3 - count)*8));
|
||||
nanosecondHundreds |= (((uint)b) << ((j + 3 - count) * 8));
|
||||
}
|
||||
//10^-7 to 10^-3
|
||||
return time.Value.AddMilliseconds(nanosecondHundreds*Math.Pow(10, -4));
|
||||
return time.Value.AddMilliseconds(nanosecondHundreds * Math.Pow(10, -4));
|
||||
}
|
||||
|
||||
private static string ConvertPath(string path, HostOS os)
|
||||
@@ -205,7 +209,7 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
|
||||
internal FileFlags FileFlags
|
||||
{
|
||||
get { return (FileFlags) base.Flags; }
|
||||
get { return (FileFlags)base.Flags; }
|
||||
}
|
||||
|
||||
internal long CompressedSize { get; private set; }
|
||||
|
||||
@@ -10,48 +10,15 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
|
||||
internal bool IsValid()
|
||||
{
|
||||
if (!(HeadCRC == 0x6152))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!(HeaderType == HeaderType.MarkHeader))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!(Flags == 0x1a21))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!(HeaderSize == BaseBlockSize))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Rar old signature: 52 45 7E 5E (not supported)
|
||||
|
||||
internal bool IsSignature()
|
||||
{
|
||||
bool valid = false;
|
||||
/*byte[] d = new byte[BaseBlock.BaseBlockSize];
|
||||
BinaryWriter writer = new BinaryWriter();
|
||||
writer.Write(HeadCRC);
|
||||
writer.Write((byte)HeaderType);
|
||||
writer.Write(flags);
|
||||
writer.Write(HeaderSize);
|
||||
writer.Flush
|
||||
|
||||
if (d[0] == 0x52) {
|
||||
if (d[1]==0x45 && d[2]==0x7e && d[3]==0x5e) {
|
||||
oldFormat=true;
|
||||
valid=true;
|
||||
}
|
||||
else if (d[1]==0x61 && d[2]==0x72 && d[3]==0x21 && d[4]==0x1a &&
|
||||
d[5]==0x07 && d[6]==0x00) {
|
||||
oldFormat=false;
|
||||
valid=true;
|
||||
}
|
||||
}*/
|
||||
return valid;
|
||||
// Rar4 signature: 52 61 72 21 1A 07 00
|
||||
return HeadCRC == 0x6152 &&
|
||||
HeaderType == HeaderType.MarkHeader &&
|
||||
Flags == 0x1A21 &&
|
||||
HeaderSize == 0x07;
|
||||
|
||||
// Rar5 signature: 52 61 72 21 1A 07 10 00 (not supported yet)
|
||||
}
|
||||
|
||||
internal bool OldFormat { get; private set; }
|
||||
|
||||
22
SharpCompress/Common/Rar/Headers/ProtectHeader.cs
Normal file
22
SharpCompress/Common/Rar/Headers/ProtectHeader.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress.Common.Rar.Headers
|
||||
{
|
||||
// ProtectHeader is part of the Recovery Record feature
|
||||
internal class ProtectHeader : RarHeader
|
||||
{
|
||||
protected override void ReadFromReader(MarkingBinaryReader reader)
|
||||
{
|
||||
Version = reader.ReadByte();
|
||||
RecSectors = reader.ReadUInt16();
|
||||
TotalBlocks = reader.ReadUInt32();
|
||||
Mark = reader.ReadBytes(8);
|
||||
}
|
||||
|
||||
internal uint DataSize { get { return AdditionalSize; } }
|
||||
internal byte Version { get; private set; }
|
||||
internal ushort RecSectors { get; private set; }
|
||||
internal uint TotalBlocks { get; private set; }
|
||||
internal byte[] Mark { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,7 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
protected virtual void ReadFromReader(MarkingBinaryReader reader)
|
||||
{
|
||||
HeadCRC = reader.ReadInt16();
|
||||
HeaderType = (HeaderType)(int)(reader.ReadByte() & 0xff);
|
||||
HeaderType = (HeaderType)(reader.ReadByte() & 0xff);
|
||||
Flags = reader.ReadInt16();
|
||||
HeaderSize = reader.ReadInt16();
|
||||
if (FlagUtility.HasFlag(Flags, LONG_BLOCK))
|
||||
|
||||
@@ -93,7 +93,11 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
{
|
||||
if (!Options.HasFlag(Options.KeepStreamsOpen))
|
||||
{
|
||||
#if NET35
|
||||
reader.Close();
|
||||
#else
|
||||
reader.Dispose();
|
||||
#endif
|
||||
}
|
||||
throw new InvalidFormatException("Error trying to read rar signature.", e);
|
||||
}
|
||||
@@ -120,6 +124,10 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
|
||||
if (IsEncrypted)
|
||||
{
|
||||
if (Password == null)
|
||||
{
|
||||
throw new CryptographicException("Encrypted Rar archive has no password specified.");
|
||||
}
|
||||
reader.SkipQueue();
|
||||
byte[] salt = reader.ReadBytes(8);
|
||||
reader.InitializeAes(salt);
|
||||
@@ -143,6 +151,33 @@ namespace SharpCompress.Common.Rar.Headers
|
||||
{
|
||||
return header.PromoteHeader<MarkHeader>(reader);
|
||||
}
|
||||
|
||||
case HeaderType.ProtectHeader:
|
||||
{
|
||||
ProtectHeader ph = header.PromoteHeader<ProtectHeader>(reader);
|
||||
|
||||
// skip the recovery record data, we do not use it.
|
||||
switch (StreamingMode)
|
||||
{
|
||||
case StreamingMode.Seekable:
|
||||
{
|
||||
reader.BaseStream.Position += ph.DataSize;
|
||||
}
|
||||
break;
|
||||
case StreamingMode.Streaming:
|
||||
{
|
||||
reader.BaseStream.Skip(ph.DataSize);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
throw new InvalidFormatException("Invalid StreamingMode");
|
||||
}
|
||||
}
|
||||
|
||||
return ph;
|
||||
}
|
||||
|
||||
case HeaderType.NewSubHeader:
|
||||
{
|
||||
FileHeader fh = header.PromoteHeader<FileHeader>(reader);
|
||||
|
||||
@@ -30,7 +30,6 @@ namespace SharpCompress.Common.Rar
|
||||
|
||||
public override byte[] ReadBytes(int count)
|
||||
{
|
||||
CurrentReadByteCount += count;
|
||||
if (UseEncryption)
|
||||
{
|
||||
return ReadAndDecryptBytes(count);
|
||||
|
||||
@@ -20,17 +20,17 @@ namespace SharpCompress.Common.Rar
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
@@ -70,27 +70,27 @@ namespace SharpCompress.Common.Rar
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override bool CanRead
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public override bool CanSeek
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override bool CanWrite
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
get { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
public override long Position { get; set; }
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace SharpCompress.Common.Rar
|
||||
/// <summary>
|
||||
/// The File's 32 bit CRC Hash
|
||||
/// </summary>
|
||||
public override uint Crc
|
||||
public override long Crc
|
||||
{
|
||||
get { return FileHeader.FileCRC; }
|
||||
}
|
||||
@@ -18,7 +18,7 @@ namespace SharpCompress.Common.Rar
|
||||
/// <summary>
|
||||
/// The path of the file internal to the Rar Archive.
|
||||
/// </summary>
|
||||
public override string FilePath
|
||||
public override string Key
|
||||
{
|
||||
get { return FileHeader.FileName; }
|
||||
}
|
||||
@@ -79,7 +79,7 @@ namespace SharpCompress.Common.Rar
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Entry Path: {0} Compressed Size: {1} Uncompressed Size: {2} CRC: {3}",
|
||||
FilePath, CompressedSize, Size, Crc);
|
||||
Key, CompressedSize, Size, Crc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,11 +28,10 @@ namespace SharpCompress.Common.Rar
|
||||
aesInitializationVector = new byte[CRYPTO_BLOCK_SIZE];
|
||||
int rawLength = 2 * password.Length;
|
||||
byte[] rawPassword = new byte[rawLength + 8];
|
||||
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
|
||||
for (int i = 0; i < password.Length; i++)
|
||||
byte[] passwordBytes = Encoding.Unicode.GetBytes(password);
|
||||
for (int i = 0; i < rawLength; i++)
|
||||
{
|
||||
rawPassword[i * 2] = passwordBytes[i];
|
||||
rawPassword[i * 2 + 1] = 0;
|
||||
rawPassword[i] = passwordBytes[i];
|
||||
}
|
||||
for (int i = 0; i < salt.Length; i++)
|
||||
{
|
||||
@@ -106,7 +105,7 @@ namespace SharpCompress.Common.Rar
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
rijndael.Dispose();
|
||||
((IDisposable)rijndael).Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,20 +13,16 @@ namespace SharpCompress.Common.Rar
|
||||
public abstract class RarVolume : Volume
|
||||
{
|
||||
private readonly RarHeaderFactory headerFactory;
|
||||
public string Password { get; set; }
|
||||
|
||||
internal RarVolume(StreamingMode mode, Stream stream, Options options)
|
||||
: this(mode, stream, null, options)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
internal RarVolume(StreamingMode mode, Stream stream, string password, Options options)
|
||||
: base(stream, options)
|
||||
{
|
||||
headerFactory = new RarHeaderFactory(mode, options, password);
|
||||
Password = password;
|
||||
}
|
||||
|
||||
internal string Password { get; private set; }
|
||||
|
||||
internal StreamingMode Mode
|
||||
{
|
||||
get { return headerFactory.StreamingMode; }
|
||||
|
||||
13
SharpCompress/Common/ReaderExtractionEventArgs.cs
Normal file
13
SharpCompress/Common/ReaderExtractionEventArgs.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
|
||||
namespace SharpCompress.Common
|
||||
{
|
||||
public class ReaderExtractionEventArgs<T> : EventArgs
|
||||
{
|
||||
internal ReaderExtractionEventArgs(T entry)
|
||||
{
|
||||
Item = entry;
|
||||
}
|
||||
public T Item { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -67,8 +67,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
ulong id = _currentReader.ReadNumber();
|
||||
if (id > 25)
|
||||
return null;
|
||||
|
||||
#if DEBUG
|
||||
Log.WriteLine("ReadId: {0}", (BlockType)id);
|
||||
#endif
|
||||
return (BlockType)id;
|
||||
}
|
||||
|
||||
@@ -159,7 +160,7 @@ namespace SharpCompress.Common.SevenZip
|
||||
private DateTime TranslateTime(long time)
|
||||
{
|
||||
// FILETIME = 100-nanosecond intervals since January 1, 1601 (UTC)
|
||||
return DateTime.FromFileTimeUtc(time);
|
||||
return DateTime.FromFileTimeUtc(time).ToLocalTime();
|
||||
}
|
||||
|
||||
private DateTime? TranslateTime(long? time)
|
||||
@@ -197,20 +198,25 @@ namespace SharpCompress.Common.SevenZip
|
||||
|
||||
private void GetNextFolderItem(CFolder folder)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- GetNextFolderItem --");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
int numCoders = ReadNum();
|
||||
#if DEBUG
|
||||
Log.WriteLine("NumCoders: " + numCoders);
|
||||
|
||||
#endif
|
||||
folder.Coders = new List<CCoderInfo>(numCoders);
|
||||
int numInStreams = 0;
|
||||
int numOutStreams = 0;
|
||||
for (int i = 0; i < numCoders; i++)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- Coder --");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
CCoderInfo coder = new CCoderInfo();
|
||||
@@ -220,11 +226,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
int idSize = (mainByte & 0xF);
|
||||
byte[] longID = new byte[idSize];
|
||||
ReadBytes(longID, 0, idSize);
|
||||
Log.WriteLine("MethodId: " +
|
||||
String.Join("",
|
||||
Enumerable.Range(0, idSize)
|
||||
.Select(x => longID[x].ToString("x2"))
|
||||
.ToArray()));
|
||||
#if DEBUG
|
||||
Log.WriteLine("MethodId: " + String.Join("", Enumerable.Range(0, idSize).Select(x => longID[x].ToString("x2")).ToArray()));
|
||||
#endif
|
||||
if (idSize > 8)
|
||||
throw new NotSupportedException();
|
||||
ulong id = 0;
|
||||
@@ -236,12 +240,15 @@ namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
coder.NumInStreams = ReadNum();
|
||||
coder.NumOutStreams = ReadNum();
|
||||
Log.WriteLine("Complex Stream (In: " + coder.NumInStreams + " - Out: " + coder.NumOutStreams +
|
||||
")");
|
||||
#if DEBUG
|
||||
Log.WriteLine("Complex Stream (In: " + coder.NumInStreams + " - Out: " + coder.NumOutStreams + ")");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("Simple Stream (In: 1 - Out: 1)");
|
||||
#endif
|
||||
coder.NumInStreams = 1;
|
||||
coder.NumOutStreams = 1;
|
||||
}
|
||||
@@ -251,8 +258,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
int propsSize = ReadNum();
|
||||
coder.Props = new byte[propsSize];
|
||||
ReadBytes(coder.Props, 0, propsSize);
|
||||
Log.WriteLine("Settings: " +
|
||||
String.Join("", coder.Props.Select(bt => bt.ToString("x2")).ToArray()));
|
||||
#if DEBUG
|
||||
Log.WriteLine("Settings: " + String.Join("", coder.Props.Select(bt => bt.ToString("x2")).ToArray()));
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((mainByte & 0x80) != 0)
|
||||
@@ -263,23 +271,31 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int numBindPairs = numOutStreams - 1;
|
||||
folder.BindPairs = new List<CBindPair>(numBindPairs);
|
||||
#if DEBUG
|
||||
Log.WriteLine("BindPairs: " + numBindPairs);
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
for (int i = 0; i < numBindPairs; i++)
|
||||
{
|
||||
CBindPair bp = new CBindPair();
|
||||
bp.InIndex = ReadNum();
|
||||
bp.OutIndex = ReadNum();
|
||||
folder.BindPairs.Add(bp);
|
||||
#if DEBUG
|
||||
Log.WriteLine("#" + i + " - In: " + bp.InIndex + " - Out: " + bp.OutIndex);
|
||||
#endif
|
||||
}
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
|
||||
if (numInStreams < numBindPairs)
|
||||
throw new NotSupportedException();
|
||||
@@ -292,7 +308,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
if (folder.FindBindPairForInStream(i) < 0)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("Single PackStream: #" + i);
|
||||
#endif
|
||||
folder.PackStreams.Add(i);
|
||||
break;
|
||||
}
|
||||
@@ -303,26 +321,36 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("Multiple PackStreams ...");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
for (int i = 0; i < numPackStreams; i++)
|
||||
{
|
||||
var num = ReadNum();
|
||||
#if DEBUG
|
||||
Log.WriteLine("#" + i + " - " + num);
|
||||
#endif
|
||||
folder.PackStreams.Add(num);
|
||||
}
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private List<uint?> ReadHashDigests(int count)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.Write("ReadHashDigests:");
|
||||
#endif
|
||||
|
||||
var defined = ReadOptionalBitVector(count);
|
||||
var digests = new List<uint?>(count);
|
||||
@@ -331,44 +359,62 @@ namespace SharpCompress.Common.SevenZip
|
||||
if (defined[i])
|
||||
{
|
||||
uint crc = ReadUInt32();
|
||||
#if DEBUG
|
||||
Log.Write(" " + crc.ToString("x8"));
|
||||
#endif
|
||||
digests.Add(crc);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEBUG
|
||||
Log.Write(" ########");
|
||||
#endif
|
||||
digests.Add(null);
|
||||
}
|
||||
}
|
||||
#if DEBUG
|
||||
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
return digests;
|
||||
}
|
||||
|
||||
private void ReadPackInfo(out long dataOffset, out List<long> packSizes, out List<uint?> packCRCs)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- ReadPackInfo --");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
packCRCs = null;
|
||||
|
||||
dataOffset = checked((long)ReadNumber());
|
||||
#if DEBUG
|
||||
Log.WriteLine("DataOffset: " + dataOffset);
|
||||
#endif
|
||||
|
||||
int numPackStreams = ReadNum();
|
||||
#if DEBUG
|
||||
Log.WriteLine("NumPackStreams: " + numPackStreams);
|
||||
#endif
|
||||
|
||||
WaitAttribute(BlockType.Size);
|
||||
packSizes = new List<long>(numPackStreams);
|
||||
#if DEBUG
|
||||
Log.Write("Sizes:");
|
||||
#endif
|
||||
for (int i = 0; i < numPackStreams; i++)
|
||||
{
|
||||
var size = checked((long)ReadNumber());
|
||||
#if DEBUG
|
||||
Log.Write(" " + size);
|
||||
#endif
|
||||
packSizes.Add(size);
|
||||
}
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
|
||||
BlockType? type;
|
||||
for (; ; )
|
||||
@@ -393,19 +439,25 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadUnpackInfo(List<byte[]> dataVector, out List<CFolder> folders)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- ReadUnpackInfo --");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
WaitAttribute(BlockType.Folder);
|
||||
int numFolders = ReadNum();
|
||||
#if DEBUG
|
||||
Log.WriteLine("NumFolders: {0}", numFolders);
|
||||
#endif
|
||||
|
||||
using (CStreamSwitch streamSwitch = new CStreamSwitch())
|
||||
{
|
||||
@@ -424,20 +476,27 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
|
||||
WaitAttribute(BlockType.CodersUnpackSize);
|
||||
|
||||
#if DEBUG
|
||||
Log.WriteLine("UnpackSizes:");
|
||||
#endif
|
||||
for (int i = 0; i < numFolders; i++)
|
||||
{
|
||||
CFolder folder = folders[i];
|
||||
#if DEBUG
|
||||
Log.Write(" #" + i + ":");
|
||||
#endif
|
||||
int numOutStreams = folder.GetNumOutStreams();
|
||||
for (int j = 0; j < numOutStreams; j++)
|
||||
{
|
||||
long size = checked((long)ReadNumber());
|
||||
#if DEBUG
|
||||
Log.Write(" " + size);
|
||||
#endif
|
||||
folder.UnpackSizes.Add(size);
|
||||
}
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
}
|
||||
|
||||
for (; ; )
|
||||
@@ -459,15 +518,19 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadSubStreamsInfo(List<CFolder> folders, out List<int> numUnpackStreamsInFolders,
|
||||
out List<long> unpackSizes, out List<uint?> digests)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- ReadSubStreamsInfo --");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
numUnpackStreamsInFolders = null;
|
||||
@@ -479,14 +542,20 @@ namespace SharpCompress.Common.SevenZip
|
||||
if (type == BlockType.NumUnpackStream)
|
||||
{
|
||||
numUnpackStreamsInFolders = new List<int>(folders.Count);
|
||||
#if DEBUG
|
||||
Log.Write("NumUnpackStreams:");
|
||||
#endif
|
||||
for (int i = 0; i < folders.Count; i++)
|
||||
{
|
||||
var num = ReadNum();
|
||||
#if DEBUG
|
||||
Log.Write(" " + num);
|
||||
#endif
|
||||
numUnpackStreamsInFolders.Add(num);
|
||||
}
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
if (type == BlockType.CRC || type == BlockType.Size)
|
||||
@@ -511,21 +580,26 @@ namespace SharpCompress.Common.SevenZip
|
||||
int numSubstreams = numUnpackStreamsInFolders[i];
|
||||
if (numSubstreams == 0)
|
||||
continue;
|
||||
|
||||
#if DEBUG
|
||||
Log.Write("#{0} StreamSizes:", i);
|
||||
#endif
|
||||
long sum = 0;
|
||||
for (int j = 1; j < numSubstreams; j++)
|
||||
{
|
||||
if (type == BlockType.Size)
|
||||
{
|
||||
long size = checked((long)ReadNumber());
|
||||
#if DEBUG
|
||||
Log.Write(" " + size);
|
||||
#endif
|
||||
unpackSizes.Add(size);
|
||||
sum += size;
|
||||
}
|
||||
}
|
||||
unpackSizes.Add(folders[i].GetUnpackSize() - sum);
|
||||
#if DEBUG
|
||||
Log.WriteLine(" - rest: " + unpackSizes.Last());
|
||||
#endif
|
||||
}
|
||||
if (type == BlockType.Size)
|
||||
type = ReadId();
|
||||
@@ -589,7 +663,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -603,8 +679,10 @@ namespace SharpCompress.Common.SevenZip
|
||||
out List<long> unpackSizes,
|
||||
out List<uint?> digests)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- ReadStreamsInfo --");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
dataOffset = long.MinValue;
|
||||
@@ -637,14 +715,18 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private List<byte[]> ReadAndDecodePackedStreams(long baseOffset, IPasswordProvider pass)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- ReadAndDecodePackedStreams --");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
long dataStartPos;
|
||||
@@ -697,14 +779,18 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadHeader(ArchiveDatabase db, IPasswordProvider getTextPassword)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("-- ReadHeader --");
|
||||
Log.PushIndent();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
BlockType? type = ReadId();
|
||||
@@ -762,7 +848,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
throw new InvalidOperationException();
|
||||
|
||||
int numFiles = ReadNum();
|
||||
#if DEBUG
|
||||
Log.WriteLine("NumFiles: " + numFiles);
|
||||
#endif
|
||||
db.Files = new List<CFileItem>(numFiles);
|
||||
for (int i = 0; i < numFiles; i++)
|
||||
db.Files.Add(new CFileItem());
|
||||
@@ -786,112 +874,147 @@ namespace SharpCompress.Common.SevenZip
|
||||
using (var streamSwitch = new CStreamSwitch())
|
||||
{
|
||||
streamSwitch.Set(this, dataVector);
|
||||
#if DEBUG
|
||||
Log.Write("FileNames:");
|
||||
#endif
|
||||
for (int i = 0; i < db.Files.Count; i++)
|
||||
{
|
||||
db.Files[i].Name = _currentReader.ReadString();
|
||||
#if DEBUG
|
||||
Log.Write(" " + db.Files[i].Name);
|
||||
#endif
|
||||
}
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case BlockType.WinAttributes:
|
||||
#if DEBUG
|
||||
Log.Write("WinAttributes:");
|
||||
#endif
|
||||
ReadAttributeVector(dataVector, numFiles, delegate(int i, uint? attr)
|
||||
{
|
||||
db.Files[i].Attrib = attr;
|
||||
Log.Write(" " +
|
||||
(attr.HasValue
|
||||
? attr.Value.ToString("x8")
|
||||
: "n/a"));
|
||||
#if DEBUG
|
||||
Log.Write(" " + (attr.HasValue ? attr.Value.ToString("x8") : "n/a"));
|
||||
#endif
|
||||
});
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.EmptyStream:
|
||||
emptyStreamVector = ReadBitVector(numFiles);
|
||||
#if DEBUG
|
||||
|
||||
Log.Write("EmptyStream: ");
|
||||
#endif
|
||||
for (int i = 0; i < emptyStreamVector.Length; i++)
|
||||
{
|
||||
if (emptyStreamVector[i])
|
||||
{
|
||||
#if DEBUG
|
||||
Log.Write("x");
|
||||
#endif
|
||||
numEmptyStreams++;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEBUG
|
||||
Log.Write(".");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
|
||||
emptyFileVector = new BitVector(numEmptyStreams);
|
||||
antiFileVector = new BitVector(numEmptyStreams);
|
||||
break;
|
||||
case BlockType.EmptyFile:
|
||||
emptyFileVector = ReadBitVector(numEmptyStreams);
|
||||
#if DEBUG
|
||||
Log.Write("EmptyFile: ");
|
||||
for (int i = 0; i < numEmptyStreams; i++)
|
||||
Log.Write(emptyFileVector[i] ? "x" : ".");
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.Anti:
|
||||
antiFileVector = ReadBitVector(numEmptyStreams);
|
||||
#if DEBUG
|
||||
Log.Write("Anti: ");
|
||||
for (int i = 0; i < numEmptyStreams; i++)
|
||||
Log.Write(antiFileVector[i] ? "x" : ".");
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.StartPos:
|
||||
#if DEBUG
|
||||
Log.Write("StartPos:");
|
||||
#endif
|
||||
ReadNumberVector(dataVector, numFiles, delegate(int i, long? startPos)
|
||||
{
|
||||
db.Files[i].StartPos = startPos;
|
||||
Log.Write(" " +
|
||||
(startPos.HasValue
|
||||
? startPos.Value.ToString()
|
||||
: "n/a"));
|
||||
#if DEBUG
|
||||
Log.Write(" " + (startPos.HasValue ? startPos.Value.ToString() : "n/a"));
|
||||
#endif
|
||||
});
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.CTime:
|
||||
#if DEBUG
|
||||
Log.Write("CTime:");
|
||||
#endif
|
||||
ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time)
|
||||
{
|
||||
db.Files[i].CTime = time;
|
||||
Log.Write(" " +
|
||||
(time.HasValue
|
||||
? time.Value.ToString()
|
||||
: "n/a"));
|
||||
#if DEBUG
|
||||
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
|
||||
#endif
|
||||
});
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.ATime:
|
||||
#if DEBUG
|
||||
Log.Write("ATime:");
|
||||
#endif
|
||||
ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time)
|
||||
{
|
||||
db.Files[i].ATime = time;
|
||||
Log.Write(" " +
|
||||
(time.HasValue
|
||||
? time.Value.ToString()
|
||||
: "n/a"));
|
||||
#if DEBUG
|
||||
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
|
||||
#endif
|
||||
});
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.MTime:
|
||||
#if DEBUG
|
||||
Log.Write("MTime:");
|
||||
#endif
|
||||
ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time)
|
||||
{
|
||||
db.Files[i].MTime = time;
|
||||
Log.Write(" " +
|
||||
(time.HasValue
|
||||
? time.Value.ToString()
|
||||
: "n/a"));
|
||||
#if DEBUG
|
||||
Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
|
||||
#endif
|
||||
});
|
||||
#if DEBUG
|
||||
Log.WriteLine();
|
||||
#endif
|
||||
break;
|
||||
case BlockType.Dummy:
|
||||
#if DEBUG
|
||||
Log.Write("Dummy: " + size);
|
||||
#endif
|
||||
for (long j = 0; j < size; j++)
|
||||
if (ReadByte() != 0)
|
||||
throw new InvalidOperationException();
|
||||
@@ -933,7 +1056,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if DEBUG
|
||||
Log.PopIndent();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1073,14 +1198,12 @@ namespace SharpCompress.Common.SevenZip
|
||||
private class FolderUnpackStream : Stream
|
||||
{
|
||||
private ArchiveDatabase _db;
|
||||
private int _otherIndex;
|
||||
private int _startIndex;
|
||||
private List<bool> _extractStatuses;
|
||||
|
||||
public FolderUnpackStream(ArchiveDatabase db, int p, int startIndex, List<bool> list)
|
||||
{
|
||||
this._db = db;
|
||||
this._otherIndex = p;
|
||||
this._startIndex = startIndex;
|
||||
this._extractStatuses = list;
|
||||
}
|
||||
@@ -1089,48 +1212,48 @@ namespace SharpCompress.Common.SevenZip
|
||||
|
||||
public override bool CanRead
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public override bool CanSeek
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override bool CanWrite
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
get { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
set { throw new NotImplementedException(); }
|
||||
get { throw new NotSupportedException(); }
|
||||
set { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
private Stream _stream;
|
||||
@@ -1150,13 +1273,10 @@ namespace SharpCompress.Common.SevenZip
|
||||
|
||||
private void OpenFile()
|
||||
{
|
||||
bool skip = !_extractStatuses[_currentIndex];
|
||||
int index = _startIndex + _currentIndex;
|
||||
int realIndex = _otherIndex + index;
|
||||
//string filename = @"D:\_testdump\" + _db.Files[index].Name;
|
||||
//Directory.CreateDirectory(Path.GetDirectoryName(filename));
|
||||
//_stream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.Delete);
|
||||
#if DEBUG
|
||||
Log.WriteLine(_db.Files[index].Name);
|
||||
#endif
|
||||
if (_db.Files[index].CrcDefined)
|
||||
_stream = new CrcCheckStream(_db.Files[index].Crc.Value);
|
||||
else
|
||||
@@ -1192,7 +1312,7 @@ namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
// we support partial extracting
|
||||
System.Diagnostics.Debugger.Break();
|
||||
throw new NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
OpenFile();
|
||||
}
|
||||
|
||||
@@ -16,7 +16,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
if (_active)
|
||||
{
|
||||
_active = false;
|
||||
#if DEBUG
|
||||
Log.WriteLine("[end of switch]");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (_needRemove)
|
||||
@@ -47,7 +49,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
if (dataIndex < 0 || dataIndex >= dataVector.Count)
|
||||
throw new InvalidOperationException();
|
||||
|
||||
#if DEBUG
|
||||
Log.WriteLine("[switch to stream {0}]", dataIndex);
|
||||
#endif
|
||||
_archive = archive;
|
||||
_archive.AddByteStream(dataVector[dataIndex], 0, dataVector[dataIndex].Length);
|
||||
_needRemove = true;
|
||||
@@ -55,7 +59,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteLine("[inline data]");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ namespace SharpCompress.Common.SevenZip
|
||||
#region Variables
|
||||
|
||||
private byte[] _buffer;
|
||||
private int _origin;
|
||||
private int _offset;
|
||||
private int _ending;
|
||||
|
||||
@@ -45,7 +44,6 @@ namespace SharpCompress.Common.SevenZip
|
||||
public DataReader(byte[] buffer, int offset, int length)
|
||||
{
|
||||
_buffer = buffer;
|
||||
_origin = offset;
|
||||
_offset = offset;
|
||||
_ending = offset + length;
|
||||
}
|
||||
@@ -78,7 +76,9 @@ namespace SharpCompress.Common.SevenZip
|
||||
throw new EndOfStreamException();
|
||||
|
||||
_offset += (int) size;
|
||||
#if DEBUG
|
||||
Log.WriteLine("SkipData {0}", size);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void SkipData()
|
||||
|
||||
@@ -17,12 +17,12 @@ namespace SharpCompress.Common.SevenZip
|
||||
get { return FilePart.CompressionType; }
|
||||
}
|
||||
|
||||
public override uint Crc
|
||||
public override long Crc
|
||||
{
|
||||
get { return FilePart.Header.Crc ?? 0; }
|
||||
}
|
||||
|
||||
public override string FilePath
|
||||
public override string Key
|
||||
{
|
||||
get { return FilePart.Header.Name; }
|
||||
}
|
||||
@@ -39,22 +39,22 @@ namespace SharpCompress.Common.SevenZip
|
||||
|
||||
public override DateTime? LastModifiedTime
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
get { return FilePart.Header.MTime; }
|
||||
}
|
||||
|
||||
public override DateTime? CreatedTime
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public override DateTime? LastAccessedTime
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public override DateTime? ArchivedTime
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public override bool IsEncrypted
|
||||
@@ -72,13 +72,14 @@ namespace SharpCompress.Common.SevenZip
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override int? Attrib
|
||||
{
|
||||
get { return (int) FilePart.Header.Attrib; }
|
||||
}
|
||||
|
||||
internal override IEnumerable<FilePart> Parts
|
||||
{
|
||||
get { return FilePart.AsEnumerable<FilePart>(); }
|
||||
}
|
||||
|
||||
internal override void Close()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,18 +2,11 @@
|
||||
|
||||
namespace SharpCompress.Common.SevenZip
|
||||
{
|
||||
public class SevenZipVolume : GenericVolume
|
||||
public class SevenZipVolume : Volume
|
||||
{
|
||||
public SevenZipVolume(Stream stream, Options options)
|
||||
: base(stream, options)
|
||||
{
|
||||
}
|
||||
|
||||
#if !PORTABLE && !NETFX_CORE
|
||||
public SevenZipVolume(FileInfo fileInfo, Options options)
|
||||
: base(fileInfo, options)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using System.IO;
|
||||
using System.Net;
|
||||
#endif
|
||||
using System.Text;
|
||||
using SharpCompress.Converter;
|
||||
|
||||
namespace SharpCompress.Common.Tar.Headers
|
||||
{
|
||||
@@ -25,7 +26,7 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
|
||||
internal class TarHeader
|
||||
{
|
||||
internal static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0);
|
||||
internal static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
internal string Name { get; set; }
|
||||
//internal int Mode { get; set; }
|
||||
@@ -40,48 +41,60 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
|
||||
internal void Write(Stream output)
|
||||
{
|
||||
if (Name.Length > 255)
|
||||
{
|
||||
throw new InvalidFormatException("UsTar fileName can not be longer thatn 255 chars");
|
||||
}
|
||||
byte[] buffer = new byte[512];
|
||||
string name = Name;
|
||||
if (name.Length > 100)
|
||||
{
|
||||
name = Name.Substring(0, 100);
|
||||
}
|
||||
WriteStringBytes(name, buffer, 0, 100);
|
||||
|
||||
WriteOctalBytes(511, buffer, 100, 8);
|
||||
WriteOctalBytes(0, buffer, 108, 8);
|
||||
WriteOctalBytes(0, buffer, 116, 8);
|
||||
WriteOctalBytes(Size, buffer, 124, 12);
|
||||
var time = (long) (LastModifiedTime - Epoch).TotalSeconds;
|
||||
WriteOctalBytes(time, buffer, 136, 12);
|
||||
|
||||
buffer[156] = (byte) EntryType;
|
||||
WriteOctalBytes(511, buffer, 100, 8); // file mode
|
||||
WriteOctalBytes(0, buffer, 108, 8); // owner ID
|
||||
WriteOctalBytes(0, buffer, 116, 8); // group ID
|
||||
|
||||
//Encoding.UTF8.GetBytes("magic").CopyTo(buffer, 257);
|
||||
if (Name.Length > 100)
|
||||
{
|
||||
name = Name.Substring(101, Name.Length);
|
||||
ArchiveEncoding.Default.GetBytes(name).CopyTo(buffer, 345);
|
||||
// Set mock filename and filetype to indicate the next block is the actual name of the file
|
||||
WriteStringBytes("././@LongLink", buffer, 0, 100);
|
||||
buffer[156] = (byte)EntryType.LongName;
|
||||
WriteOctalBytes(Name.Length + 1, buffer, 124, 12);
|
||||
}
|
||||
if (Size >= 0x1FFFFFFFF)
|
||||
else
|
||||
{
|
||||
#if PORTABLE || NETFX_CORE
|
||||
byte[] bytes = BitConverter.GetBytes(Utility.HostToNetworkOrder(Size));
|
||||
#else
|
||||
byte[] bytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(Size));
|
||||
#endif
|
||||
var bytes12 = new byte[12];
|
||||
bytes.CopyTo(bytes12, 12 - bytes.Length);
|
||||
bytes12[0] |= 0x80;
|
||||
bytes12.CopyTo(buffer, 124);
|
||||
WriteStringBytes(Name, buffer, 0, 100);
|
||||
WriteOctalBytes(Size, buffer, 124, 12);
|
||||
var time = (long)(LastModifiedTime.ToUniversalTime() - Epoch).TotalSeconds;
|
||||
WriteOctalBytes(time, buffer, 136, 12);
|
||||
buffer[156] = (byte)EntryType;
|
||||
|
||||
if (Size >= 0x1FFFFFFFF)
|
||||
{
|
||||
byte[] bytes = DataConverter.BigEndian.GetBytes(Size);
|
||||
var bytes12 = new byte[12];
|
||||
bytes.CopyTo(bytes12, 12 - bytes.Length);
|
||||
bytes12[0] |= 0x80;
|
||||
bytes12.CopyTo(buffer, 124);
|
||||
}
|
||||
}
|
||||
|
||||
int crc = RecalculateChecksum(buffer);
|
||||
WriteOctalBytes(crc, buffer, 148, 8);
|
||||
|
||||
output.Write(buffer, 0, buffer.Length);
|
||||
|
||||
if (Name.Length > 100)
|
||||
{
|
||||
WriteLongFilenameHeader(output);
|
||||
Name = Name.Substring(0, 100);
|
||||
Write(output);
|
||||
}
|
||||
}
|
||||
private void WriteLongFilenameHeader(Stream output)
|
||||
{
|
||||
byte[] nameBytes = ArchiveEncoding.Default.GetBytes(Name);
|
||||
output.Write(nameBytes, 0, nameBytes.Length);
|
||||
|
||||
// pad to multiple of 512 bytes, and make sure a terminating null is added
|
||||
int numPaddingBytes = 512 - (nameBytes.Length % 512);
|
||||
if (numPaddingBytes == 0)
|
||||
numPaddingBytes = 512;
|
||||
output.Write(new byte[numPaddingBytes], 0, numPaddingBytes);
|
||||
}
|
||||
|
||||
internal bool Read(BinaryReader reader)
|
||||
@@ -103,24 +116,19 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
EntryType = (EntryType) buffer[156];
|
||||
if ((buffer[124] & 0x80) == 0x80) // if size in binary
|
||||
{
|
||||
long sizeBigEndian = BitConverter.ToInt64(buffer, 0x80);
|
||||
#if PORTABLE || NETFX_CORE
|
||||
Size = Utility.NetworkToHostOrder(sizeBigEndian);
|
||||
#else
|
||||
Size = IPAddress.NetworkToHostOrder(sizeBigEndian);
|
||||
#endif
|
||||
Size = DataConverter.BigEndian.GetInt64(buffer, 0x80);
|
||||
}
|
||||
else
|
||||
{
|
||||
Size = ReadASCIIInt64Base8(buffer, 124, 11);
|
||||
}
|
||||
long unixTimeStamp = ReadASCIIInt64Base8(buffer, 136, 11);
|
||||
LastModifiedTime = Epoch.AddSeconds(unixTimeStamp);
|
||||
LastModifiedTime = Epoch.AddSeconds(unixTimeStamp).ToLocalTime();
|
||||
|
||||
|
||||
Magic = ArchiveEncoding.Default.GetString(buffer, 257, 6).TrimNulls();
|
||||
|
||||
if (!string.IsNullOrEmpty(Magic) && "ustar ".Equals(Magic))
|
||||
if (!string.IsNullOrEmpty(Magic) && "ustar".Equals(Magic))
|
||||
{
|
||||
string namePrefix = ArchiveEncoding.Default.GetString(buffer, 345, 157);
|
||||
namePrefix = namePrefix.TrimNulls();
|
||||
@@ -163,7 +171,6 @@ namespace SharpCompress.Common.Tar.Headers
|
||||
{
|
||||
buffer[offset + i + shift] = (byte) val[i];
|
||||
}
|
||||
buffer[offset + length] = 0;
|
||||
}
|
||||
|
||||
private static int ReadASCIIInt32Base8(byte[] buffer, int offset, int count)
|
||||
|
||||
@@ -22,12 +22,12 @@ namespace SharpCompress.Common.Tar
|
||||
get { return type; }
|
||||
}
|
||||
|
||||
public override uint Crc
|
||||
public override long Crc
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
public override string FilePath
|
||||
public override string Key
|
||||
{
|
||||
get { return filePart.Header.Name; }
|
||||
}
|
||||
@@ -100,9 +100,5 @@ namespace SharpCompress.Common.Tar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal override void Close()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,12 +6,12 @@ namespace SharpCompress.Common.Tar
|
||||
{
|
||||
internal class TarFilePart : FilePart
|
||||
{
|
||||
private Stream seekableStream;
|
||||
private readonly Stream seekableStream;
|
||||
|
||||
internal TarFilePart(TarHeader header, Stream seekableStream)
|
||||
{
|
||||
this.seekableStream = seekableStream;
|
||||
this.Header = header;
|
||||
Header = header;
|
||||
}
|
||||
|
||||
internal TarHeader Header { get; private set; }
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace SharpCompress.Common.Tar
|
||||
internal class TarReadOnlySubStream : Stream
|
||||
{
|
||||
private bool isDisposed;
|
||||
private int amountRead;
|
||||
private long amountRead;
|
||||
|
||||
public TarReadOnlySubStream(Stream stream, long bytesToRead)
|
||||
{
|
||||
@@ -22,7 +22,7 @@ namespace SharpCompress.Common.Tar
|
||||
isDisposed = true;
|
||||
if (disposing)
|
||||
{
|
||||
int skipBytes = this.amountRead % 512;
|
||||
long skipBytes = amountRead % 512;
|
||||
if (skipBytes == 0)
|
||||
{
|
||||
return;
|
||||
@@ -33,7 +33,7 @@ namespace SharpCompress.Common.Tar
|
||||
return;
|
||||
}
|
||||
var buffer = new byte[skipBytes];
|
||||
this.Stream.ReadFully(buffer);
|
||||
Stream.ReadFully(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,48 +58,48 @@ namespace SharpCompress.Common.Tar
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
throw new System.NotSupportedException();
|
||||
}
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get { throw new System.NotImplementedException(); }
|
||||
get { throw new System.NotSupportedException(); }
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get { throw new System.NotImplementedException(); }
|
||||
set { throw new System.NotImplementedException(); }
|
||||
get { throw new System.NotSupportedException(); }
|
||||
set { throw new System.NotSupportedException(); }
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (this.BytesLeftToRead < count)
|
||||
if (BytesLeftToRead < count)
|
||||
{
|
||||
count = (int)this.BytesLeftToRead;
|
||||
count = (int)BytesLeftToRead;
|
||||
}
|
||||
int read = this.Stream.Read(buffer, offset, count);
|
||||
int read = Stream.Read(buffer, offset, count);
|
||||
if (read > 0)
|
||||
{
|
||||
this.BytesLeftToRead -= read;
|
||||
this.amountRead += read;
|
||||
BytesLeftToRead -= read;
|
||||
amountRead += read;
|
||||
}
|
||||
return read;
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
throw new System.NotSupportedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
throw new System.NotSupportedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
throw new System.NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,18 +2,11 @@
|
||||
|
||||
namespace SharpCompress.Common.Tar
|
||||
{
|
||||
public class TarVolume : GenericVolume
|
||||
public class TarVolume : Volume
|
||||
{
|
||||
public TarVolume(Stream stream, Options options)
|
||||
: base(stream, options)
|
||||
{
|
||||
}
|
||||
|
||||
#if !PORTABLE && !NETFX_CORE
|
||||
public TarVolume(FileInfo fileInfo, Options options)
|
||||
: base(fileInfo, options)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -24,16 +24,18 @@ namespace SharpCompress.Common
|
||||
/// RarArchive is the first volume of a multi-part archive.
|
||||
/// Only Rar 3.0 format and higher
|
||||
/// </summary>
|
||||
public abstract bool IsFirstVolume { get; }
|
||||
public virtual bool IsFirstVolume
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RarArchive is part of a multi-part archive.
|
||||
/// </summary>
|
||||
public abstract bool IsMultiVolume { get; }
|
||||
|
||||
#if !PORTABLE && !NETFX_CORE
|
||||
public abstract FileInfo VolumeFile { get; }
|
||||
#endif
|
||||
public virtual bool IsMultiVolume
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
private bool disposed;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace SharpCompress.Common.Zip.Headers
|
||||
{
|
||||
@@ -34,6 +35,12 @@ namespace SharpCompress.Common.Zip.Headers
|
||||
byte[] comment = reader.ReadBytes(commentLength);
|
||||
Comment = DecodeString(comment);
|
||||
LoadExtra(extra);
|
||||
|
||||
var unicodePathExtra = Extra.FirstOrDefault(u => u.Type == ExtraDataType.UnicodePathExtraField);
|
||||
if (unicodePathExtra != null)
|
||||
{
|
||||
Name = ((ExtraUnicodePathExtraField)unicodePathExtra).UnicodeName;
|
||||
}
|
||||
}
|
||||
|
||||
internal override void Write(BinaryWriter writer)
|
||||
|
||||
@@ -1,19 +1,8 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace SharpCompress.Common.Zip.Headers
|
||||
{
|
||||
internal enum ExtraDataType : ushort
|
||||
{
|
||||
WinZipAes = 0x9901,
|
||||
}
|
||||
|
||||
internal class ExtraData
|
||||
{
|
||||
internal ExtraDataType Type { get; set; }
|
||||
internal ushort Length { get; set; }
|
||||
internal byte[] DataBytes { get; set; }
|
||||
}
|
||||
|
||||
internal class LocalEntryHeader : ZipFileEntry
|
||||
{
|
||||
public LocalEntryHeader()
|
||||
@@ -37,6 +26,12 @@ namespace SharpCompress.Common.Zip.Headers
|
||||
byte[] extra = reader.ReadBytes(extraLength);
|
||||
Name = DecodeString(name);
|
||||
LoadExtra(extra);
|
||||
|
||||
var unicodePathExtra = Extra.FirstOrDefault(u => u.Type == ExtraDataType.UnicodePathExtraField);
|
||||
if (unicodePathExtra!=null)
|
||||
{
|
||||
Name = ((ExtraUnicodePathExtraField) unicodePathExtra).UnicodeName;
|
||||
}
|
||||
}
|
||||
|
||||
internal override void Write(BinaryWriter writer)
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpCompress.Common.Zip.Headers
|
||||
{
|
||||
internal enum ExtraDataType : ushort
|
||||
{
|
||||
WinZipAes = 0x9901,
|
||||
|
||||
NotImplementedExtraData = 0xFFFF,
|
||||
// Third Party Mappings
|
||||
// -Info-ZIP Unicode Path Extra Field
|
||||
UnicodePathExtraField = 0x7075
|
||||
}
|
||||
|
||||
internal class ExtraData
|
||||
{
|
||||
internal ExtraDataType Type { get; set; }
|
||||
internal ushort Length { get; set; }
|
||||
internal byte[] DataBytes { get; set; }
|
||||
}
|
||||
|
||||
internal class ExtraUnicodePathExtraField : ExtraData
|
||||
{
|
||||
internal byte Version
|
||||
{
|
||||
get { return this.DataBytes[0]; }
|
||||
}
|
||||
|
||||
internal byte[] NameCRC32
|
||||
{
|
||||
get
|
||||
{
|
||||
var crc = new byte[4];
|
||||
Buffer.BlockCopy(this.DataBytes, 1, crc, 0, 4);
|
||||
return crc;
|
||||
}
|
||||
}
|
||||
|
||||
internal string UnicodeName
|
||||
{
|
||||
get
|
||||
{
|
||||
// PathNamelength = dataLength - Version(1 byte) - NameCRC32(4 bytes)
|
||||
var length = this.Length - 5;
|
||||
var nameStr = Encoding.UTF8.GetString(this.DataBytes, 5, length);
|
||||
return nameStr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static class LocalEntryHeaderExtraFactory
|
||||
{
|
||||
internal static ExtraData Create(ExtraDataType type,ushort length, byte[] extraData)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ExtraDataType.UnicodePathExtraField:
|
||||
return new ExtraUnicodePathExtraField()
|
||||
{
|
||||
Type = type,
|
||||
Length = length,
|
||||
DataBytes = extraData
|
||||
};
|
||||
default:
|
||||
return new ExtraData
|
||||
{
|
||||
Type = type,
|
||||
Length = length,
|
||||
DataBytes = extraData
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SharpCompress.Converter;
|
||||
|
||||
namespace SharpCompress.Common.Zip.Headers
|
||||
{
|
||||
@@ -13,7 +14,6 @@ namespace SharpCompress.Common.Zip.Headers
|
||||
Extra = new List<ExtraData>();
|
||||
}
|
||||
|
||||
|
||||
internal bool IsDirectory
|
||||
{
|
||||
get { return Name.EndsWith("/"); }
|
||||
@@ -25,6 +25,7 @@ namespace SharpCompress.Common.Zip.Headers
|
||||
{
|
||||
return Encoding.UTF8.GetString(str, 0, str.Length);
|
||||
}
|
||||
|
||||
return ArchiveEncoding.Default.GetString(str, 0, str.Length);
|
||||
}
|
||||
|
||||
@@ -66,22 +67,19 @@ namespace SharpCompress.Common.Zip.Headers
|
||||
|
||||
protected void LoadExtra(byte[] extra)
|
||||
{
|
||||
for (int i = 0; i < extra.Length;)
|
||||
for (int i = 0; i < extra.Length-4;)
|
||||
{
|
||||
ExtraDataType type = (ExtraDataType) BitConverter.ToUInt16(extra, i);
|
||||
ExtraDataType type = (ExtraDataType)DataConverter.LittleEndian.GetUInt16(extra, i);
|
||||
if (!Enum.IsDefined(typeof (ExtraDataType), type))
|
||||
{
|
||||
return;
|
||||
type = ExtraDataType.NotImplementedExtraData;
|
||||
}
|
||||
ushort length = BitConverter.ToUInt16(extra, i + 2);
|
||||
|
||||
ushort length = DataConverter.LittleEndian.GetUInt16(extra, i + 2);
|
||||
byte[] data = new byte[length];
|
||||
Buffer.BlockCopy(extra, i + 4, data, 0, length);
|
||||
Extra.Add(new ExtraData
|
||||
{
|
||||
Type = type,
|
||||
Length = length,
|
||||
DataBytes = data
|
||||
});
|
||||
Extra.Add(LocalEntryHeaderExtraFactory.Create(type,length,data));
|
||||
|
||||
i += length + 4;
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ namespace SharpCompress.Common.Zip
|
||||
{
|
||||
internal class SeekableZipHeaderFactory : ZipHeaderFactory
|
||||
{
|
||||
private const int MAX_ITERATIONS_FOR_DIRECTORY_HEADER = 1000;
|
||||
private const int MAX_ITERATIONS_FOR_DIRECTORY_HEADER = 4096;
|
||||
|
||||
internal SeekableZipHeaderFactory(string password)
|
||||
: base(StreamingMode.Seekable, password)
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.IO;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Engines;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
using SharpCompress.Converter;
|
||||
|
||||
namespace SharpCompress.Common.Zip
|
||||
{
|
||||
@@ -113,7 +114,7 @@ namespace SharpCompress.Common.Zip
|
||||
: bytesRemaining;
|
||||
|
||||
// update the counter
|
||||
Array.Copy(BitConverter.GetBytes(nonce++), 0, counter, 0, 4);
|
||||
DataConverter.LittleEndian.PutBytes(counter, 0, nonce++);
|
||||
|
||||
// Determine if this is the final block
|
||||
if ((bytesToRead == bytesRemaining) && (totalBytesLeftToRead == 0))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using SharpCompress.Converter;
|
||||
|
||||
namespace SharpCompress.Common.Zip
|
||||
{
|
||||
@@ -55,13 +56,13 @@ namespace SharpCompress.Common.Zip
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
get { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
set { throw new NotImplementedException(); }
|
||||
get { throw new NotSupportedException(); }
|
||||
set { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
@@ -82,7 +83,7 @@ namespace SharpCompress.Common.Zip
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
@@ -117,7 +118,7 @@ namespace SharpCompress.Common.Zip
|
||||
: bytesRemaining;
|
||||
|
||||
// update the counter
|
||||
Array.Copy(BitConverter.GetBytes(nonce++), 0, counter, 0, 4);
|
||||
DataConverter.LittleEndian.PutBytes(counter, 0, nonce++);
|
||||
|
||||
// Determine if this is the final block
|
||||
if ((bytesToRead == bytesRemaining) && (totalBytesLeftToRead == 0))
|
||||
@@ -164,17 +165,17 @@ namespace SharpCompress.Common.Zip
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using SharpCompress.Converter;
|
||||
using SharpCompress.Crypto;
|
||||
|
||||
namespace SharpCompress.Common.Zip
|
||||
@@ -56,10 +57,10 @@ namespace SharpCompress.Common.Zip
|
||||
generatedVerifyValue = paramz.GetBytes(2);
|
||||
|
||||
|
||||
short verify = BitConverter.ToInt16(passwordVerifyValue, 0);
|
||||
short verify = DataConverter.LittleEndian.GetInt16(passwordVerifyValue, 0);
|
||||
if (password != null)
|
||||
{
|
||||
short generated = BitConverter.ToInt16(generatedVerifyValue, 0);
|
||||
short generated = DataConverter.LittleEndian.GetInt16(generatedVerifyValue, 0);
|
||||
if (verify != generated)
|
||||
throw new InvalidFormatException("bad password");
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using SharpCompress.Converter;
|
||||
|
||||
namespace SharpCompress.Common.Zip
|
||||
{
|
||||
@@ -54,10 +55,10 @@ namespace SharpCompress.Common.Zip
|
||||
IvBytes = rfc2898.GetBytes(KeySizeInBytes);
|
||||
generatedVerifyValue = rfc2898.GetBytes(2);
|
||||
|
||||
short verify = BitConverter.ToInt16(passwordVerifyValue, 0);
|
||||
short verify = DataConverter.LittleEndian.GetInt16(passwordVerifyValue, 0);
|
||||
if (password != null)
|
||||
{
|
||||
short generated = BitConverter.ToInt16(generatedVerifyValue, 0);
|
||||
short generated = DataConverter.LittleEndian.GetInt16(generatedVerifyValue, 0);
|
||||
if (verify != generated)
|
||||
throw new InvalidFormatException("bad password");
|
||||
}
|
||||
|
||||
@@ -53,12 +53,12 @@ namespace SharpCompress.Common.Zip
|
||||
}
|
||||
}
|
||||
|
||||
public override uint Crc
|
||||
public override long Crc
|
||||
{
|
||||
get { return filePart.Header.Crc; }
|
||||
}
|
||||
|
||||
public override string FilePath
|
||||
public override string Key
|
||||
{
|
||||
get { return filePart.Header.Name; }
|
||||
}
|
||||
@@ -112,9 +112,5 @@ namespace SharpCompress.Common.Zip
|
||||
{
|
||||
get { return filePart.AsEnumerable<FilePart>(); }
|
||||
}
|
||||
|
||||
internal override void Close()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ using SharpCompress.Compressor.BZip2;
|
||||
using SharpCompress.Compressor.Deflate;
|
||||
using SharpCompress.Compressor.LZMA;
|
||||
using SharpCompress.Compressor.PPMd;
|
||||
using SharpCompress.Converter;
|
||||
using SharpCompress.IO;
|
||||
|
||||
namespace SharpCompress.Common.Zip
|
||||
@@ -108,19 +109,19 @@ namespace SharpCompress.Common.Zip
|
||||
{
|
||||
throw new InvalidFormatException("Winzip data length is not 7.");
|
||||
}
|
||||
ushort method = BitConverter.ToUInt16(data.DataBytes, 0);
|
||||
ushort method = DataConverter.LittleEndian.GetUInt16(data.DataBytes, 0);
|
||||
|
||||
if (method != 0x01 && method != 0x02)
|
||||
{
|
||||
throw new InvalidFormatException("Unexpected vendor version number for WinZip AES metadata");
|
||||
}
|
||||
|
||||
ushort vendorId = BitConverter.ToUInt16(data.DataBytes, 2);
|
||||
ushort vendorId = DataConverter.LittleEndian.GetUInt16(data.DataBytes, 2);
|
||||
if (vendorId != 0x4541)
|
||||
{
|
||||
throw new InvalidFormatException("Unexpected vendor ID for WinZip AES metadata");
|
||||
}
|
||||
Header.CompressionMethod = (ZipCompressionMethod)BitConverter.ToUInt16(data.DataBytes, 5);
|
||||
Header.CompressionMethod = (ZipCompressionMethod)DataConverter.LittleEndian.GetUInt16(data.DataBytes, 5);
|
||||
return CreateDecompressionStream(stream);
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -2,20 +2,13 @@
|
||||
|
||||
namespace SharpCompress.Common.Zip
|
||||
{
|
||||
public class ZipVolume : GenericVolume
|
||||
public class ZipVolume : Volume
|
||||
{
|
||||
public ZipVolume(Stream stream, Options options)
|
||||
: base(stream, options)
|
||||
{
|
||||
}
|
||||
|
||||
#if !PORTABLE && !NETFX_CORE
|
||||
public ZipVolume(FileInfo fileInfo, Options options)
|
||||
: base(fileInfo, options)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
public string Comment { get; internal set; }
|
||||
}
|
||||
}
|
||||
@@ -670,6 +670,7 @@ namespace SharpCompress.Compressor.Deflate
|
||||
send_bits((tree[c2] & 0xffff), (tree[c2 + 1] & 0xffff));
|
||||
}
|
||||
|
||||
#pragma warning disable 675 // workaround for Visual Studio 2015 compiler bug: https://github.com/dotnet/roslyn/issues/4027
|
||||
internal void send_bits(int value, int length)
|
||||
{
|
||||
int len = length;
|
||||
@@ -680,7 +681,7 @@ namespace SharpCompress.Compressor.Deflate
|
||||
//int val = value;
|
||||
// bi_buf |= (val << bi_valid);
|
||||
|
||||
bi_buf |= (short) ((value << bi_valid) & 0xffff);
|
||||
bi_buf |= (short)((value << bi_valid) & 0xffff);
|
||||
//put_short(bi_buf);
|
||||
pending[pendingCount++] = (byte) bi_buf;
|
||||
pending[pendingCount++] = (byte) (bi_buf >> 8);
|
||||
@@ -692,11 +693,12 @@ namespace SharpCompress.Compressor.Deflate
|
||||
else
|
||||
{
|
||||
// bi_buf |= (value) << bi_valid;
|
||||
bi_buf |= (short) ((value << bi_valid) & 0xffff);
|
||||
bi_buf |= (short)((value << bi_valid) & 0xffff);
|
||||
bi_valid += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore 675
|
||||
|
||||
// Send one empty static block to give enough lookahead for inflate.
|
||||
// This takes 10 bits, of which 7 may remain in the bit buffer.
|
||||
|
||||
@@ -174,7 +174,7 @@ namespace SharpCompress.Compressor.Deflate
|
||||
/// </summary>
|
||||
public override long Length
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
get { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -198,7 +198,7 @@ namespace SharpCompress.Compressor.Deflate
|
||||
return _baseStream._z.TotalBytesIn;
|
||||
return 0;
|
||||
}
|
||||
set { throw new NotImplementedException(); }
|
||||
set { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -275,7 +275,7 @@ namespace SharpCompress.Compressor.Deflate
|
||||
/// <returns>irrelevant!</returns>
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -284,7 +284,7 @@ namespace SharpCompress.Compressor.Deflate
|
||||
/// <param name="value">this is irrelevant, since it will always throw!</param>
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Converter;
|
||||
|
||||
namespace SharpCompress.Compressor.Deflate
|
||||
{
|
||||
@@ -163,7 +164,7 @@ namespace SharpCompress.Compressor.Deflate
|
||||
/// </summary>
|
||||
public override long Length
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
get { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -188,7 +189,7 @@ namespace SharpCompress.Compressor.Deflate
|
||||
return 0;
|
||||
}
|
||||
|
||||
set { throw new NotImplementedException(); }
|
||||
set { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -286,7 +287,7 @@ namespace SharpCompress.Compressor.Deflate
|
||||
/// <returns>irrelevant!</returns>
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -295,7 +296,7 @@ namespace SharpCompress.Compressor.Deflate
|
||||
/// <param name="value">irrelevant; this method will always throw!</param>
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -417,7 +418,7 @@ namespace SharpCompress.Compressor.Deflate
|
||||
LastModified = DateTime.Now;
|
||||
TimeSpan delta = LastModified.Value - UnixEpoch;
|
||||
var timet = (Int32) delta.TotalSeconds;
|
||||
Array.Copy(BitConverter.GetBytes(timet), 0, header, i, 4);
|
||||
DataConverter.LittleEndian.PutBytes(header, i, timet);
|
||||
i += 4;
|
||||
|
||||
// xflg
|
||||
|
||||
@@ -895,6 +895,11 @@ namespace SharpCompress.Compressor.Deflate
|
||||
r = ZlibConstants.Z_OK;
|
||||
else
|
||||
{
|
||||
// Handling missing trailing bit(s)
|
||||
var tmp_tindex = (tree_index + (b & InternalInflateConstants.InflateMask[k]))*3;
|
||||
if (k >= tree[tmp_tindex + 1])
|
||||
break;
|
||||
|
||||
blocks.bitb = b;
|
||||
blocks.bitk = k;
|
||||
z.AvailableBytesIn = n;
|
||||
@@ -998,6 +1003,11 @@ namespace SharpCompress.Compressor.Deflate
|
||||
r = ZlibConstants.Z_OK;
|
||||
else
|
||||
{
|
||||
// Handling missing trailing bit(s)
|
||||
var tmp_tindex = (tree_index + (b & InternalInflateConstants.InflateMask[k]))*3;
|
||||
if (k >= tree[tmp_tindex + 1])
|
||||
break;
|
||||
|
||||
blocks.bitb = b;
|
||||
blocks.bitk = k;
|
||||
z.AvailableBytesIn = n;
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
using System;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Tar.Headers;
|
||||
using SharpCompress.Converter;
|
||||
|
||||
namespace SharpCompress.Compressor.Deflate
|
||||
{
|
||||
@@ -221,9 +222,9 @@ namespace SharpCompress.Compressor.Deflate
|
||||
{
|
||||
// Emit the GZIP trailer: CRC32 and size mod 2^32
|
||||
int c1 = crc.Crc32Result;
|
||||
_stream.Write(BitConverter.GetBytes(c1), 0, 4);
|
||||
_stream.Write(DataConverter.LittleEndian.GetBytes(c1), 0, 4);
|
||||
int c2 = (Int32)(crc.TotalBytesRead & 0x00000000FFFFFFFF);
|
||||
_stream.Write(BitConverter.GetBytes(c2), 0, 4);
|
||||
_stream.Write(DataConverter.LittleEndian.GetBytes(c2), 0, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -267,9 +268,9 @@ namespace SharpCompress.Compressor.Deflate
|
||||
}
|
||||
|
||||
|
||||
Int32 crc32_expected = BitConverter.ToInt32(trailer, 0);
|
||||
Int32 crc32_expected = DataConverter.LittleEndian.GetInt32(trailer, 0);
|
||||
Int32 crc32_actual = crc.Crc32Result;
|
||||
Int32 isize_expected = BitConverter.ToInt32(trailer, 4);
|
||||
Int32 isize_expected = DataConverter.LittleEndian.GetInt32(trailer, 4);
|
||||
Int32 isize_actual = (Int32)(_z.TotalBytesOut & 0x00000000FFFFFFFF);
|
||||
|
||||
if (crc32_actual != crc32_expected)
|
||||
@@ -339,7 +340,7 @@ namespace SharpCompress.Compressor.Deflate
|
||||
|
||||
public override System.Int64 Seek(System.Int64 offset, System.IO.SeekOrigin origin)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
//_outStream.Seek(offset, origin);
|
||||
}
|
||||
|
||||
@@ -405,7 +406,7 @@ namespace SharpCompress.Compressor.Deflate
|
||||
if (header[0] != 0x1F || header[1] != 0x8B || header[2] != 8)
|
||||
throw new ZlibException("Bad GZIP header.");
|
||||
|
||||
Int32 timet = BitConverter.ToInt32(header, 4);
|
||||
Int32 timet = DataConverter.LittleEndian.GetInt32(header, 4);
|
||||
_GzipMtime = TarHeader.Epoch.AddSeconds(timet);
|
||||
totalBytesRead += n;
|
||||
if ((header[3] & 0x04) == 0x04)
|
||||
@@ -573,8 +574,8 @@ namespace SharpCompress.Compressor.Deflate
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
set { throw new NotImplementedException(); }
|
||||
get { throw new NotSupportedException(); }
|
||||
set { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
internal enum StreamMode
|
||||
|
||||
@@ -166,7 +166,7 @@ namespace SharpCompress.Compressor.Deflate
|
||||
/// </summary>
|
||||
public override long Length
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
get { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -191,7 +191,7 @@ namespace SharpCompress.Compressor.Deflate
|
||||
return 0;
|
||||
}
|
||||
|
||||
set { throw new NotImplementedException(); }
|
||||
set { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -264,7 +264,7 @@ namespace SharpCompress.Compressor.Deflate
|
||||
/// </summary>
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -272,7 +272,7 @@ namespace SharpCompress.Compressor.Deflate
|
||||
/// </summary>
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -91,7 +91,7 @@ namespace SharpCompress.Compressor.Filters
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override long Length
|
||||
@@ -102,7 +102,7 @@ namespace SharpCompress.Compressor.Filters
|
||||
public override long Position
|
||||
{
|
||||
get { return position; }
|
||||
set { throw new NotImplementedException(); }
|
||||
set { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
@@ -203,17 +203,17 @@ namespace SharpCompress.Compressor.Filters
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user